本文 首发于 🍀 永浩转载 请注明 来源

17、【对线面试官】Redis基础

你先来讲讲为什么要用Redis吧?

  1. 我个人是这样理解的:无论Redis也好、MySQL也好、HDFS也好、HBase也好
  2. 他们都是存储数据的地方
  3. 因为它们的设计理念的不同,我们会根据不同的应用场景使用不同的存储
  4. 像Redis一般我们会把它用作于缓存
  5. 当然啦,日常有的应用场景比较简单,用个HashMap也能解决很多的问题了,没必要上Redis
  6. 这就好比,有的单机限流可能应对某些场景就够用了,也没必要说一定要上分布式限流把系统搞得复杂

那你在项目里有用到Redis吗?怎么用的?

  1. Redis肯定是用到的,我负责的项目几乎都会有Redisl的踪影
  2. 我举几个我这边项目用的案例呗?
  3. 我这边负责消息管理平台,简单来说就是发消息的
  4. 那发完消息肯定我们是得知道消息有没有下发成功的,是吧?
  5. 于是我们系统有一套完整的链路追踪体系
  6. 其中实时的数据我们就用Redis来进行存储,有实时肯定就会有离线的嘛(离线的数据我们是存储到Hive的)
  7. 对消息进行实时链路追踪,我这边就用了Redis好几种的数据结构,分别有Set、List和Hash
  8. 我再稍微铺垫下链路追踪的背景吧~
  9. 要在消息管理平台发消息,首先得在后台新建一个「模板」,有模板自然会有一个模板ID
  10. 对模板D进行扩展,比如说加上日期和固定的业务参数,形成的ID可以唯一标识某个模板的下发链路
  11. 在系统上,我这边叫它为UMPID
  12. 在发送入口处会对所有需要下发的消息打上UMPID,然后在关键链路上打上对应的点位
  13. 接下来的工作就是清洗出统一的模型,然后根据不同维度进行处理啦。比如说:
  14. 我要看某一天下发的所有模板有哪些,那只要我把清洗出来后数据的,将对应UMPID扔到了Set就好了
  15. 我要看某一个模板的消息下发的整体链路情况,那我以UMPID为Key,Value是Hash结构,Key是state,Value则是人数
  16. 这里的state我们在下发的过程中打的关键点位,比如接收到消息打个51,消息被去重了打个61,消息成功下发了打个81…
  17. 以UMPID为Key,Hash结构的Key(State)进行不断的累加,就可以实现某一个模板的消息下发的整体链路情况
  18. 我要看某个用户当天下发的消息有哪些,以及这些消息的整体链路是如何。
  19. 这边我用的是List结构,Key是userld,Value则是UMPID+state(关键点位)+processTime(处理时间)
  • 简单来说,就是通过Redis丰富的数据结构来实现对下发消息多个维度的统计
  • 不同的应用场景选择不同的数据结构,再等到透出做处理的时候,就变得十分简单了
  • 消息下发过程中去重或者一般正常的场景就直接Key-Value就能符合需求了
  • 像bitmap、hyperloglogs、sortset、steam等等这些数据结构在我所负责的项目用得是真不多
  • 要是我有机会去到贵公司,贵公司有相关的应用场景,我相信我也很快就能掌握
  • 这些数据结构底层都由对应的object来支撑着,objecti记录对应的「编码」
  • 其实就是会根据key-value存储的数量或者长度来使用选择不同的底层数据结构实现
  • 比如说:ziplist压缩列表这个底层数据结构有可能上层的实现是list、hash和sortset
  • Hash结构的底层数据结构可能是hash和ziplist
  • 在节省内存和性能的考量之中切换,Redis还是有点屌的啊。

就你上面那个实时链路场景,可以用其他的存储替代吗?

  1. 嗯,理论上是可以的(或许可以尝试用HBase),但总体来说没这么好吧
  2. 因为Redis拥有丰富的数据结构,在透出的时候,处理会非常的方便。
  3. 如果不用Redis的话,还得做很多解析的工作
  4. 并且,我那场景的并发还是相当大的(就一条消息发送,可能就产生10条记录)
  5. 监控峰值命令处理数会去到20K+QPS,当然了,这场景我肯定用了Pipeline的(不然处理会慢很多)
  6. 综合上面并发量和实时性以及数据结构,用Redis:是一个比较好的选择。

你觉得为什么Redis可以这么快?

  1. 首先,它是纯内存操作,内存本身就很快
  2. 其次,它是单线程的,Redis服务器核心是基于非阻塞的O多路复用机制,单线程避免了多线程的频繁上下文切换问题
  3. 至于这个单线程,其实官网也有过说明(:表示使用Redis往往的瓶颈在于内与和网络,而不在于CPU