Redis的String类型有什么缺点
在花费内存方面,String花费的内存很多。如果存储的是64位有符号整数的话,就是一个8字节Long类型整数。如果是包含字符的话,就会用SDS,也就是简单字符串来存储,SDS中会把存储的数据最后加一个\0,还会存储使用的buf的长度,实际分配的buf的长度。
不仅如此,有一些统一的数据,Redis还会用RedisObject来存储。它包含元数据以及指向实际数据的指针。Redis对Long做了优化,会把指针直接变成Long的值,如果SDS小于44,会把RedisObject和数据布局在一起,超过的话就不能放在一起了。
不仅如此,Redis中的全局哈希,key value next也会耗费内存,所以我们可以用hash表中的压缩列表来实现保存。把key拆分成key1 key2,压缩列表可以存储一组entry,每一个entry会存储上一个entry的长度,自身长度,编码方式,自身数据,这减少了RedisObject的内存,还减少了指针的内存。
Redis的各种场景
聚合统计
也就是求交集,并集,差集,用在网站查看总人数,新增人数,留存人数。可以用set来存储,比如set id value set id:20240821 id value。需要注意的是set计算的时间复杂度很高,所以可以用一个从库来计算。
排序统计
例如求最新的东西,用在最新评论。list可以直接lpush,但是有一个缺点,就是如果在换页的时候正好有lpush操作,就会在第二页显示第一页的老数据。用zset就没有这个问题,可以设置权重,按照权重顺序来获取。
二值统计
只用记录0或1,可以用在签到上面,使用BitMap最好。SETBIT uid:sign:3000:202008 2 1
key是uid:sign:3000:202008,索引是2,值为1,也可以把日期作为key,用户作为索引,这样子只需要交集就可以知道谁连续登录了。虽然内存不大,但是最好也要设置过期时间
基数统计
统计网页一天净访问人数,可以用set或者hash但是使用的内存太多。HyperLogLog可以很好的完成基数统计,当集合元素数量非常多时,它计算基数所需的空间总是固定的,而且还很小。
地址统计
GEO数据类型,专门存储地址有关的数据,可以返回范围内的数据,zset没有办法保存经纬度,GEO是依靠zset作为底层结构,使用GeoHash来编码。
保存时间序列数据
在Redis中保存时间序列数据有两种方法
第一种是用hash和zset,并且用事务的方式保证原子性,但是不可以回滚,这种方法不能做聚合操作,想做聚合只能把数据返回过来,对带宽影响大。
RedisTimeSeries是专门操作时间类的,可以进行聚合操作,但是它搜索数据的时间复杂度是o(n)
带宽好,实例内存大,选第一种。
带宽差,数据量大,聚合操作多选第二种。
Redis用作消息队列
List和Streams
List有方法保证数据的有序性,也可以确保消费者是否接收到了消息,消费者也可以使用阻塞式等待List存在数据,但是数据过多,消费者处理慢的时候压力很大。
Streams可以保证有序性,可靠性的同时,支持被多个消费者读取。