文章目录
Mencache与Redis区别
redis为什么很快
关于单线程为什么更快:
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
redis常用数据类型
-
String,最基本的数据类型,二进制安全(可包含任何数据,512M),应用场景:常规key-value缓存应用。常规计数: 微博数, 粉丝数。
-
Hash,String元素组成的字典,适用于存储对象。
适用场景:存储需要部分变更的数据,如用户信息等。
-
List,列表,按照元素插入顺序排序。
适用场景:
1、消息队列系统:使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。比如:将Redis用作日志收集器,实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。
2、取最新N个数据的操作:记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。比如微博的新发布的博客常驻缓存
l代表从左边开始,r代表右边
-
Set,String组成的无序集合,通过哈希表实现,不允许重复。添加删除查找的复杂度都为O(1)
适用场景:
1.需要使用交集并集差集的时候例如显示共同关注的人。在微博中可以将一个用户所有的关注人存在一个集合中。
2、对一定时间内的数据去重
-
Sorted Set,通过一个double类型的分数来为集合中的成员进行从小到大的排序。它的成员是唯一的但是分数可以重复。
适用场景:与set类似,只不过它是有序的。
-
用于计数的HyperLogLog,用于存储地理位置信息的Geo
以上数据结构都是通过如下数据类型实现的
缓存穿透、雪崩
缓存穿透是指查询一个不存在的数据,但是由于 Cache不命中,又需要去DB中查询,造成的性能下降解决方案:给没有命中的key设定“没有意义的空值
缓存雪崩是指 Cache设置了相同的过期时间,导致 Cache在同一时间失效,请求全部转发到DB,DB的瞬时压力过大,造成雪崩解决方案:给key设定不同的(随机的)过期时间
如何从海量的key中获取带有一定前缀的key
- keys pattern,一次性返回所有匹配的key
- scan course [MATCH pattern] [COUNT count] count 只能作为一个参考,不一定能返回该数量的数据。
如何实现异步队列
- 使用rpush生产消息 和 lpop消费消息
缺点:不会等待队列里有值才消费。
解决该缺点的方法:
1、可以通过咋应用层引入sleep机制调用lpop重试
2、使用blpop key [key …] timeout:阻塞直到消息队列中有数据或者超时(该方法只能供一个消费者消费)
3、pub/sub主体订阅者模式
发送者pub发送消息,sub订阅者订阅消息
缺点:
消息发送无状态,无法保证可到达(有可能丢失),比如某个消费者在生产者发布消息的时候下线,他在重新上线后是无法收到消息的。要解决只能通过专业的消息队列比如kafka。
如何通过redis实现分布式锁
分布式需要解决的问题
- 互斥性,任意时刻只能有一个客户端获取锁
- 安全性,锁只能由持有该锁的客户端删除
- 死锁,获取锁的客户端因为某些原因宕机,其他客户端无法获取锁
- 容错,部分redis节点宕机时,客户端仍然可以获取锁
解决方案
- setnx key value。如果key不存在,则创建并赋值。
时间复杂度O(1)
返回值: 成功返回1,失败返回0
利用上诉功能,并且setnx具有原子性,若当前值存在则表示资源有线程在使用。
但是使用该方法还引发了一个问题setnx 设置的值是长期有效的,这就导致锁一直被占用,这时就需要使用如下方法解决(缺点:缺乏原子性):
expire key seconds
设置key的生存时间,过期自动清除
在程序中的伪代码如下
解决方法:
set key value [ex seconds] [px milliseconds] [nx|xx]
// NX是不存在时才set, XX是存在时才set, EX是秒,PX是毫秒
jedisClient.set(key, value, "NX", "EX", expireSecond);
在大量key同时过期时
由于过于集中清除大量key很耗时,将出现短暂卡顿现象
可以在设置key过期时间的时候给每个key加上随机值
redis持久化
查看redis目录下的redis.conf文件
进入src目录
rdb文件按保存的位置
打开
实现持久化
使用rdb快照持久化:保存某个时间点的全量数据快照
- SAVE:阻塞redis的服务进程(主进程),直到rdb文件被创建完毕。(就是说会卡住)
- BGSAVE:Fork一个子进程来创建rdb文件,不阻塞服务器进程
save:
进入进入redis.conf目录搜索dir,可以看见rdb文件的保存目录。
使用save保存快照
lastsave指令(上次执行save指令的时间)
bgsave(客户端不会卡顿)
BGSAVE原理
只有当调用者试图修改资源时才会真正复制。对于其他调用者来说初始资源未改变。
自动触发RDB持久化的方式
rdb方式的缺点
使用AOF(Append-Only_File)持久化:保存写状态(将除了查询之外的所有操作增量保存)
默认AOF是关闭的需要去配置文件中打开
aof的不断写入会使文件不断增大
数据恢复
AOF和RDB区别
混合方式
在redis重启时,先使用bgsave持久化重新构建内容,再使用AOP重放近期操作来完成数据的恢复。
Pipeline及主从同步
pipeline
主从同步
原理
- 全同步:(全同步之后一般所有的读操作在slaver上运行,写操作在master上)
1)从服务器连接主服务器,发送SYNC命令;
2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令; - 增量操作
从服务器越多越好么?
并不是,从服务器相当于挂在主服务器上, 每次有写入请求,主服务器都需要对所有从服务器发送数据进行同步,这就相当于上传下载操作,将影响性能
配置主从同步
启动三个redis服务,可以启动三个虚拟机,分别启动一个redis服务
查看默认主从同步配置
可以发现三台都一样
任选一台作为主节点,主节点不需要修改,只修改另外两台从节点
在redis核心配置文件中进行修改
重启服务再次查看主从同步配置,发现已经更改
无磁盘化复制
当磁盘很垃圾,带宽很高的时候可以使用。
从服务器连接上后,主服务器将rdb直接写入socket中,不存入磁盘。
主从同步弊端
不能提供高可用,当主服务宕机,则无法进行写入操作
解决方法:
redis集群
解决上诉问题:
一致性的Hash算法是对2的32方取模(一般hash是对服务器个数取模)。即,一致性Hash算法将整个Hash空间组织成一个虚拟的圆环,Hash函数的值空间为0 ~ 2^32 - 1(一个32位无符号整型),整个哈希环如下:
对数据进行hash后会将数据存储到按顺时针排列最近的一个节点上。
假如一个节点宕机,受影响的只是宕机的节点与它逆时针最近的一个节点之间的数据
假如增加一个节点,受影响的只是新增的节点与它逆时针最近的一个节点之间的数据
关于数据倾斜的问题
引入虚拟节点可以解决该问题,一般虚拟节点为32个甚至更大