redis的数据类型和底层数据结构
5种基本类型+3种拓展类型。
sorted Set底层使用跳表,结构如下。
- redis的哈希表:通过链表来解决哈希冲突,reshap过程(3个步骤-较大的那个)。
- 压缩列表-相当于一个数组,和数组不同的是压缩列表在表头有三个字段zlbytes,zltail和zlen分别表示列表长度,列表尾的偏移量和元素个数。第一个和最后一个o(1),其他元素–o(N)
- Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的。但其他功能如持久化、集群数据同步由额外的线程执行。
- redis快?1.io多路复用;2. 内存数据库。
redis中AOF是后写日志的:先执行命令,数据写入内存,再记录日志(1.避免出现记录错误命令的情况,2.不会阻塞当前的写操作,缺点:1.还没来得及写日志就宕机了—数据丢失风险。可能会阻塞下一个操作,磁盘写入压力大).AOF的回写频率:1.always,2everysec:每秒回写,no:由OS决定何时将缓冲区的内容写回磁盘。
AOF日志文件过大?—redis根据数据库的现状创建一个新的AOF文件,也就是说,读取数据可中的所有键值对,然后对每一个键值对用一条命令记录它的写入。例如:key:value—重写机制会记录set key ,value。。优点:重写机制(fork出新的进程:bgrewriteaof)具有“多变一”的功能。旧日志文件中的多条命令,保留了最新的。—两个日志(保证重新过程新的日志不丢失)。AOF日志和AOF重新日志,拷贝完成后,替换。
内存快照(把某一个时刻数据库的数据以文件的形式写到磁盘上,是数据而不是命令):宕机后,redis如何快速恢复(直接copy数据就可以),
redis有两个命令来生成RDB文件,分别是save和bgsave(默认,创建一个子进程,专门用于写入RDB文件)。快照时数据能修改吗?
----为了快照而暂停写操作,肯定是不能接受的。redis使用OS的写时复制技术----Copy-On–Write,COW。
修改数据时,这块数据会被复制一份,生成该数据的副本。bgsave子进程会把这个副本数据写入RDB文件中,而在这个过程中,主进程仍然可以直接修改原来的数据。
RDB的频率不好控制。redis4.0提供了一种混合使用AOF日志和内存快照的方法。简单的说。内存快照以一定的频率执行,在两个快照中,使用AOF日志记录着期间的所有写命令。
redis的简单动态字符串。
1.有单独的统计变量len(读写字符串不用依赖’\0’终止,保证了二进制安全),free(直接判断出是否需要申请空间)
redis的过期策略(定时过期-内存友好,CPU不友好、惰性过期、定期过期)与内存淘汰策略(全局的键空间、设置了过期时间的键空间)
redis的事务不支持回滚。
redis的事务语句。multi,exec,discard,watch(乐观锁,CAS,监控事务是否被修改,unwatch)
分布式锁:临时有序节点(序号最小的)
redis单实例中实现分布式锁的正确方式(原子性非常重要):SET key_name my_random_value NX PX 30000 # NX 表示if not exist 就设置并返回True,否则不设置并返回False PX 表示过期时间用毫秒级, 30000 表示这些毫秒时间后此key过期。
多节点redis实现的分布式锁算法(RedLock):有效防止单点故障,
获取每个redis实例的锁,1.计算总的时间差,2.一半以上的redis主机都成功获得锁。—本次成功获得锁。 Redis Distributed Lock–红锁
Memcached 和 Redis 采用哈希表作为 key-value 索引。
• Redis 提供了 INCR/DECR 命令,把这三个操作转变为一个原子操作了。2。Lua脚本
哈希桶中的元素保存的并不是值本身,而是指向具体值的指针。这也就是说,不管值是 String,还是集合类型,哈希桶中的元素都是指向它们的指针。
你看,这个查找过程主要依赖于哈希计算,和数据量的多少并没有直接关系。也就是说,不管哈希表里有 10 万个键还是 100 万个键,我们只需要一次计算就能找到相应的键。
跳表在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位,如下图所示
主从库:读操作,主从都OK。写操作,首先在主库,然后同步到从库
replicaof命令
哨兵其实就是一个运行在特殊模式下的 Redis 进程,主从库实例运行的同时,它也在运行。哨兵主要负责的就是三个任务:监控、选主(选择主库)和通知
PING
redis的分片集群,切片集群。
具体来说,Redis Cluster 方案采用哈希槽(Hash Slot,接下来我会直接称之为 Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽。
key在哪个哈希槽:1.通过key计算CRC16位的数。2.该数对16384取模的结果表示一个具体的哈希槽索引。Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。
而GEO它的底层基于Sorted Set,因为LBS服务比如打车服务,都是需要范围查询的,需要将范围内可打的车按照与打车人之间的距离进行排序,所以自然而然要用能排序的数据结构,且score相近则两个位置的经纬度也相近。
redis保存时间数据:Redis Streams 。
redis实现消息队列(1.消息保证顺序、避免重复消费(全局唯一的 ID 号)、2保证消息的可靠性)。实现方法:1.List;2/Streams
如果一个操作能被异步执行,就意味着,它并不是 Redis 主线程的关键路径上的操作.
异步的键值对删除和数据库清空操作是 Redis 4.0 后提供的功能,—惰性删除()
但实际上,这个时候删除还没有执行,等到后台子线程从任务队列中读取任务后,才开始实际删除键值对,并释放相应的内存空间。因此,我们把这种异步删除也称为惰性删除(lazy free)。此时,删除或清空操作不会阻塞主线程,这就避免了对主线程的性能影响。
如果 Redis 的内存不够用了,操作系统会启动 swap 机制,这就会直接拖慢 Redis。
删除数据后,为什么内存占用率还是很高?----内存碎片。启动:activedefrag:yes
可能导致溢出的情况主要是下面两种:
写入了 bigkey,比如一下子写入了多个百万级别的集合类型数据;
布隆过滤器。它的查询效率很高,经常会用在缓存场景中,可以用来判断数据是否存在缓存中。
一致性:
• 缓存中有数据,那么,缓存的数据值需要和数据库中的值相同;
• 缓存中本身没有数据,那么,数据库中的值必须是最新值。
、如何解决数据不一致问题?
1.引入消息队列+重试
缓存三大问题:
redis在统计聚合中的应用
在一些场景下,有些数据被访问的次数非常少,甚至只会被访问一次。当这些数据服务完访问请求后,如果还继续留存在缓存中的话,就只会白白占用缓存空间。这种情况,就是缓存污染。解决方案LFU策略,
极客时间资料:https://g.yuque.com/jdxj/abc3qm/vcsbx8?language=zh-cn