最近遇上评论数据的瓶颈了,放 mysql 吧受不了这么大的请求量,放 redis 吧,内存受不了。
mysql 请求太多,继续用的话只能再堆服务器了
redis 吧,数据太多了,比如:评论数据
按 item_comment:item_id
去存取数据的话,那么现在的 item 已经到6位数了。。。那么也就是说 redis 里有 item_comment:654321(n)
仅仅评论数据就有 6 位数的 key 了,那么加上所有的互动就有 5*654,321
位数的 key,还是继续增加中。。。内存就。。。。
有什么好办法。。。
1
zhangwei 2015-05-06 08:45:32 +08:00
又想马儿跑得快,又想马儿不吃草
|
2
whatisnew OP 以前老骂cnbeta只在24小时内显示评论数据,现在终于充分理解了。。。
|
3
whatisnew OP |
4
freshlhy 2015-05-06 08:48:37 +08:00
围观
|
8
rqrq 2015-05-06 08:56:23 +08:00
业务需求是什么?以至于十万级的评论数据让mysql承受不了了。
|
9
gowithwind 2015-05-06 08:57:37 +08:00
舍不得内存,就用缓存呗.针对热数据缓存.
|
11
whatisnew OP @gowithwind 热数据缓存不还得用到 redis 么。。。
|
12
Livid MOD 数据库大到一定程度就必须要拆。
拆到不同的表甚至不同的服务器上。 |
13
nowcoder 2015-05-06 09:01:10 +08:00
牛客网的评论放在mysql,赞放在redis
|
14
simonlei 2015-05-06 09:01:44 +08:00
冷热数据分离。热数据在内存,冷数据在硬盘。
|
15
wy315700 2015-05-06 09:03:10 +08:00
mysql试试看innodb呗
不行就上hbase吧 |
16
xiaozi 2015-05-06 09:05:08 +08:00 1
用hash优化
item_comment:6543 21(n) 22(n) 设置过期时间,自动清理冷数据 |
17
kier 2015-05-06 09:07:31 +08:00
说说看并发量是多大?
|
18
whatisnew OP 设置过期时间是个好主意!
但是 hash 优化的话。。。不在一个点上哦,一个 item_comment 对应的是一个 json 字符串,不是按多少楼分的。。。是依 item 为单位的。 |
19
lincanbin 2015-05-06 09:09:37 +08:00
评论的缓存过期时间是多久?
|
20
whatisnew OP 然后, item_comment 里对应的那些用户 user_id 读取 avatar nickname 这些字段怎么办。。。存成死数据吗?
|
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 转换。
|
23
whatisnew OP @xiaozi 把 key 的 id 拆分成两个数字.... 这一段没看懂,哪个 key 哪个 id?一个 hash 里边可以存超过 6 位数的 field 吗。。。
|
24
cdffh 2015-05-06 09:17:12 +08:00
十万条数据不断多哦 是读写太频繁了吗
|
25
huitailang 2015-05-06 09:18:38 +08:00
围观~
|
27
cdffh 2015-05-06 09:21:25 +08:00
额 现在大概的数据规模是多大啊。 并发多少啊。这些情况要说清楚啊。不然不好找优化点啊
|
28
gowithwind 2015-05-06 09:24:31 +08:00
我看楼主也是不愿花钱,这样的话考虑用ssdb吧.和redis基本类似,底层是leveldb,大量数据存在硬盘里,性能也可以.
|
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 |
30
nevernet 2015-05-06 09:29:05 +08:00
@gowithwind ssdb现在稳定了吗?
|
31
czheo 2015-05-06 09:29:19 +08:00
mysql主从设了么?读写分离啊。
|
35
czheo 2015-05-06 09:47:54 +08:00
mysql query cache开了么?
|
38
youxiachai 2015-05-06 09:54:26 +08:00
ssdb ? 接口跟redis 直接兼容..
|
39
czheo 2015-05-06 09:55:29 +08:00
redis里面放最近1000的comment, 翻页到1000以后开始从mysql读数据。
|
40
whatisnew OP @youxiachai 我是说他是存内存的还是存ssd的。。。还是都可以。。。
|
41
justfly 2015-05-06 09:56:17 +08:00
给个思路 mysql里面放评论的详细信息 redis里面只存放 ID 查询的时候先查redis得到ID 再从mysql里面拿详细信息组合 mysql上面可以放一层memcache或者redis 固定内存大小 做缓存 存放热数据
|
42
tonghuashuai 2015-05-06 10:19:19 +08:00
如果是我我会这么做:
评论内容放在 mysql,评论关联,赞,星标放到 redis |
43
tonghuashuai 2015-05-06 10:29:20 +08:00
抱歉,上一条回错了,没有看全就回了。。。
|
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 中,可以参考新浪微博的关注的实现。 |
45
cfan8 2015-05-06 10:52:42 +08:00
评论数据直接和item meta info压在一起吧,既然上NoSQL也没必要考虑什么范式之类的东西了
|
46
guoer 2015-05-06 11:16:01 +08:00
http://opentalk.upyun.com/show/issue/15
这里面洪小军的演讲可能对你有帮助 |
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'); } |
48
yuankui 2015-05-06 11:29:42 +08:00
|
49
yuankui 2015-05-06 11:31:38 +08:00
评论的化,放 mysql,加上索引,性能问题应该不大吧,而且,可以加缓存啊.
|
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新手就可以胜任。 日志流的处理可以用卡夫卡,可靠,安全,速度快。 |
52
sunchen 2015-05-06 12:21:46 +08:00
试试aerospike,使用ssd
|
55
daoluan 2015-05-06 13:01:45 +08:00
只缓存热数据,数据库做分表/库,redis 没有你想的那么弱。
|
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实例; |
58
wys163 2015-05-06 14:21:25 +08:00
mongodb 拯救你
|
59
fenzlie 2015-05-06 15:42:00 +08:00 1
@phx13ye 倒是没有留意过专门写这种场景的书。我是这样的来的,先了解一些分布式系统的基础知识,再找一些淘宝,京东,新浪微博等相关的讲座或说明去了解下。参加一些技术分享会,理解一些分布式相关的开源项目实现,比如说ZOOKEEPER,SPARK等。主要是理解这些公司分别应对的是什么样的问题,再去比较它们之间相似系统的实现差别。当然,最好是能进入有大流量公司的研发部门,这样直接干这一行最有效。
这些问题大多是有些难度,又十分有意思,实现了又很有成就感的。比如说淘宝双11时在一个电视上实时的秒级同步显示当前各地区交易总量,交易总额。这个东西正常人都知道肯定不可能是每秒执行一个SQL去数据库里查出来的。 |
60
hanwujibaby 2015-05-06 18:34:22 +08:00
没有必要把所有的值放到缓存里。热数据放到缓存中,每次写的时候同步更新缓存的失效时间。redis活memcache有自己的缓存失效算法的。如果用redis的话, 注意redis的slave.不然主挂掉的话,缓存雪崩很麻烦。大并发下能直接压死mysql.大数据的话注意一下分表和分库。这些基本的策略能扛住日均1亿的访问。
|
61
gfreezy 2015-05-07 00:14:07 +08:00
qps到多少了,MySQL机器的配置是什么?
我们业务 “赞” 的表到千万量级,用MySQL完全没啥问题啊。 之前是遇到过MySQL性能不够用,后来升级了下MySQL的机器,问题就解决了。 |