35海量数据计数器(+1)

413 阅读3分钟

1.计数器使用场景

微博的计数场景有:

微博的评论数、点赞数、转发数、浏览数、表态数等等(热点数据,经常查询)

用户的粉丝数、关注数、发布微博数、私信数等等

\

不好的设计:

把计数与微博数据存储在一起,这样每次更新计数的时候都需要锁住这一行记录,降低了写入的并发

点赞数不需要展示谁点赞,因此不用记录点赞行为(业务保证)

2.计数器的业务特点

数据量大

访问量大,对系统性能要求高

可用性和数据的准确性要求高

3.高并发计数系统如何设计

第一阶段:使用MySQL存储

将微博id,点赞,评论,转发计数下来

select repost_count, comment_count, praise_count, view_count from t_weibo_count where weibo_id = ?

\

第二阶段:MySQL的分库分表

单表的存储量级达到几千万的时候,性能上就会有损耗

因此采用分库分表的方式,分散数据量,提升读性能(写性能不变化在master上写,读会经过一次hash,查询复杂度logn,n越小查询越快)

\

怎么分库分表?

1.哈希算法对 weibo_id 计算哈希值,然后根据这个哈希值计算出需要存储到哪一个库哪一张表中

2.按照 weibo_id 生成的时间来做分库分表(ID 的生成最好带有业务意义的字段,比如生成 ID 的时间戳)

\

最近的数据是热点数据,因此按照时间分库分表

hash会使数据分布更均匀

\

第三阶段:使用Redis+MySQL

通过redis来加速读取性能,将redis也切分成多个分片

致命缺点:无法保证数据库和缓存数据一致性

第四阶段:完全使用Redis存储

将所有数据存储在redis中,异步加载到数据库中(兜底)

\

第五阶段:消息队列+Redis存储

使用消息队列削峰填谷

同时可以将多个写请求合并成一个写请求,提升写入性能

4.如何降级存储成本

1.可以优化原生redis数据库

  • 一是原生的 Redis 在存储 Key 时是按照字符串类型来存储的,比如一个 8 字节的 Long 类型的数据,需要 8(sdshdr 数据结构长度)+ 19(8 字节数字的长度)+1(’\0’)=28 个字节,如果我们使用 Long 类型来存储就只需要 8 个字节,会节省 20 个字节的空间;
  • 去除了原生 Redis 中多余的指针,如果要存储一个 KV 信息就只需要 8(weibo_id)+4(转发数)=12 个字节,相比之前有很大的改进

2.将先用weiboid的计数存储下一个hash下,减少了多个微博id计数

3.计数服务增加 SSD 磁盘,然后将时间上比较久远的数据 dump 到磁盘上,内存中只保留最近的数据

要读取冷数据的时候,使用单独的 I/O 线程异步地将冷数据从 SSD 磁盘中加载到一块儿单独的 Cold Cache 中\

\

5.总结

  • KISS原则(Keep It Simple and Stupid)

  • 数据库 + 缓存的方案是计数系统的初级阶段,完全可以支撑中小访问量和存储量的存储服务\

  • 使用 SSD+ 内存的方案可以最终解决存储计数数据的成本问题。这个方式适用于冷热数据明显的场景\

\