Redis
# Redis
# 1、如何使用Bitmap统计活跃用户?
# 1.1比特位的长度代表总的用户数
场景:连续天数活跃的用户数量
使用setBit插入每天活跃用户的数量信息。其中key可以为日期,如20221220。offset偏置设置为用户ID,第几个用户对应位图上的第几位。
#20221220为key的位图上,将第5个bit位置为1。>>00001
>SETBIT 20221220 5 1
2
因此某一天的所有用户登录状态可以通过redis获取,想要求出某段时间的连续活跃用户数,则使用BITOP指令对多个位图结果做"与"操作即可。
>BITOP and result 20221220 20221221
>BITCOUNT result
2
# 1.2比特位的长度代表天数
场景:统计用户签到信息
位图的key设置为用户Id,offset偏执设置为天数(月30天/年365天),第几天签到则在第几个比特位上置1。
# 2.谈谈其它几种结构的应用场景
Set:可以用于记录某个活动报名的所有用户信息。其中key为活动Id,value为所有用户ID的set集合。
Hash:可以用于存储对象信息,一个对象内包含多个字段。比如购物车场景,key为用户ID,value为多个字段对的对象信息(field-value),field1为商品1的ID,value1为商品1的数量;field2为商品2的ID,value2为商品2的数量...
HyperLogLog:统计页面UV,每次访问添加用户ID。(存在重复ID则不会创建)
# 3.Redis单线程模型
redis单线程指的是从客户端连接->读取socket,接收数据->执行->响应整个过程是单线程,但是持久化等都是fork子进程执行。此外redis6.0也支持多线程处理。
redis单线程模型快的原因主要有两方面原因:
- 内存操作,就是快。
- I/O多路复用。单线程减少上下文切换,容易维护。
I/O多路如何提高通信效率?
一个客户端连接请求对应一个套接字,Redis服务端需要同时处理多个套接字。普遍的方法有两种:
- 方法①:一个请求创建一个线程处理,随着线程数越多,上下文开销也会越来越大。
- 方法②:只创建一个服务端进程,处理多个客户端连接的通信场景。存在一个大问题:如果客户1的数据还没到达,那么服务端进程会被阻塞,其它用户准备好的数据也无法快速响应。
Redis中IO多路复用的做法是通过一个线程(I/O多路复用程序)来监视多个套接字的准备状态。发现有数据准备好了后,就会轮询一边所有的套接字,依次顺序执行准备好的套接字,基于reactor模式从队列当中交给事件分发器。常见的几种多路复用方式如下:
- select:只能监视1024个套接字,轮询所有套接字
- poll:可以监视任意数量的套接字
- epoll:可以监视任意数量套接字,并只轮询真正发出事件的套接字
综上,I/O多路复用的本质是通过监视的方式避免线程被阻塞的场景,提高CPU利用率。实际上还是串行执行每个客户端请求,速度比不上多线程并行执行。