妈妈再也不用担心我的程序 OOM 啦 - 一个基于 Redis 的分布式内存 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
爱意满满的作品展示区。
wangleineo

妈妈再也不用担心我的程序 OOM 啦 - 一个基于 Redis 的分布式内存

  •  
  •   wangleineo
    RealHacker Nov 11, 2015 4737 views
    This topic created in 3822 days ago, the information mentioned may be changed or developed.

    Dmem ( Distributed memory )是用 python 实现的一个分布式内存的解决方案,把 Python 的基础数据类型映射到 Redis 上,通过一个“透明”的 Redis Client 实现在多个节点上存取数据。

    Githubhttps://github.com/RealHacker/dmem

    应用场景:

    • 程序对于内存需求较大,单节点无法满足时,无需更改代码逻辑即可支持分布式内存。
    • 需要分布式存储多层数据结构,比如一个 list ,其中每个元素是一个 dict 。( Redis 命令只支持单层数据结构)
    • 代码洁癖患者,可以使用 Python 原生操作符(x[y], del x.y, x in y)和方法来处理分布式对象。

    废话不多说,看代码:

    from dmem import * # Configure your redis instances pool RedisClientPool.get_pool().load_config({ "redis1": {"host":"192.168.1.1", "port": 6379, "db":0}, "redis2": {"host":"192.168.1.2", "port": 6379, "db":0}, "redis3": {"host":"192.168.1.3", "port": 6379, "db":0}, }) # Create a list mylist = RedisList([1, "abc", 3.1415]) # Now the list is alive on Redis print mylist[1] # actually retrieved with LGET command # output: 'abc' print mylist[0:2] # map to LRANGE command # output: [1, 'abc'] del mylist[0] # map to LREM command print mylist[:] # output: ["abc", 3.1415] s = RedisStr("Redis string") # Now the string lives in Redis mylist.append(s) # APPEND command print len(mylist) # STRLEN command # output: 3 print mylist[-1].getvalue() # GET command # output: 'Redis string' mydict = RedisDict({"a":1234}) # HSET commands # Now the dict lives in Redis as a hashmap mydict["list"] = mylist # HGET command print mydict.keys() # HKEYS command # output: ['a', 'list'] for k,v in mydict.items(): # HGETALL command print k, v # output: a 1234 # output: list <redislist.RedisList object at 0x01CDEF30> print mydict["list"][0] # output: 'abc' obj = RedisObject() # For redis object, the attributes are stored in Redis obj.attr1 = "abc" obj.attr2 = mydict print obj.attr2['list'][0] # output: 'abc' 

    欢迎提建议、报 Bug 。

    24 replies    2015-11-14 20:38:06 +08:00
    ryd994
        1
    ryd994  
       Nov 11, 2015
    这样的性能会不会不如 swap ?
    另外用 mmap 是好东西
    wangleineo
        2
    wangleineo  
    OP
       Nov 11, 2015
    @ryd994 没有测试过, 不过网络性能一般会比磁盘 I/O 高一些,否则 memcached/redis 集群都没意义了。
    ryd994
        3
    ryd994  
       Nov 11, 2015
    @wangleineo 那可不一定。磁盘是带缓存的。而且热数据都在内存里。
    binux
        4
    binux  
       Nov 11, 2015
    延迟
    raingolee
        5
    raingolee  
       Nov 11, 2015
    程序对于内存需求较大,单节点无法满足时,无需更改代码逻辑即可支持分布式内存
    ---

    对比 sentinel 有什么区别呢?
    楼主其实我还是不太明白 Dmem 的用处?
    wangleineo
        6
    wangleineo  
    OP
       Nov 11, 2015
    @raingolee 比如存取一个列表元素, RedisList 和原生的 list 一样: list[1],而不是 redis.client.lindex(...)。如果数据是存在内存中的 list 中,要迁移到 redis ,不用改变代码逻辑,只要把 list 换成 RedisList 就好了。
    kendetrics
        7
    kendetrics  
       Nov 11, 2015
    我感觉会比 swap 更卡。。
    ryd994
        8
    ryd994  
       Nov 11, 2015
    其实可以用 tmpfs 开 nfs ,然后 swapfile 放到 nfs 上。估计性能还比你这样好。不过万一断网就会崩
    mzer0
        9
    mzer0  
       Nov 11, 2015
    没啥用, 我的服务器目前还没出现过内存不够用的情况.

    另外你这东西弄得太复杂了, 纯 C 语言实现的或许还会有人试试.
    msg7086
        10
    msg7086  
       Nov 11, 2015
    @ryd994 可是这个场景里内存都吃光了啊……哪有地方给你 caching ……
    ryd994
        11
    ryd994  
       Nov 11, 2015
    @msg7086 他这样把所有变量都直接改到 memcache 里去,内存根本没用到多少
    如果我对代码的理解没错的话,缓存是以整个 list 或者 dict 为单位的
    另外我很好奇这个 self.cache 在什么情况下会被回收

    说实话,我真心觉得 nfs 上挂 swap 虽然作死,但效果应该不差。
    wangleineo
        12
    wangleineo  
    OP
       Nov 11, 2015 via iPhone
    @mzer0 为什么用 c 语言就不复杂呢?

    @ryd994 self.cache 是用在 loaded 这个 context 中,退出 cache 就释放

    为啥都纠结性能问题呢?这和直接用 redis 的命令性能没什么不同
    ryd994
        13
    ryd994  
       Nov 11, 2015
    @wangleineo 纠结性能是因为你的定位是“分布式内存”,是要解决 OOM ,那性能就是要和物理内存比的。
    如果你的定位是“易用的 memcached 客户端”的话,我觉得写的很好。
    canesten
        14
    canesten  
       Nov 11, 2015
    就是 Python 版的 Redisson ?
    wangleineo
        15
    wangleineo  
    OP
       Nov 11, 2015
    @ryd994 的确有点标题党了,其实我的定位是:如果你能接受 Redis 的性能,就可以考虑用这个。


    @canesten 概念上类似,不过 Redisson 有很多功能,比如异步,我都没有实现。
    dreampuf
        16
    dreampuf  
       Nov 11, 2015
    楼上纠结 RAM+Network 不如 Disk 的诸位


    类库封装了 redis 支持多个节点,但是实现比较简单,没有考虑拆分的情况,集群容量还是受最小单节点限制
    https://github.com/RealHacker/dmem/blob/master/dbase.py#L19
    wangleineo
        17
    wangleineo  
    OP
       Nov 11, 2015
    此图甚好 另外有一个 post http://norvig.com/21-days.html#answers
    mzer0
        18
    mzer0  
       Nov 13, 2015 via iPhone
    @wangleineo C 语言实现一个分布式的内存,应该只需要几百行代码;而我认为,先不谈分布式内存的存在意义, redis+python 是不能接受的,硬要说的话,理由是“没有理由”就是我不想这样做,我宁愿自己编一个。或许某个俄国人实现过,要知道,俄国人最喜欢这些东西了,但我敢肯定没人用。
    R4rvZ6agNVWr56V0
        19
    R4rvZ6agNVWr56V0  
       Nov 13, 2015
    感觉没啥适用场景。实际上我用 zookeeper+zmq 实现单机内存统计和消息通信,内存不够或者机器下线,直接把任务交给其他相对大点的内存机器去跑了
    wangleineo
        20
    wangleineo  
    OP
       Nov 13, 2015
    @mzer0 好吧
    mzer0
        21
    mzer0  
       Nov 13, 2015 via iPhone
    @wangleineo 有一种情形我会使用分布式内存:如果两台主机的硬盘数据是自动同步的,主机 A 可以先命令主机 B 加载文件到内存,再通过分布式内存同步到 A 的内存,达到从内存加载文件的目的,减轻硬盘 IO 负担。
    Actrace
        22
    Actrace  
       Nov 14, 2015
    内存的存在意义就在于速度。
    网络存取,虽然在同一个局域网里,实现了扩大容量的愿景,但是性能肯定不如真正的内存。还不如多买几块 SSD 再做个 RAID 来的实在。
    楼主你还是认清事实吧,自行车再怎么快也比不上飞机的(是的,连汽车的速度都无法超越),还是要用正确的工具做正确的事情。

    不过这套设计可以用在分布式的持久化存储文件系统上,还是有点意义的。
    wangleineo
        23
    wangleineo  
    OP
       Nov 14, 2015
    @Actrace 技术是不断发展的,网络存取的速度已经越来越接近内存了,(虽然内存的速度也在提升)。但是硬盘还差好几个数量级,看看上面的图。
    lilin
        24
    lilin  
       Nov 14, 2015
    @Actrace 在 vpn 讨论区看到你有个可靠的服务商,可以推荐给我吗?
    我的邮箱:[email protected]
    谢谢
    About     Help     Advertise     Blog     API     FAQ     Solana     3222 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 72ms UTC 11:56 PVG 19:56 LAX 04:56 JFK 07:56
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86