应用场景:在某大型互联网公司,有上亿的用户,要统计当前用户的在线人数和在线用户id,最快的实现方法是什么?
答:一般情况下,我们都使用数据库字段在用户登陆状态发生变更时进行变更,查找在线人数和在线用户id都是用select的方式。但是这种方式在实际中,调取速度非常慢,效率比较低,时效性差。
在redis中,我们知道setbit,bitcount等方法,可以直接对二进制位进行存储和变更,以及计数,根据这些我们讲述一下它的实现思想。
setbit(name,offset,value),对name对应值的二进制表示的位进行操作。参数offset,位的索引(将值变换成二进制后再进行索引,起始位0);value,值只能是1或0。
getbit(name,offset),获取name对应值的二进制表示中的某位的值(0或1)。
bitcount(key,start=None,end=None),获取name对应的值的二进制表示中1的个数。参数key,Redis的name;参数start,位起始位置;参数end,位结束位置。
注意:
通过在redis中实际检查,我们确认了以下的情况:
1.参数offset的索引的起始位为0;
2.getbit中,超出参数name指定的字符串值的索引的对应位的默认值均为0
3.在setbit中我们可以设置超出指定字符串位的索引位的相应的位值。
通过上面的实现,我们了解到我们可以在数据库中通过字段的变更和查看,我们为了维护上亿的用户的信息,提升其调用效率和速度,我们可以使用二进制位的设定。
设置一个key,如state_code,如果用户登陆,就通过“setbit state_code offset 1” 来改变用户的登陆状态(offset用唯一的用户id来指定,字符位为1的代表用户为登陆状态,0为离线状态)。
注:想要获取字符串的二进制位,可以先将其转成ascii码(ord()),再将ascii码转换成二进制位(bin())。如:ord('a'),返回97;bin(97),返回0b1100001。
通过上面的命令,我们可以发现,我们设置了用户id为0,8,10000000和1000000000的登陆状态为登陆状态(位值为1)。
再通过bitcount我们可以清楚地掌握当前的在线用户数。
想要了解当前的在线用户的id,我们可以通过for循环实现,将位值为1的依次打印出来即可。
有点:效率大大提升,10M就能存下10*1024*1024*8=83886080 八千多万的用户的登陆id和在线用户数,相对于数据库字段的调用,无论是存储,写入,修改,读取的速度都大为提升。