V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
piaochen0
V2EX  ›  Django

Django 远程连接对象缓存的方案

  •  
  •   piaochen0 · 2019-08-28 16:25:35 +08:00 · 4204 次点击
    这是一个创建于 1932 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近要做一个网页版 FTP 工具,用户在网页上,完成 FTP 工具的操作。
    我的方案是: 1.每个登录用户连接 FTP 服务器后,会把 ftp 连接对象放到一个对象池中(实际上就是一个公共的字典中,key 为用户的 id,FTP 对象为 value )
    2.用户每次操作,直接到公共字典中去找有没有已经生成的 ftp 对象,假如有,直接拿过来用。省的每次操作都要重新建立远程连接。
    3.当字典中的对象超过一定数量时,清理掉最早加入的。

    现在的问题是,在本地调试没有问题。但是放到 uwsgi 环境的时候,发现由于 uwsgi 会生成多实例,实际上也就生成了多个对象池。这个方案就有不行了。

    麻烦询问一下大家是怎么处理这个方案的,其实最终的目的,也就是单个用户,每步操作都要重新跟服务器建立连接。只在登录页面的时候,连一下。然后其他操作公用此 ftp 对象即可。

    麻烦各位赐教。

    13 条回复    2019-08-29 09:33:27 +08:00
    mayorbryant
        1
    mayorbryant  
       2019-08-28 16:29:49 +08:00
    用 redis 来替代你文中说的公共字典
    piaochen0
        2
    piaochen0  
    OP
       2019-08-28 16:35:44 +08:00
    @mayorbryant radis 可以缓存 ftp 这种连接类的对象吗?印象中这种只适合可序列化的对象吧。
    wuwukai007
        3
    wuwukai007  
       2019-08-28 16:39:30 +08:00   ❤️ 1
    redis 可以指定序列化方式,默认是 json,可以指定 pickle,但是 pickle 也有很多序列不了的对象,
    这个时候用 dill 第三方序列化 pip install dill
    可以序列化 函数,嵌套函数,匿名函数,main 函数等大多数 py 对象
    然后 dill 序列化后是字节 ,pickle 可以识别
    mayorbryant
        4
    mayorbryant  
       2019-08-28 16:42:19 +08:00   ❤️ 1
    @piaochen0 楼上说的也是我想表达的
    piaochen0
        5
    piaochen0  
    OP
       2019-08-28 17:10:15 +08:00
    提个想法,这种 FTP 连接对象,可以放到 session 中吗?会有什么问题没有?
    jesnridy
        6
    jesnridy  
       2019-08-28 17:30:00 +08:00
    @piaochen0 我第一个想法就是放到 session 中,链接 session 对象放在单例模型中搞,登出的时候断开 session
    sujin190
        7
    sujin190  
       2019-08-28 17:40:31 +08:00   ❤️ 2
    楼上 redis 或者 session 序列化的,你们认真的么?一个进程拥有的 socket 能通过 pickle 弄到另外一个进程去?见鬼了吧
    socket 底层就是文件句柄,数据能序列化,文件句柄复制到另外一个进程怎么用?
    所以你这个 uwsgi 部署的 Django 是很难做出来的,估计需要用 tornado 或者 asyncio 做一个代理连接层吧,也不复杂
    piaochen0
        8
    piaochen0  
    OP
       2019-08-28 17:56:07 +08:00
    @jesnridy session 的方案不行,我刚试了。无法序列化
    sujin190
        9
    sujin190  
       2019-08-28 18:09:59 +08:00   ❤️ 1
    或者另外一个方案是,nginx 做 upstream 负载均衡的时候,然后依据 session_id hash 方式选择 upstream,这样就可以确保单个登录用户始终由同一个进程来处理,这样你就可以用原来全局字典缓存的方式了

    https://blog.csdn.net/lvshaorong/article/details/78309514
    可以看看这个
    wuwukai007
        10
    wuwukai007  
       2019-08-28 18:22:54 +08:00
    sor,socket 好像不可以序列化尴尬了
    est
        11
    est  
       2019-08-28 18:55:29 +08:00   ❤️ 1
    最终的目的,不管怎么做,ftp 连接池的维护,都会落到一个进程来负责。所以最直接的方式是,uwsgi 里 workers 数量改成 1 即可。

    可能其他 web 请求处理量,一个 worker 不够,那也很简单,另外再跑一套 uwsgi,前面再套一个 nginx 反代或者 uwsgi router。
    wangyongbo
        12
    wangyongbo  
       2019-08-28 19:03:28 +08:00   ❤️ 2
    我们是这样做的,1 浏览器,2 web 服务,3 ftp 连接服务。 就是把你现在整体的后端服务分成 2 和 3 两个服务。

    1 和 2 之间用 http 协议,或者 websocket 协议,2 和 3 之间用消息队列通信,通信协议需要自己定义。

    比如 用户要连接一个 ftp 服务器。通过 http 协议,发到 2, 然后 2 处理之后,比如验证权限,连接数量等等,然后把请求放到消息队列。3 从消息队列读取到请求之后,创建一个 ftp 连接。


    可以根据实际需要扩展 2 和 3 的服务数量,互不干扰。
    你觉得怎么样?
    piaochen0
        13
    piaochen0  
    OP
       2019-08-29 09:33:27 +08:00
    @wangyongbo 消息队列是用的 ActiveMQ 这种中间件来实现的吗?我没怎么用过这种模式,根据我的理解,这应该是异步的操作吧。web 服务把消息发给了消息队列,队列里面一个一个处理,处理完了以后,通知 web 服务。这个时候还能通过 response 通知前端页面吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4958 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:41 · PVG 11:41 · LAX 19:41 · JFK 22:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.