V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
wangleineo
V2EX  ›  分享创造

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

  •  
  •   wangleineo ·
    RealHacker · 2015-11-11 00:01:51 +08:00 · 4009 次点击
    这是一个创建于 3096 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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


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


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

    不过这套设计可以用在分布式的持久化存储文件系统上,还是有点意义的。
    wangleineo
        23
    wangleineo  
    OP
       2015-11-14 11:19:05 +08:00
    @Actrace 技术是不断发展的,网络存取的速度已经越来越接近内存了,(虽然内存的速度也在提升)。但是硬盘还差好几个数量级,看看上面的图。
    lilin
        24
    lilin  
       2015-11-14 20:38:06 +08:00
    @Actrace 在 vpn 讨论区看到你有个可靠的服务商,可以推荐给我吗?
    我的邮箱:[email protected]
    谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   846 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 19:25 · PVG 03:25 · LAX 12:25 · JFK 15:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.