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

请支招: redis || mysql 评论,赞,星标,这些互动数据

  •  1
     
  •   whatisnew · 2015-05-06 08:38:34 +08:00 · 8564 次点击
    这是一个创建于 3275 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近遇上评论数据的瓶颈了,放 mysql 吧受不了这么大的请求量,放 redis 吧,内存受不了。

    mysql 请求太多,继续用的话只能再堆服务器了

    redis 吧,数据太多了,比如:评论数据item_comment:item_id 去存取数据的话,那么现在的 item 已经到6位数了。。。那么也就是说 redis 里有 item_comment:654321(n) 仅仅评论数据就有 6 位数的 key 了,那么加上所有的互动就有 5*654,321 位数的 key,还是继续增加中。。。内存就。。。。

    有什么好办法。。。

    61 条回复    2015-05-07 00:14:07 +08:00
    zhangwei
        1
    zhangwei  
       2015-05-06 08:45:32 +08:00
    又想马儿跑得快,又想马儿不吃草
    whatisnew
        2
    whatisnew  
    OP
       2015-05-06 08:46:13 +08:00
    以前老骂cnbeta只在24小时内显示评论数据,现在终于充分理解了。。。
    whatisnew
        3
    whatisnew  
    OP
       2015-05-06 08:47:35 +08:00
    @zhangwei 问题是老这和堆服务器,除了堆服务器,算法上有没有可能做一些优化呢。

    我们现在考虑用 ssd 纯文本存储评论数据。。。
    freshlhy
        4
    freshlhy  
       2015-05-06 08:48:37 +08:00
    围观
    zhangwei
        5
    zhangwei  
       2015-05-06 08:48:53 +08:00
    @whatisnew 内存价格其实还可以
    lzxgh621
        6
    lzxgh621  
       2015-05-06 08:54:36 +08:00
    @whatisnew 然后,我就在没去过cnbeta,没评论没意义。
    whatisnew
        7
    whatisnew  
    OP
       2015-05-06 08:55:23 +08:00
    @lzxgh621 哈哈哈,我现在是只看个标题
    rqrq
        8
    rqrq  
       2015-05-06 08:56:23 +08:00
    业务需求是什么?以至于十万级的评论数据让mysql承受不了了。
    gowithwind
        9
    gowithwind  
       2015-05-06 08:57:37 +08:00
    舍不得内存,就用缓存呗.针对热数据缓存.
    whatisnew
        10
    whatisnew  
    OP
       2015-05-06 08:58:41 +08:00
    @rqrq 。。。数据容量不是问题,问题在连接数和IO
    whatisnew
        11
    whatisnew  
    OP
       2015-05-06 08:59:10 +08:00
    @gowithwind 热数据缓存不还得用到 redis 么。。。
    Livid
        12
    Livid  
    MOD
       2015-05-06 09:00:21 +08:00   ❤️ 1
    数据库大到一定程度就必须要拆。

    拆到不同的表甚至不同的服务器上。
    nowcoder
        13
    nowcoder  
       2015-05-06 09:01:10 +08:00
    牛客网的评论放在mysql,赞放在redis
    simonlei
        14
    simonlei  
       2015-05-06 09:01:44 +08:00
    冷热数据分离。热数据在内存,冷数据在硬盘。
    wy315700
        15
    wy315700  
       2015-05-06 09:03:10 +08:00
    mysql试试看innodb呗

    不行就上hbase吧
    xiaozi
        16
    xiaozi  
       2015-05-06 09:05:08 +08:00   ❤️ 1
    用hash优化

    item_comment:6543
    21(n)
    22(n)

    设置过期时间,自动清理冷数据
    kier
        17
    kier  
       2015-05-06 09:07:31 +08:00
    说说看并发量是多大?
    whatisnew
        18
    whatisnew  
    OP
       2015-05-06 09:08:16 +08:00
    设置过期时间是个好主意!
    但是 hash 优化的话。。。不在一个点上哦,一个 item_comment 对应的是一个 json 字符串,不是按多少楼分的。。。是依 item 为单位的。
    lincanbin
        19
    lincanbin  
       2015-05-06 09:09:37 +08:00
    评论的缓存过期时间是多久?
    whatisnew
        20
    whatisnew  
    OP
       2015-05-06 09:10:06 +08:00
    然后, item_comment 里对应的那些用户 user_id 读取 avatar nickname 这些字段怎么办。。。存成死数据吗?
    whatisnew
        21
    whatisnew  
    OP
       2015-05-06 09:11:00 +08:00
    @lincanbin 现在是30天,打算改到10天
    xiaozi
        22
    xiaozi  
       2015-05-06 09:12:04 +08:00
    @whatisnew redis的配置文件中 hash-max-ziplist-entries,会对 hash 存储进行优化;你把 key 的 id 拆分成两个数字,一个 hash 里面大概存 1000 个好了,每个子 id 也是对应一个字符串;如果觉得子 id 也长了,可以对子 id 进行 base62 转换。
    whatisnew
        23
    whatisnew  
    OP
       2015-05-06 09:14:47 +08:00
    @xiaozi 把 key 的 id 拆分成两个数字.... 这一段没看懂,哪个 key 哪个 id?一个 hash 里边可以存超过 6 位数的 field 吗。。。
    cdffh
        24
    cdffh  
       2015-05-06 09:17:12 +08:00
    十万条数据不断多哦 是读写太频繁了吗
    huitailang
        25
    huitailang  
       2015-05-06 09:18:38 +08:00
    围观~
    whatisnew
        26
    whatisnew  
    OP
       2015-05-06 09:19:06 +08:00
    @cdffh 这只是评论数据。。。还有很多其他数据
    cdffh
        27
    cdffh  
       2015-05-06 09:21:25 +08:00
    额 现在大概的数据规模是多大啊。 并发多少啊。这些情况要说清楚啊。不然不好找优化点啊
    gowithwind
        28
    gowithwind  
       2015-05-06 09:24:31 +08:00
    我看楼主也是不愿花钱,这样的话考虑用ssdb吧.和redis基本类似,底层是leveldb,大量数据存在硬盘里,性能也可以.
    xiaozi
        29
    xiaozi  
       2015-05-06 09:26:51 +08:00
    @whatisnew

    比如你是这样的:

    item_comment:6543001
    item_comment:6543002
    item_comment:6544010

    然后存成这样的:

    hset item_comment:6543 001 '这是json str'
    hset item_comment:6543 002 '这是json str'

    hset item_comment:6544 002 '这是json str'

    不是存成一个大hash,是好多个hash
    nevernet
        30
    nevernet  
       2015-05-06 09:29:05 +08:00
    @gowithwind ssdb现在稳定了吗?
    czheo
        31
    czheo  
       2015-05-06 09:29:19 +08:00
    mysql主从设了么?读写分离啊。
    whatisnew
        32
    whatisnew  
    OP
       2015-05-06 09:35:48 +08:00
    @czheo 主从,读读读写分离,主从从从 这都是标配了。。。
    whatisnew
        33
    whatisnew  
    OP
       2015-05-06 09:36:39 +08:00
    @nevernet 我看了 ssdb 的文档,看了半天也没看出来他是存在内存还是ssd
    lincanbin
        34
    lincanbin  
       2015-05-06 09:40:53 +08:00 via Android
    @whatisnew 需要缓存的只是热数据,你设置1天都够多了。
    czheo
        35
    czheo  
       2015-05-06 09:47:54 +08:00
    mysql query cache开了么?
    whatisnew
        36
    whatisnew  
    OP
       2015-05-06 09:48:48 +08:00
    @lincanbin 那不是跟 cnbeta 一样了。。。很多人喜欢评论的
    whatisnew
        37
    whatisnew  
    OP
       2015-05-06 09:51:07 +08:00
    @czheo 这个。。。 cache 是在应用层做的,不是在 mysql
    youxiachai
        38
    youxiachai  
       2015-05-06 09:54:26 +08:00
    ssdb ? 接口跟redis 直接兼容..
    czheo
        39
    czheo  
       2015-05-06 09:55:29 +08:00
    redis里面放最近1000的comment, 翻页到1000以后开始从mysql读数据。
    whatisnew
        40
    whatisnew  
    OP
       2015-05-06 09:56:05 +08:00
    @youxiachai 我是说他是存内存的还是存ssd的。。。还是都可以。。。
    justfly
        41
    justfly  
       2015-05-06 09:56:17 +08:00
    给个思路 mysql里面放评论的详细信息 redis里面只存放 ID 查询的时候先查redis得到ID 再从mysql里面拿详细信息组合 mysql上面可以放一层memcache或者redis 固定内存大小 做缓存 存放热数据
    tonghuashuai
        42
    tonghuashuai  
       2015-05-06 10:19:19 +08:00
    如果是我我会这么做:
    评论内容放在 mysql,评论关联,赞,星标放到 redis
    tonghuashuai
        43
    tonghuashuai  
       2015-05-06 10:29:20 +08:00
    抱歉,上一条回错了,没有看全就回了。。。
    tonghuashuai
        44
    tonghuashuai  
       2015-05-06 10:40:24 +08:00
    我会这么做:
    * 评论内容存到 mysql 中,比如 comment_id, txt
    * 评论的关联存在 redis 中,用 zset(score为评论时间戳方便排序),sadd item_comment:item_id score comment_id
    也就是 redis 中只有 id,都是 int 占用应该不会太过分吧,查询时查 redis 获取某个文章的评论id及排序,然后根据查到的 id 去 mysql 中查评论内容 (建好索引什么的应该不会慢吧)。
    如果 id 增长很快的话可以用上面说的做一下 base64或MD5 就定长了
    这样的话,只有有评论的文章才会在 redis 中有记录。

    星标和攒就类似了,只有 id 关联,全在 redis 中,可以参考新浪微博的关注的实现。
    cfan8
        45
    cfan8  
       2015-05-06 10:52:42 +08:00
    评论数据直接和item meta info压在一起吧,既然上NoSQL也没必要考虑什么范式之类的东西了
    guoer
        46
    guoer  
       2015-05-06 11:16:01 +08:00
    http://opentalk.upyun.com/show/issue/15
    这里面洪小军的演讲可能对你有帮助
    fuxkcsdn
        47
    fuxkcsdn  
       2015-05-06 11:20:32 +08:00
    把最近1礼拜的评论存放在 redis 上,其余的存在 mysql 里,1礼拜前的老帖本来看的人就少(你去试试要翻 cnbeta 1礼拜前的贴要翻几页就知道了)

    代码里也就多一个判断
    $comment = hGetAll('item_comment:65442345');
    if(count($comment) === 0) {
    $comment = $pdo->query('select * from t_comment where id=65442345');
    }
    yuankui
        48
    yuankui  
       2015-05-06 11:29:42 +08:00
    yuankui
        49
    yuankui  
       2015-05-06 11:31:38 +08:00
    评论的化,放 mysql,加上索引,性能问题应该不大吧,而且,可以加缓存啊.
    fenzlie
        50
    fenzlie  
       2015-05-06 12:13:59 +08:00   ❤️ 15
    为了回答这个问题特意去注册了一个帐号,结果发现还得等7000秒才能回复...

    首先,如果你的系统还没有一个DAL层,那么是时候去实现一个了。否则下面的内容也没必要看了。

    短期解决方案,你的MYSQL使用肯定有问题,不到百万级的数据不太可能搞不定。从表结构,语句,配置,连接池等等方面入手优化。就算你的业务再复杂,应该也可以应付得来。如果实在不行,必须要用REDIS,那就自己写一个一致性HASH,REDIS设置成多节点负载。这个实现快,也十分有效果,从KEY的数量上来看,区区65万X5也不算很大。 我之前记得100万KEY在REDIS中使用的内存也不过70M这样而已,当然,这和存的VALUE也有关系。现在商用服务器随便32G 64G内存,对数据结构做一些优化,REDIS也作一些优化BLABLA,用REDIS存储完全没有压力。注意这个阶段因为是对REDIS直接当数据库用的,所以要特别注意它的数据持久化和恢复方案。

    如果从预期上来看数据会随业务发展有暴发式增长的话,那就需要考虑冷热数据交替的架构,简单讲就是加缓存结构,其它分库分表之类的就不提了。 可以把上述短期解决方案中的REDIS集群直接用做缓存,不会改变的冷数据扔到MYSQL数据库中去。请求先到缓存层,取不到再到数据库去取,同时把数据放置在REDIS中。这里大概的实现可以这样做,所有在REDIS中的数据全都设置相应的过期时间,每次访问重置过期时间。在每个REDIS MASTER节点拖的SLAVE节点上作RDB,把生成的RDB文件离线定时解析,把其中过期时间小于某值的所有数据同步到MYSQL中。

    终极解决方案,如果你的数据量和访问量大到没边了。以上的REDIS集群不管怎么扩容,连正常的查询修改操作也完全COVER不住时。首先要恭喜你的应用比较牛B了现在。现在要做的事情有很多,可能需要有多级缓存,CDN扩展,甚至业务上要作一些妥协等等。从框架上来讲,大概的思路就是读写分离以及深化分离。 比如说,你前两步做的REDIS集群只用作读操作了,所有写操作只记录在简要日志中。写操作的请求过程中,不在数据持久层或缓存层作修改操作。然后你有离线的系统TAIL所有写操作的简要日志,把这些操作离线同步到数据持久层和缓存层。不过这样写操作因为只是记录了日志,写操作完成后有一段时间查询请求过来时是访问不到该修改的。这段时间的长短与你的离线日志流处理系统的性能相关。

    REDIS 的RDB解析可以用REDIS RDB TOOLS, 用PYTHON写的,对过期时间的处理可能需要一些自定义的修改,PYTHON新手就可以胜任。
    日志流的处理可以用卡夫卡,可靠,安全,速度快。
    li24361
        51
    li24361  
       2015-05-06 12:19:27 +08:00
    @fenzlie 讲得很好啊
    sunchen
        52
    sunchen  
       2015-05-06 12:21:46 +08:00
    试试aerospike,使用ssd
    keakon
        53
    keakon  
       2015-05-06 12:32:34 +08:00
    粗略看了下,只有 @xiaozi 说的是能快速有效解决的,很多人不用勉强答的…
    zyue
        54
    zyue  
       2015-05-06 12:36:14 +08:00
    @fenzlie 赞一个 讲的很好
    daoluan
        55
    daoluan  
       2015-05-06 13:01:45 +08:00
    只缓存热数据,数据库做分表/库,redis 没有你想的那么弱。
    phx13ye
        56
    phx13ye  
       2015-05-06 13:13:28 +08:00
    @fenzlie
    没有体验过这种场景,有专门讲方面的书吗???
    jevonszmx
        57
    jevonszmx  
       2015-05-06 13:47:25 +08:00   ❤️ 1
    @fuxkcsdn

    hgetall,时间复杂度是O(N),会死的很惨,慎用。



    应该分几个方面处理啊:
    1、分析用户常见浏览量,如果大多数浏览量都是最近N条,则做评论翻页功能,最新N条是热数据,存redis,其他可以使用mysql做被动缓存;

    2、评论分页使用前端缓存,如varnish,这样可以大大减轻后端压力;

    3、mysql数据分表;

    4、redis拆分实例,我们是程序实现了一个redis切片集群,通过key名hash切分到不同的redis实例;
    wys163
        58
    wys163  
       2015-05-06 14:21:25 +08:00
    mongodb 拯救你
    fenzlie
        59
    fenzlie  
       2015-05-06 15:42:00 +08:00   ❤️ 1
    @phx13ye 倒是没有留意过专门写这种场景的书。我是这样的来的,先了解一些分布式系统的基础知识,再找一些淘宝,京东,新浪微博等相关的讲座或说明去了解下。参加一些技术分享会,理解一些分布式相关的开源项目实现,比如说ZOOKEEPER,SPARK等。主要是理解这些公司分别应对的是什么样的问题,再去比较它们之间相似系统的实现差别。当然,最好是能进入有大流量公司的研发部门,这样直接干这一行最有效。

    这些问题大多是有些难度,又十分有意思,实现了又很有成就感的。比如说淘宝双11时在一个电视上实时的秒级同步显示当前各地区交易总量,交易总额。这个东西正常人都知道肯定不可能是每秒执行一个SQL去数据库里查出来的。
    hanwujibaby
        60
    hanwujibaby  
       2015-05-06 18:34:22 +08:00
    没有必要把所有的值放到缓存里。热数据放到缓存中,每次写的时候同步更新缓存的失效时间。redis活memcache有自己的缓存失效算法的。如果用redis的话, 注意redis的slave.不然主挂掉的话,缓存雪崩很麻烦。大并发下能直接压死mysql.大数据的话注意一下分表和分库。这些基本的策略能扛住日均1亿的访问。
    gfreezy
        61
    gfreezy  
       2015-05-07 00:14:07 +08:00
    qps到多少了,MySQL机器的配置是什么?
    我们业务 “赞” 的表到千万量级,用MySQL完全没啥问题啊。

    之前是遇到过MySQL性能不够用,后来升级了下MySQL的机器,问题就解决了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5438 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 06:52 · PVG 14:52 · LAX 23:52 · JFK 02:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.