由简入繁,水滴石穿。想到哪记到哪,加油!!!
Redis 支持的数据类型
- String 字符串:set key value格式。String 类型是二进制安全的,就是说Redis中String可以包括任何数据,jpg图片或者序列化对象,一个键值对最大能存储512MB数据。
- 缓存功能:String 字符串在各个开发语言中都是使用最广泛的,在Redis中可以加快系统读写速度,降低压力,使用也简单,常见的就是把List呀、Bean呀什么的转成JSONString进行存储,拿出来在反向序列化使用。
- 计数器:可以使用Redis作为系统的实时计数器,可以快速查询和计数。如果使用计数器就涉及到另一个问题:分布式锁
- setnx key value,如果锁的key不存在,将key的值设为value并返回1;若key存在,setnx不做任何动作,返回0;即返回0为获取锁失败;返回1为获取锁成功;
- 共享用户session:这个很基本,常见的spring session就是使用redis进行会话集中管理的。
- Hash 哈希:hmset name key1 value1 key2 value2 格式。里面是一个键值(key=> value)对集合。是String 类型的field和value的映射表,特别适合存储对象。
- Hash类似Map结构,可以当做map操作存在redis中。
- Hash的编码也是ziplist或者hashtable,使用压缩有两种:
- 保存的同一键值对的两个节点紧靠相邻,key在前,值在后;
- 先保存的键值对在压缩列表的表头方向,后来在表尾方向;
- 如果使用字典方式:
- 字典的键为字符串对象,保存键key;
- 字典的值也是字符串对象,保存键值对的值;
- List 列表:ipush name value格式。简单的字符串列表,按照插入顺序排序,可以添加数据元素到表头或者尾部。添加头部数据:rpush name value;添加尾部数据:lrem name index;
- 异步队列:一般使用List结构作为队列,rpush生产消息,lpop消费消息,lpop是同步的,没有数据需要sleep一下等待数据。如果不想使用sleep的话,可以考虑blpop阻塞队列。
- list列表底层主要是使用压缩和双链表两种。
- 当list保存的数据所有字符串元素的长度都小鱼64个字节,使用压缩ziplist编码;
- 当list保存的元素数量小于512个也会去使用压缩编码;
- 除以上两种,其余都是使用双链表编码
- Set 集合:sadd name value格式。Set是Stiring类型的无序集合,内部是通过哈希表实现的,复杂度都是O(1)。
- Set对象的编码可以是intset或者hashtable:
- intset编码:使用整数集合实现,set对象包含的所有元素都被保存在intset整数集合中;
- set对象保存的所有元素都是整数;
- set对象保存的元素数量不超过512个;
- hashtable编码:字典实现,字典的键包含一个set元素,值为null;
- intset编码:使用整数集合实现,set对象包含的所有元素都被保存在intset整数集合中;
- Set对象的编码可以是intset或者hashtable:
- ZSet(sorted set有序集合):zadd name score value格式。不允许重复数据出现,每个元素都会关联一个double类型的分数,通过这些分数进行从小到大排序。
- ZSet对象编码可以是ziplist或者skiplist编码,每个集合元素使用相邻的两个压缩列表节点保存,一个保存元素成员,一个保存元素的分值,然后根据分值进行从小到大的排序。
- ziplist编码:
- 有序集合保存的元素小于128个;
- 有序集合保存的所有元素长度都小于64字节
- ziplist编码:
- ZSet对象编码可以是ziplist或者skiplist编码,每个集合元素使用相邻的两个压缩列表节点保存,一个保存元素成员,一个保存元素的分值,然后根据分值进行从小到大的排序。
高端数据结构
-
BitMap:位图是支持按 bit 位来存储信息,可以用来实现 布隆过滤器(BloomFilter)
- bitmap就是最小单位的bit来进行0或者1的设置,表示元素的值或者状态,一个bit最多存储信息是。8bit=1b=0.001kb
- 主要操作
命令 含义 getbit key offset 对key所存储的字符串值,获取指定偏移量上的位(bit) setbit key offset value 对key所存储的字符串值,设置或清除指定偏移量上的位(bit) 1. 返回值为该位在setbit之前的值 2. value只能取0或1 3. offset从0开始,即使原位图只能10位,offset可以取1000 bitcount key [start end] 获取位图指定范围中位值为1的个数 如果不指定start与end,则取所有 bitop op destKey key1 [key2…] 做多个BitMap的and(交集)、or(并集)、not(非)、xor(异或)操作并将结果保存在destKey中 bitpos key tartgetBit [start end] 计算位图指定范围第一个偏移量对应的的值等于targetBit的位置 1. 找不到返回-1 2. start与end没有设置,则取全部 3. targetBit只能取0或者1 -
HyperLogLog:用来做基数统计的算法,在输入元素的数量或者体积非常大的时候,计算基础所需要的的空间总是固定的、并且很小(来自菜鸟教程)。
上述不是很好理解,菜鸟教程给出的比较笼统。举个例子:我们在某网站发布了一个博客文章,想统计一天内有多少人独立访问过这个文章,也就是即使这个人访问了20次,有效访问次数也是1次,而不是20次。
- 对每一个独立访客增加一个标识
- 记录访客点击链接编号及访客标识
- 然后维护一个中心表,如果访客是第一次点击,链接计数加一
使用HyperLogLog就简单的多,可以将链接作为key ,访问者进行PFADD进去,最后PFCOUNT出来的值就是纯基数了。就是这么简单
- SpringBoot 中使用Redis HyperLogLog
/** 注入 StringRedisTemplate, 使用默认配置 */ @Autowired private StringRedisTemplate stringRedisTemplate; @Test @SuppressWarnings("all") public void testHyperLogLog() { HyperLogLogOperations operations = stringRedisTemplate.opsForHyperLogLog(); // 添加 方法对应 PFADD 命令 operations.add("ip_20210501", "192.168.0.1", "192.168.0.2", "192.168.0.3"); // 基数估算值 方法对应 PFCOUNT 命令 System.out.println(operations.size("ip_20210501")); // 3 operations.add("ip_20210501", "192.168.0.1", "192.168.0.4"); System.out.println(operations.size("ip_20210501")); // 4 operations.add("ip_20210502", "192.168.0.1", "192.168.0.5"); System.out.println(operations.size("ip_20210502")); // 2 // 合并 方法对应 PFMERGE 命令 operations.union("ip_202105", "ip_20210501", "ip_20210502"); System.out.println(operations.size("ip_202105")); // 5 }
- 占用体积:HyperLogLog 占用是固定的,不会存储输入元素本身,基本上每个键大约12KB的内存。
-
Geo:主要用来存储地理位置信息,能对存储的信心进行一些操作;
- geoadd:添加地理位置信息
- geopos:获取地理位置信息
- geodist:计算两个信息之间的距离
- georadius:获取指定经纬度范围内的元素集合
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合
- geohash:返回一个或多个位置对象的 geohash 值
-
Pub/Sub
Redis的pub/sub中,sub是需要独占一个Redis连接的,这样就会需要消耗一个线程资源。
另外主题订阅模式是支持1:N的消息队列的,不过在消费者下线时,生产的消息会丢失。
Redis 持久化
持久化就是把内存中的数据写入磁盘中,防止服务器宕机后内存数据丢失。Redis提供了两种持久化方式:RDB(默认)、AOF
- RDB
Redis DataBase缩写,核心函数rdbSave就是将内存数据生成RDB文件,载入时rdbLoad函数组成。原理就是通过fork创建一个子进程去进行RDB操作,cow创建子进程共享数据段。
- AOF
Append-only file 缩写,可以通过执行或者定时任务执行函数flushAppendOnlyFile都会被调用,该函数执行两个工作,一个是写,将aof_buf的缓存写入AOF文件中;根据条件调用fsync或者fdatasynv函数,将AOF文件保存到磁盘中。
如果运行中突然断电,可以通过AOF里面的sync配置,配置数据同步是时间,减少丢失数据范围。
- 存储结构
都是通过redis通讯协议(RESP)格式的命令文本存储。
- 两者比较
- AOF文件比RDB文件更新频率更高
- AOF比RDB文件更安全,体积也更大
- RDB比AOF在性能上好
- 两者可以一同配置,优先加载AOF
- RESP
Redis客户端和服务器之间使用的一种通讯协议,简单、可以快速解析、可读性好。
淘汰策略
基本是与本地缓存Ehcache、Memcache、Hazelcast等等类似:FIFO淘汰最早数据、LRU淘汰最近最少使用、LFU淘汰最近最少使用频率。
- noeviction:默认策略,不淘汰,如果内存已满,添加数据是报错
- allkeys-lru:回收最少使用
- vlatile-lru:回收过期集合的键、最少使用
- allkeys-random:随机回收
- volatile-random:过期随机回收
- volatile-ttl:回收过期的键,并且回收存活时间短的