37 | 计数系统设计(一):面对海量数据的计数器要如何做?

2019-12-18 唐扬
《高并发系统设计 40 问》
课程介绍


讲述:唐扬

时长:大小12.50M


你好,我是唐扬。
从今天开始,我们正式进入最后的实战篇。在之前的课程中,我分别从数据库、缓存、消息队列和分布式服务化的角度,带你了解了面对高并发的时候要如何保证系统的高性能、高可用和高可扩展。课程中虽然有大量的例子辅助你理解理论知识,但是没有一个完整的实例帮你把知识串起来。
所以,为了将我们提及的知识落地,在实战篇中,我会以微博为背景,用两个完整的案例带你从实践的角度应对高并发大流量的冲击,期望给你一个更加具体的感性认识,为你在实现类似系统的时候提供一些思路。今天我要讲的第一个案例是如何设计一个支持高并发大存储量的计数系统。
来看这样一个场景: 在地铁上,你也许会经常刷微博、点赞热搜,如果有抽奖活动,再转发一波,而这些与微博息息相关的数据,其实就是微博场景下的计数数据,细说起来,它主要有几类:
微博的评论数、点赞数、转发数、浏览数、表态数等等;
用户的粉丝数、关注数、发布微博数、私信数等等。
微博维度的计数代表了这条微博受欢迎的程度,用户维度...

展开全文
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。

