1:redis 是用c语言来实现的,速度快 持久化 单线程 复杂的数据类型有bitmap和hyperloglog和geo地理信息
2:高可用、分布式
v2.8开始支持Redis-Sentinel(哨兵)高可用
v3.0开始支持Redis-Cluster 分布式
3:典型应用场景
缓存系统
计数器(如微博评论数,转发数以及点赞数)
消息队列
排行榜(sortset)
社交网络(set并集交集差集)
实时系统
4:可执行文件说明
redis-server Redis服务器
redis-cli Redis命令行客户端
redis-benchmark Redis性能测试
redis-check-aof AOF文件修复工具
redis-check-dump RDB文件修复工具
redis-sentinel Sentinel服务器(2.8以后)
5:三种启动方式
最简单启动 redis-server
判断是否启动成功
ps -ef|grep redis
netstat -antpl|grep redis
redis-cli -h ip -p port ping
动态参数启动
redis-server --port 6380 (默认6379)
配置文件启动
redis-server configPath
生产环境选择配置启动
单机多实例配置文件开源用端口号区分开
6:简单的客户端链接:
redis-cli -h 10.10.79.150 -p 6384
ping
set hello world
get hello
7:Redis Ping 命令使用客户端向 Redis 服务器发送一个 PING ,如果服务器运作正常的话,会返回一个 PONG 。
通常用于测试与服务器的连接是否仍然生效,或者用于测量延迟值。
# 客户端和服务器连接正常
redis 127.0.0.1:6379> PING
PONG
# 客户端和服务器连接不正常(网络不正常或服务器未能正常运行)
redis 127.0.0.1:6379> PING
Could not connect to Redis at 127.0.0.1:6379: Connection refused
8:Redis常用配置
deamonize 是否是守护进程默认no建议yes
prot redis对外端口号
logfile redis系统日志
dir redis工作目录
9:慢查询 找到系统中瓶颈的命令
客户端请求的生命周期
两点说明:
1.慢查询发生在第三阶段
2.客户端超时不一定慢查询,但慢查询是客户端超时的一个可能因素
10:edis的slowlog是redis用于记录记录慢查询执行时间的日志系统。由于slowlog只保存在内存中,
因此slowlog的效率很高,完全不用担心会影响到redis的性能。
Slowlog是Redis从2.2.12版本引入的一条命令。
在redis.conf中有关于slowlog的设置:
1slowlog-log-slower-than 10000
2slowlog-max-len 128
其中slowlog-log-slower-than表示slowlog的划定界限,只有query执行时间大于slowlog-log-slower-than的才会定义成慢查询,才会被slowlog进行记录。slowlog-log-slower-than设置的单位是微妙,默认是10000微妙,也就是10ms
slowlog-max-len表示慢查询最大的条数,当slowlog超过设定的最大值后,会将最早的slowlog删除,是个FIFO队列
10:慢查询命令
slowlog get [n] 获取慢查询队列
slowlog len 获取慢查询队列长度 队列里面有多少慢查询
slowlog reset 清空慢查询队列
11:
- pipeline 提高客户端的效率
流水线
减少网络时间的消耗
与原生M(mget,mset等)操作对比
M操作是原子操作
pipeline命令是非原子的,Redis服务器会对其命令集进行拆分。
- 发布订阅 redis的发布订阅功能
角色:发布者 订阅者 频道 订阅者可以订阅多频道(右图)
消息队列 要抢 Redis不仅可作为缓存服务器,还可用作消息队列。它的列表类型天生支持用作消息队列
发布订阅 都有
- Bitmap 减少内存的方案
-
bitmap位图的概念
- 其实类型也是字符串
-
首先来看一个例子,字符串big,
字母b的ASCII码为98,转换成二进制为 01100010 字母i的ASCII码为105,转换成二进制为 01101001 字母g的ASCII码为103,转换成二进制为 01100111
如果在Redis中,设置一个key,其值为big,此时
可以get到big这个值
,也可以获取到 big的ASCII码每一个位对应的值,也就是0或1
例如:
127.0.0.1:6379> set hello big OK 127.0.0.1:6379> getbit hello 0 # b的二进制形式的第1位,即为0 (integer) 0 127.0.0.1:6379> getbit hello 1 # b的二进制形式的第2位,即为1 (integer) 1
big长度为3个字节,对应的长度为24位,
使用getbit命令可以获取到big对应的位的对应的值
setbit getbit bitcount
- 若只有10万独立用户
数据类型 | 每个userId占用空间 | 需要存储的用户量 | 内存使用总量 |
---|---|---|---|
set | 32位(假设userId用的是整型) | 100,000 | 32位*100,000=4MB |
Bitmap | 1位 | 100,000,000 | 1位*100,000,000=12.5MB |
Java连接远程的redis时,连接被拒绝。
Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect
at redis.clients.jedis.Connection.connect(Connection.java:154)
at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:83)
at redis.clients.jedis.Connection.sendCommand(Connection.java:93)
at redis.clients.jedis.BinaryClient.set(BinaryClient.java:100)
at redis.clients.jedis.Client.set(Client.java:29)
at redis.clients.jedis.Jedis.set(Jedis.java:65)
at redis.Demo1.main(Demo1.java:10)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at redis.clients.jedis.Connection.connect(Connection.java:148)
... 6 more
可能的原因:
redis服务器的redis.conf配置中bind 127.0.0.1
应该改为:bind 0.0.0.0
- HyperLogLog 极端的减少内存的方案/数据结构(算法)
本质还是字符串
- GEO 地理信息
3.2版本添加的新特性 用来计算地理位置相关 其实zset类型实现
11:通用命令
mset /mget 批量设置 减少了网络时间 一般而言=网络时间+命令时间
sadd myset a b c d e 将一个或多个成员元素加入到集合中
keys * 生产不适用 热备从节点 scan
dbsize 计算key的总数
exists key 检查key是否存在
expire key seconds key在seconds秒后过期
ttl key 查看key剩余的过期时间
persist key 去掉key的过期时间
type key 返回key的类型
时间复杂度都是o(1)
12:
13:
单线程架构
单线程为什么这么块?
1.纯内存
2.非阻塞IO
3.避免现场切换和竟态消耗
14:字符串string操作
字符串类型
incr key #自增1
decr key #自减1
incrby key k #自增k
decrby key k #自减k
set key value #不管key是否存在,都设置
setnx key value #key不存在,才设置
set key value xx #key存在,才设置
getset key newvalue #set key newvalue并返回旧的value
append key value #将value追加到旧的value
strlen key #返回字符串的长度
incrbyfloat key 3.5 #增加key对应的值3.5
getrange key start end #获取字符串指定下标的所有值
setrange key index value #设置指定下标所对应的值
get key 获取key
set key 设置key
del key 删除key
以上命令时间复杂度都为o(1)
mget key1 key2 key3 时间复杂度o(n) 原子操作节约网络开销时间 pipline 不是原子操作
mset key1 value1 key2 value2 时间复杂度o(n)
15:hash 操作
以h开头:
hget key field 获取key中field
hset key field 设置key field
hdel key field 删除key field
hexist key field 判断是否存在field
hlen key 获取所有field 数量
HSETNX key field value
只有在字段 field 不存在时,设置哈希表字段的值。
HINCRBY key field increment
为哈希表 key 中的指定字段的整数值加上增量 increment 。
6 HINCRBYFLOAT key field increment
为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
以上命令时间复杂度都为o(1)
hmget key field1 field2 时间复杂度o(n) 原子操作节约网络开销时间 pipline 不是原子操作
hmset key field1 value1 field2 value2 时间复杂度o(n)
hgetall key 返回hash中所有的filed和value时间复杂度o(n)
hvals key 返回所有hash中的value时间复杂度o(n)
hkeys key 返回所有hash中的key时间复杂度o(n)
不能设置field的过期时间
17:jredis 使用
18:直连
19:连接池
20:对比
21:代码
public JedisPool JedisPoolFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
return jp;
}
/**
* 获取当个对象
* */
publicT get(KeyPrefix prefix, String key, Class clazz) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//生成真正的key
String realKey = prefix.getPrefix() + key;
String str = jedis.get(realKey);
T t = stringToBean(str, clazz);
return t;
}finally {
returnToPool(jedis);
}
}
private void returnToPool(Jedis jedis) {
if(jedis != null) {
jedis.close();
}
}
22:持久化方式
快照RDM方案
触发方式有三种
save命令(会阻塞redis),会首先生成一个临时文件当生成以后替换老的文件 时间复杂度o(n)
bgsave命令
配置自动触发(通过bgsave实现)
日志AOF方案
23:
24:redis 配置
redis配置文件中可以设置/opt/moudels/redis/config
save 900 1 #900s内改变1次就生成RDB 实际生产环境去掉自动触发rdm机制
save 300 10
save 60 10000
dbfilename dump.rdb #设置rdb的名称
dir ./ #rdb文件的位置
stop-writes-on-bgsave-error yes 默认配置 stop-writes-on-bgsave-error yes当bgsave出错时数据将不能修改
rdbcompression yes
rdbchecksum yes
25
26:触发rdb机制---不容忽略方式
1.全量复制 主从复制
2.debug reload debug机制
3.shutdown
27:
修改redis.conf中daemonize为yes,确保守护进程开启,也就是在后台可以运行.
# 默认情况下 redis 不是作为守护进程运行的,如果你想让它在后台运行,你就把它改成 yes。
# 当redis作为守护进程运行的时候,它会写一个 pid 到 /var/run/redis.pid 文件里面。
daemonize no
# 当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/run/redis.pid 文件里面,
# 但是你可以在这里自己制定它的文件位置。
pidfile /var/run/redis.pid
# 指定日志文件的位置
logfile ""
28:RDB方式缺点: 耗时耗性能,容易丢失数据,时间复杂度o(n) fork消耗内存,io磁盘性能
AOF:就是把执行的redis命令写到AOF文件中,然后恢复的时候直接在redis中执行AOF中的命令
AOF三种策略:always everysec no
29:
AOF重写是把原有的AOF文件进行重构合并命令是文件更小
作用:减少磁盘占用量
加速恢复速度
AOF重写实现两种方式
bgrwriteof命令
AOF重写配置
30:RDB和AOF的决择
31:AOF重写流程
32:Redis开发运维常见问题
fork操作
1.同步操作
2.与内存量息息相关:内存越大,耗时越长(与机器类型有关)
3.info:latest_fork_usec
- 进程外开销
33:redis的no-appendfsync-on-rewrite参数
同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。
因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no。
34:AOF追加阻塞
配置appenedfsync everysec后
当执行set命令的时候,先进入1步骤,然后检查后台是否有同步线程,如果没有则,主线程继续执行。如果有同步线程,那么判断上次同步时间和现在时间,如果大于2秒,表示上个同步线程还没有执行完,而且时间已经大于2秒,这个时侯主线程就阻塞,一直等待同步线程的完成。如果小于2秒,运行主线程继续执行,如果不发生阻塞的话就实现2s同步一次。
所以虽然设置了everysec,可能丢失2秒数据。
查看阻塞情况
其中aof_delayed_fsync 就是阻塞次数
35:主从复制的配置 两种实现方式
slaveof命令 slaveof 127.0.0.1 6379 无需重启
如果想断掉的话使用命令 slaveof no one 断掉主从不会删掉数据,但是再找新的主时候会被清空
配置文件配置
slaveof 192.168.0.100 6379 (映射到主服务器上) 需要重新启动
Slave-read-only yes
可以通过 info replication来查看当前的角色 info server来查看runid 每次重启都会生成新的runid 都会进行一次全量复制
36:全量复制和部分复制
全量复制流程
如果从服务器以前没有复制过任何主服务器,或者之前执行过SLAVEOF no one命令,那么从服务器在开始一次新的复制时将向主服务器发送PSYNC ? -1命令,主动请求主服务器进行完整重同步(因为这时不可能执行部分重同步);
相反地,如果从服务器已经复制过某个主服务器,那么从服务器在开始一次新的复制时将向主服务器发送PSYNC命令:其中runid是上一次复制的主服务器的运行ID,而offset则是从服务器当前的复制偏移量,接收到这个命令的主服务器会通过这两个参数来判断应该对从服务器执行哪种同步操作,如何判断已经在介绍runid时进行详细说明。
根据情况,接收到PSYNC命令的主服务器会向从服务器返回以下三种回复的其中一种:
如果主服务器返回+FULLRESYNC回复(runid变化或者offset不在缓冲区队列范围之内),那么表示主服务器将与从服务器执行完整重同步操作:其中runid是这个主服务器的运行ID,从服务器会将这个ID保存起来,在下一次发送PSYNC命令时使用;而offset则是主服务器当前的复制偏移量,从服务器会将这个值作为自己的初始化偏移量;
如果主服务器返回+CONTINUE回复(runid没有变化且offset在缓冲区队列范围之内),那么表示主服务器将与从服务器执行部分同步操作,从服务器只要等着主服务器将自己缺少的那部分数据发送过来就可以了;
如果主服务器返回-ERR回复,那么表示主服务器的版本低于Redis 2.8,它识别不了PSYNC命令,从服务器将向主服务器发送SYNC命令,并与主服务器执行完整同步操作。
由此可见psync也有不足之处,当从库重启以后runid发生变化,也就意味者从库还是会进行全量复制,而在实际的生产中进行从库的维护很多时候会进行重启,而正是有由于全量同步需要主库执行快照,以及数据传输会带不小的影响。因此在4.0版本,psync命令做了改进,以下说明。
全量复制开销~
- bgsave时间
- rdb文件传输时间
- 从节点清空时间
- 从节点加载rdb
- 可能的AOF重写,加载rdb完成后,如果开启了aof重写,需要重写aof
36:run_id 和复制偏移量和复制积压缓冲区
run_id 是redis每次启动时生成的随机的ID,用于标识该节点,重启会生成新的run_id,可以在redis-cli中执行 info命令查看
偏移量 用于主从同步、从节点上报从节点偏移量、master_repl_offset
主库和从库分别各自维护一个复制偏移量(可以使用info replication查看)用于标识自己复制的情况,在主库中代表主节点向从节点传递的字节数,在从库中代表从库同步的字节数。每当主库向从节点发送N个字节数据时,主节点的offset增加N,从库每收到主节点传来的N个字节数据时,从库的offset增加N。因此offset总是不断增大,这也是判断主从数据是否同步的标志,若主从的offset相同则表示数据同步量,不通则表示数据不同步
replication backlog buffer(复制积压缓冲区):复制积压缓冲区是一个固定长度的FIFO队列,大小由配置参数repl-backlog-size指定,默认大小1MB。需要注意的是该缓冲区由master维护并且有且只有一个,所有slave共享此缓冲区,其作用在于备份最近主库发送给从库的数据。在主从命令传播阶段,主节点除了将写命令发送给从节点外,还会发送一份到复制积压缓冲区,作为写命令的备份。除了存储最近的写命令,复制积压缓冲区中还存储了每个字节相应的复制偏移量(如下图),由于复制积压缓冲区固定大小先进先出的队列,所以它总是保存的是最近redis执行的命令。
37:部分复制是2.8以后出现的
部分复制
- 如果网络发生抖动,2.8之前会重新生产rdb文件,然后重新执行
- 之后,提供部分复制功能、如果抖动,master会在复制缓冲区生成一个buffer(默认1M),如果offset在buffer范围内,则会将部分数据复制到slave,而不需要全量复制
38:
2.主从配置不一致
例如maxmemory不一致:丢失数据
例如数据结构优化参数(hash-max-ziplist-entries):内存不一致
3.规避全量复制
3.1 第一次全量复制,不可避免 小主节点 、低峰
3.2 节点运行ID不匹配 主节点重启(运行ID变化)
故障转移,例如哨兵或集群(sentinals和Redis Cluster)
3.3 复制积压缓冲区不足
网络中断,部分复制无法满足
增大复制缓冲区配置rel_backlog_size 默认1m,网络“增强”。#10m
4.规避复制风暴
4.1 单主节点复制风暴
问题:主节点重启,多从节点复制
解决:更换复制拓扑
4.2 单机器复制风暴
主节点分散多机器
- 单机器复制风暴(redis<4.0当master宕机重启,会导致该机器下所有slave同时产生复制。避免单机部署一套redis主从)====》主节点分散多台机
1.读写分离 #读流量分摊到从节点,MySQL也是读写分离
可能遇到的问题:
复制数据延迟
读到过期数据
从节点故障
39:redis sentinel
故障转移
配置多套监控
40:安装配置流程
sentinal的默认端口26379,形成如下的安装配置(其实就是单机多实例)
sentinel节点主要配置
info replicaton
会显示主从相关配置信息
ps- ef | grep redis-server |grep 700
redis sentinel redis-sentinel.conf
sentinel 不能存储数据
客户端实现基本原理-1
客户端实现基本原理-2
客户端实现基本原理-3
客户端实现基本原理-4 验证
客户端实现基本原理-4 通知(发布订阅))
public static void main(String[] args) {
SetIPS = new HashSet ();
IPS.add("192.168.136.158:26379");
JedisSentinelPool pool = new JedisSentinelPool("mymaster", IPS);
Jedis jedis=null;
try{
jedis = pool.getResource();
jedis.set("foo", "bar");
System.out.println(jedis.get("foo"));
} catch(Exception e){
e.printStackTrace();
// logger.error(e.getMessage(),e);
} finally {
if(jedis != null)
jedis.close();
}
42:.Redis Sentinel实现原理
5.1 Redis Sentinel内部的三个定时任务
Redis Sentinel内部有三个定时任务来对redid节点进行故障判断和转移
- 1.每10秒每个sentinel对master和slave执行
info
命令,以发现slave节点和确认主从关系
sentinel在master节点执行info replication
命令,从命令执行结果中解析出slave节点
- 2.每2秒每个sentinel通过master节点的channel交换信息(发布订阅)
master节点上有一个发布订阅的channel频道:__sentinel__:hello
,用于所有sentinel之间进行信息交换
一个sentinel发布消息,消息包含当前sentinel节点的信息,对其他sentinel节点的判断以及当前sentinel对master节点和slave节点的一些判断
其他sentinel都可以接收到这条消息
新加入sentinel节点时,sentinel节点之间可以相互感知,以达到信息交互的功能
- 3.每1秒每个sentinel对其他sentinel节点和Redis节点执行ping操作
每个sentinel都可以知道其他sentinel节点,当监控的master发生故障时,方便进行判断和新master的挑选,这个定时任务是master进行故障判定的依据
5.2 主观下线和客观下线
主观下线:每个sentinel节点对Redis节点失败的'偏见'
在redis-sentinel配置文件中,有下面这种配置
sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel down-after-milliseconds <master-name> <timeout>
一个sentinel集合可以同时监控多个master,slave的节点
sentinel对多个master,slave节点进行区分的标识就是master-name,ip和port是master节点的IP地址和端口,quorum是master客观下线之后sentinel进行判断的节点数
sentinel对master进行主观下线判断的时间,单们为毫秒
每个sentinel每秒对master和slave执行ping操作,当sentinel对master或slave在timeout定义的毫秒时间内没有回复,则sentinel会认为这个节点已经被主观下线了
在前面的例子中对sentinel的配置是
sentinel monitor mymaster 192.168.81.100 6379 2 sentinel down-after-milliseconds mymaster 30000
解释:
sentinel集合监控名为mymaster的master,slave节点
被监控的master节点的IP地址是192.168.81.100,端口为6379,
sentinel会在`__sentinel__:hello`频道中交流对master节点的看法,如果sentinel节点都对master节点ping失败'达成共识',sentinel个数超过quorum的个数,sentinel集合则会认为master节点客观下线 当两个sentinel对master节点执行ping操作,在30000毫秒(30秒)时间内没有得到回复,则认为节点已经被主观下线
quorum建议设置为:(sentinel节点数 / 2) + 1,可以根据应用场景进行设定
43: sentinel领导者选举
要点:
只需要一个sentinel节点就可以完成故障转移
通过`sentinel is-master-down-by-addr`命令来完成sentinel交换对master节点的失败判定和新master的选举
完成sentinel领导者选举步骤:
1.每个做主观下线的sentinel节点向其他sentinel节点发送命令,要求将自己设置为领导者
2.收到命令的sentinel节点如果没有同意同意其他sentinel节点发送的命令,那么将同意该请求,否则拒绝
3.如果该sentinel节点发现自己的票数已经超过sentinel集合半数且超过quorum,将成为领导者
4.如果此过程中有多个sentinel节点成为领导者,那么将等待一段时间重新进行选举
5.4 故障转移(由sentinel领导者节点完成)
故障转移步骤:
1.从slave节点中选出一个合适的节点作为新的master节点
2.对选出的slave节点执行`slaveof no one`命令,使成为新的master节点
3.向剩余的slave节点发送命令,让slave节点成为新master节点的slave节点,然后从新master节点同步数据
数据同步规则和parallel-syncs参数有关
如一个一主三从架构中,master故障,sentinel领导者从3个slave中选出一个作为新的master节点,剩余的两个slave节点会成为新master节点的slave,从新master节点同步同步数据 master节点只需要生成一次RDB文件 如果parallel-syncs参数设置为1,则剩余两个slave节点会按顺序从新master节点拷贝数据,一个slave切点拷贝完成,另外一个slave才会从新master节点拷贝数据 如果parallel-syncs参数设置为2,则两个slave节点会同时从master节点进行数据拷贝,这无疑会加入新master的开销 4.sentinel领导者会把原来的master节点设置为slave节点,并保持对其'关注',当原来的master节点恢复后,sentinel会使其去复制新master节点的数据
5.5 slave节点的选择
slave节点选择规则
1.选择slave-priority(slave节点优先级)最高的slave节点,如果存在则返回,不存在则继续
2.选择复制偏移量(offset)最大的slave节点,offset最大说明对master的数据复制的最完整,如果存在则返回,不存在则继续
3.选择run_id最小的slave节点,run_id最小说明slave节点启动最早
6.总结:
Redis Sentinel是Redis的高可用实现方案:故障发现,故障自动转移,配置中心,客户端通知
Redis Sentinel是Redis 2.8版本开始才正式生产可用,之前版本不可用于生产 尽可以在不同物理机上部署Redis Sentinel所有节点,但是最好一个局域网内 Redis Sentinel中sentinel节点个数应该大于等于3,且最好为奇数,可以保证判断的公平 Redis Sentinel中的数据节点与普通数据节点没有区别 客户端初始化时连接的是Sentinel节点集合,不是具体的Redis节点,但是Sentinel只是配置中心不是代理 Redis Sentinel通过三个定时任务实现了Sentinel节点对于master,slave,其余sentinel节点的监控 Redis Sentinel在对节点做失败判定时分为主观下线和客观下线 看懂Redis Sentinel故障转移日志对于Redis Sentinel以及问题排查非常有帮助 Redis Sentinel实现读写分离高可用可以依赖Redis Sentinel节点的消息通知,获取Redis数据节点的状态变化
顺序分区和哈希分区
修改:顺序分布其实不支持批量操作
哈希分布
- 节点取余分区 --------建议多倍扩容比较好,数据迁移量少
扩容可能会迁移80%的数据 ,多倍扩容可能只迁移50%的数据
- 一致性哈希分区 --------token环,只影响邻近节点,对其他节点影响小(节点多时候建议),保证最小数据迁移和数据负载均衡
-
一致性哈希算法
假如有一个环平均分为4分,分割点就是图中的node1、node2、node3、node4。
如果有一个key通过hash计算落在了node3余node4之间,则按照顺时针的规则,将这个数据归node3管理。
下面来看两种假设情况:
【1】现在增加一个node5节点,只会影响node4和node1之间的数据。就是原来在node4与node5之间的数据,之前是归node1节点,现在归node5节点,会产生少量的数据迁移问题。新增节点或者删除节点不会影响全部的节点。node2、node3和node4管理的数据要比node5、node1多,达不到负载均衡的效果,会产生数据倾斜。
【2】node3不幸宕机,node1和node2节点不会受影响。只是原来归属node3的key现在需要由node4负责。如果一个节点不可用,则受影响的数据仅仅是此节点到其环空间中前一节点。假如node2也发生了宕机,则node3还要承受原本属于node的key,久而久之就会产生雪崩现象。针对上述问题的解决方案——虚拟节点机制
通常情况下,一个台机器只负责一个节点,引入虚拟节点机制后,每台机器可以负责更多节点(下面以2个节点为例:node1A和node1B)。
如果存放node1A和node1B点机器挂掉了,数据的迁移如下:
我们可以看到,数据迁移到了两个节点上,相对于没有加入虚拟节点,数据负担更加均匀。当虚拟节点越多时,数据负担就会越均匀!
- 虚拟槽分区 --------前两者是客户端分片,后者是redis-cluster,服务端管理节点、槽、数据
- 45:
- 缓存更新策略
1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy
2.超时剔除:例如expire
3.主动更新:开发控制生命周期
- 45:
-
缓存穿透优化----大量请求不命中
-
解决方法:
1.缓存空对象
2.布隆过滤器拦截
1)无底洞问题介绍:
- 无底洞问题的发现:
2010年,FaceBook有3000个memcache节点,发现加机器后性能没有提升,反而下降了。机器越多,性能下降越多。 - 产生该问题原因:批量操作的变化
一次mget的操作随着机器的增加,网络时间也会增加。
当然这只对节点非常多的情况下有很大影响。 - 问题的关键点:
更多的机器!=更多的性能
批量接口需求(mget.mset等)
数据增长与水平扩展需求
2)无敌洞问题优化(优化I/O):
-
- 命令本身的优化:减少使用慢查询及hgetall bigkey等这种命令
- 优化网络时间:减少网络通信时间(Redis这种命令执行很快的主要优化这个)
具体一点可以查看前面的集群中的批量操作。
(在Mysql这种命令执行较慢的数据库中一般会去选择优化SQL语句本身) - 降低客户端连接成本:长连接,连接池,NIO(非阻塞IO)等。
-
5.热点key的重建优化
1)问题简介:
- 问题出现:
在重建时有大量的数据访问缓存,大量的线程都进行查询数据与缓存重建,对数据库数据源有很大的压力,会减缓IO的时间。 - 三个目标:
- 减少重建缓存的次数
- 数据尽可能一致
- 减少潜在的危险
2)两个解决方案:
- 问题出现: