美文网首页
flask分布式部署session的保存方案

flask分布式部署session的保存方案

作者: 忘了呼吸的那只猫 | 来源:发表于2021-08-19 13:19 被阅读0次
    • flask 默认的 session 是怎么实现的

    flask 作为 web 应用框架若多机部署,第一个问题是需要一个请求接入网关,通常我们使用 nginx 统一进行流量的分发。
    但随之而来会有一个新的问题,即 flasksession 多机之间会共享吗?带着这个问题,我们看看 flask 关于 session 的源码:

    class (CallbackDict, SessionMixin):
      ...
    class SecureCookieSessionInterface(SessionInterface):
        def open_session(self, app, request):
            ...
        def save_session(self, app, session, response):
            ...
    

    以上是 flask.sessions.py 实现的主要框架:

    SecureCookieSessionflasksession 类,可以简单的理解成一个 dict 对象。
    SecureCookieSessionInterfaceflasksession 接口类,open_session 方法用于创建 sessionsave_session 方法用于将 session 加密并存放在 responsecookie 中。所以 flask 是默认将用户的 session 存储在客户端的 cookie 中,这样请求 - 应答的数据中就有了用户操作的上下文了,至于这么做的优劣将在下文分析。

    • 常见的分布式部署 session 解决方案

    1.服务器间 session 复制

    session复制是早期的企业级的使用比较多的一种服务器集群 session 管理机制。应用服务器开启 web 容器的 session 复制功能,在集群中的几台 服务器之间同步 session 对象,使得每台服务器上都保存所有的 session 信息,这样任何一台宕机都不会导致 session 的数据丢失,服务器使用 session 时,直接从本地获取。
    java 的一些应用服务器,如tomcat等自带次功能。在python-web不常见 **缺点:**是session` 同步会暂用内网网络带宽,且服务器水平扩展存在明显上线。

    2.session 与服务器绑定

    通过请求网关,如 nginx,将负载均衡的策略改成 ip-hash 的模式,即用户的每次请求都会分发到同一台服务器,那么 sesison 则能够正常的被解析。
    优点:无需修改业务代码
    缺点:缺乏高可用性,当其中一台服务器宕机,该机器上用户需要重新登录到其他服务器

    3.客户端 session 存储

    flask 默认的 session 存储方案,可见什么都不需要改动,flask 已经支持水平扩展,细心的童鞋想想当 flask 通过 gunicorn 启动时多进程为啥能够共享 session,即不难想到多个服务间共享应该也问题不大。这里注意的是多服务器间的 secret_key 必须相同。
    优点:无需改造,flask 默认支持
    缺点:
    session 数据存储在客户端,即使加密也还是一件存在泄露风险的事情session 数据占用外网带宽
    ②受 cookie 的大小限制,session 能记录的数据有限

    4.服务端 session统一存储

    session 进行统一的存储,所有服务器共享该存储服务上的数据
    优点:服务水平扩展性良好,服务端存储,安全
    缺点:每次请求至少需要一次内部网络请求,占用网络带宽
    需要侵入业务代码

    • flask-session 服务端 session 存储

    通过比较不难发现,服务端 session 统一存储是最合适的解决方案。
    那么我们来谈谈怎么实现,幸运的是已经有前任实现了 flask 对应的扩展包flask-session,我们一起看看它的实现:
    代码大概 500+ 行,但我们实际用到的可能就几十行。

    首先我们需要选择 session 寄存的服务,flask-session 支持redis,memcached,filesystem,mongodb,sqlalchemy作为存储介质
    redis 举例,再看代码:

    class RedisSessionInterface(SessionInterface):
        serializer = pickle
        session_class = RedisSession
    
        def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
            if redis is None:
                from redis import Redis
                redis = Redis()
            self.redis = redis
            self.key_prefix = key_prefix
            self.use_signer = use_signer
            self.permanent = permanent
     def open_session(self, app, request):
           ...
        def save_session(self, app, session, response):
         ...
    

    重写open_sessionsave_session,将 session(dict)存储在 redis 并将 session_id(key)返回给客户端

    • flask http 请求 - 应答完整的数据流

    客户端 http 请求
    -> 服务端负载均衡至随机服务器
    -> 应用上下文入栈 (app_ctx)
    -> 请求上下文入栈 (request_ctx),同时生成 session
    -> 通过 request_ctx 中的路由信息找到视图函数 (view_func)
    -> view_func 进行业务处理
    -> 应用上下文出栈 (app_ctx)
    -> 请求上下文出栈 (request_ctx)
    -> 保存 sessionsessino_idcookie
    -> 返回应答
    -> 数据写入对应的文档描述符并刷新
    其实 flask 的源码阅读起来并不吃力,看下来会发现 flask 框架代码的思路结构非常的清晰,并惊叹于这个框架的可扩展性,flask 的源码非常值得学习和借鉴。
    参考文章:https://www.dazhuanlan.com/scientific/topics/950698

    相关文章

      网友评论

          本文标题:flask分布式部署session的保存方案

          本文链接:https://www.haomeiwen.com/subject/adwobltx.html