精选留言

  • 台风骆骆
    2019-12-18
    总结:
    1、一开始用mysql进行计数,后来加入了主从架构,分库分表架构。
    2、因为计数访问量太大了,加入了缓存,但是这个会造成相应的那个缓存和数据库数据不一致,如果要保证一性的话,就需要采用内存队列,对于同一个id的数量只能用单线程进行处理,这个会造成性能问题。
    3、后来直接抛弃了mysql,直接用redis cluster来支持计数服务,因为redis通过rdb和aof来支持持久化,可以通过设置保证至少有一台从redis机器同步了数据,从redis来做相应的那个持久化操作达到数据不丢失,因为原生的redis数据结构会占用比较多的字节,这里直接进行改造,让redis的数据结构占用内存加少。
    4、但是redis是全内存的,随着量越来越大肯定没法支持了,这里进行改造,引入ssd,支持把冷数据放到ssd中,热数据在内存中,当要访问冷数据时利用一个线程异步把冷数据加载到一个cold cache里面去。这个有很多开源的实现,如Pika,SSDB用ssd来替代内存存储冷数据。
    展开

    作者回复: 👍

    共 2 条评论
    48
  • 小困
    2020-05-23
    微博点赞还有哥难点,就是用户只能点赞一次,这个该用什么存储结构呢,或者技术方案

    作者回复: 布隆过滤器

    共 8 条评论
    10
  • Geek_zhuyu
    2020-01-20
    老师,通过消息队列来计数的话,怎么保证计数的准确性,比如关注数和粉丝数这种对准确性要求比较高的

    作者回复: 其实你很难保证写入完全没有错误,一般是对于粉丝数比较少的用户,在获取粉丝数的时候异步从数据库校对一下数据;如果粉丝是比较多,那么差几个用户也不会感觉到😂

    
    7
  • bug工程师
    2020-01-04
    老师,关于关注关系存储,我们公司现在用户的关注列表和粉丝列表都放在redis的sortedset结构中,一个key最大能够占到2g,现在8个节点,每个节点平均已使用20g容量,redis改造的能力我们不具备,还有什么其他优化思路,能够减少存储成本,获取粉丝列表响应时间低延迟呢?

    作者回复: 粉丝一般只在粉丝列表中展示,现在微博只展示5000个粉丝,所以没必要缓存全量的粉丝数据。

    共 3 条评论
    7
  • 吃饭饭
    2019-12-18
    【如果要存储一个 KV 类型的计数信息,Key 是 8 字节 Long 类型的 weibo_id,Value 是 4 字节 int 类型的转发数,存储在 Redis 中之后会占用超过 70 个字节的空间】这个 70 个字节是怎么算出来的,有点懵

    作者回复: 其实就是redis本身需要的一些存储空间,比如刚才提到的key使用string来存储需要28个字节,redis中使用的类似哈希表的数据结构叫dictEntry,也需要24个字节,还存储一些指针之类

    共 2 条评论
    7
  • 扬一场远远的风
    2019-12-23
    老师,这种海量的KV型计数,是否用 hbase存储会好简单许多?起码不用像mysql那样要在client端做分库分表。读请求依然可以走缓存。

    作者回复: KV型的redis、leveldb之类要比hbase性能好很多,hbase也比较重,要依赖hdfs

    
    6
  • gogo
    2019-12-18
    通过redis存储计数的话,如果redis机器故障了怎么办呢?微博本身的信息是如何存储的呢,老师能相信讲解下吗

    作者回复: redis可以做主从,然后从从库恢复数据

    共 4 条评论
    5
  • Dovelol
    2019-12-18
    老师好,想问下用redis的话该怎么用ssd配合做冷热数据存储呢,这块完全没经验,能讲讲具体的实现方案吗?

    作者回复: 就是需要改造一下redis,如果redis的数据写满了,就将比较旧的数据dump到磁盘上

    共 4 条评论
    5
  • grandcool
    2019-12-26
    Redis为啥开始不搞long类型的key呢,是为了通用性吗

    作者回复: 是的

    
    3
  • grandcool
    2019-12-26
    Pika是不是就是在Redis中改造了下逻辑,把旧的数据dump到SSD上了啊?

    作者回复: 类似

    
    3
  • 星空123
    2019-12-20
    老师的课虽然代码比较少,但是说实话,实际业务场景里还是能我们不少优化的思路。

    作者回复: 多谢肯定~

    
    3
  • Shine
    2020-08-05
    请教一个问题,有些计数点进去是有具体数据列表的,比如评论数,计数在redis,数据在数据库,数据会不会不一致,如果引入分布式锁,会不会影响性能?

    作者回复: 数据量大的情况下,计数很难百分百准确,可以看看微博的计数,很多是不准确的

    
    1
  • 小鱼儿吐泡泡
    2020-06-21
    有一个技术问题 想要请教下:

        需求:获取最近24小时内 点赞数 最多的top1000 的微博信息,更新间隔10分钟

    注意:这个点赞数是24h 内的点赞数 ,如:微博a 24h之前是1000个点赞 最近24h内 是5个点赞 那么我们在计算时 需要以5 来进行计算 而非1005(1000+5)


    我的想法是zset 保存最近24h内的微博id

    然后每个微博id再维护一个zset来计数 score为时间戳

    请教下 老师 有更好的解决方案吗
    展开
    共 1 条评论
    1
  • stg609
    2020-05-26
    一般达到多大的数据规模,需要考虑单独提供计数器的功能呢?还是说针对某一类的计数?

    我们大部分都是直接通过sql去数据库 select count,似乎目前也没什么问题

    作者回复: 面向C端的业务基本上不太可能select count吧

    
    1
  • 钱
    2020-05-10
    这讲的不是一个系统完整的方案,更像是一种计数器的演进
    1:放在MySQL中
    2:放在MySQL+redis中
    3:全部放在redis中
    4:把redis改造一下,精简存储空间,然后放在二次开发的redis中,我表示怀疑,正常来讲redis的作者应该做了这部分工作,再进行定制化可能是添加新的功能特性,如果还能精简存储空间,可以给redis提PR,否则估计不具有通用性,这里将改代码也不具体的
    5:放到redis+ssd中,又回到MySQL+redis了,只是根据数据的冷热,分区域存储
    我猜测MySQL+redis能满足80%的需求,甚至更多,再有定制化的需求估计也有实力改一下redis的源码
    展开
    
    1
  • Geek_bd613f
    2020-04-14
    老师你好,原生的 Redis 在存储 Key 时是按照字符串类型来存储的,比如一个 8 字节的 Long 类型的数据,需要 8(sdshdr 数据结构长度)+ 19(8 字节数字的长度)+1(’\0’)=28 个字节,如果我们使用 Long 类型来存储就只需要 8 个字节,会节省 20 个字节的空间。

    我查了下资料:

    redis 的 key 按照字符串类型储存的时候, key 由 SDS 组成,SDS 由
    len 字符串长度 1byt
    alloc 分配的内存 1byt
    flags        是哪种实现 sdshdr4 8 16 1byt
    char buf[] 字符数组用来储存 16byt

    SDS 的大小是 19个字节,
    老师你说:需要8(sdshdr数据结构长度)这个是什么意思呀?
    是不是我 对 redis string 类型的储存实现理解有误呀,看了半天没理解这个地方。盼回复~
    展开

    作者回复: 没记错的话,len 和free是unsigned int,各4个字节

    
    1
  • tm1234
    2020-04-06
    请问老师 mysql是支持强一致性的 但redis并不能,所以如果是对需要强一致性的计数场景(比如购物系统)是不是就不能放弃mysql完全使用redis呢?

    作者回复: redis也是一致的呀

    
    1
  • SuperYue
    2020-03-23
    老师 纯用redis,怎么解决事务的强一致性呢 比如转发和评论是一个事务性质的业务,转发的redis操作成功了,评论操作失败了 要手动补数据吗

    作者回复: 是要手动补数据

    共 2 条评论
    1
  • 好望角
    2020-03-17
    原生redis改造是啥意思啊?改源代码嘛

    作者回复: 是的

    
    1
  • 小洛
    2020-02-25
    两个问题咨下老师,第一个问题是相同微博id的计数数据放在一起,那在高并发更新下,会有性能问题吗,例如锁记录等,第二个问题是redis如何改造,才能不影响原本高效的查询性能,有进一步细节的分享么?谢谢老师

    作者回复: 1. 使用redis的话基本不会
    2. 其实文中有讲到,主要是对redis的代码做了修改,去掉了一些不必要的数据结构,以及更改的存储结构

    
    1