频道的订阅类似于微信公众的订阅,一旦频道发布消息,关注的用户会接收到这些信息
连接1 设置名字coffeemao
,查看连接名列表,查看连接名字,处于哪一个数据库中,连接分配的主机等信息。
连接名字设置成功会返回ok
127.0.0.1:6379> client setname coffeemao
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> client list
id=6 addr=127.0.0.1:5247 fd=10 name=coffeemao age=1146 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=18446744073709537584 events=r cmd=client
127.0.0.1:6379> client getname
"coffeemao"
127.0.0.1:6379>
下面是各字段的含义::
id: 唯一的64位的客户端ID(Redis 2.8.12加入)。
addr: 客户端的地址和端口
fd: 套接字所使用的文件描述符
age: 以秒计算的已连接时长
idle: 以秒计算的空闲时长
flags: 客户端 flag
db: 该客户端正在使用的数据库 ID
sub: 已订阅频道的数量
psub: 已订阅模式的数量
multi: 在事务中被执行的命令数量
qbuf: 查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
qbuf-free: 查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
obl: 输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
oll: 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
omem: 输出缓冲区和输出列表占用的内存总量
events: 文件描述符事件
cmd: 最近一次执行的命令
127.0.0.1:6379> client setname hello
OK
127.0.0.1:6379> client list
id=6 addr=127.0.0.1:5247 fd=10 name=coffeemao age=1191 idle=45 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=18446744073709537584 events=r cmd=client
id=8 addr=127.0.0.1:6474 fd=12 name=hello age=22 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=18446744073709537584 events=r cmd=client
127.0.0.1:6379> client getname
"hello"
127.0.0.1:6379>
新创建的连接默认是没有名字的。
127.0.0.1:6379> client getname
(nil)
127.0.0.1:6379> client list
id=9 addr=127.0.0.1:11739 fd=9 name= age=18 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=18446744073709537584 events=r cmd=client
127.0.0.1:6379>
提示:在 Redis 应用程序发生连接泄漏时,为连接设置名字是一种很好的 debug 手段
window
版本的Redis3.2
的配置文件,
################################## INCLUDES ###################################
# include .\path\to\local.conf
# include c:\path\to\other.conf
################################## NETWORK #####################################
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
bind 127.0.0.1
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
################################# GENERAL #####################################
loglevel notice
logfile ""
databases 16
################################ SNAPSHOTTING ################################
# Save the DB on disk:
save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum yes
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
dir ./
################################# REPLICATION #################################
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
################################## SECURITY ###################################
# Require clients to issue AUTH before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
################################### LIMITS ####################################
# maxclients 10000
# maxmemory
# The default of 5 produces good enough results. 10 Approximates very closely
# true LRU but costs a bit more CPU. 3 is very fast but not very accurate.
#
# maxmemory-samples 5
############################## APPEND ONLY MODE ###############################
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
################################ LUA SCRIPTING ###############################
lua-time-limit 5000
################################ REDIS CLUSTER ###############################
# cluster-enabled yes
# cluster-require-full-coverage yes
################################## SLOW LOG ###################################
slowlog-log-slower-than 10000
slowlog-max-len 128
################################ LATENCY MONITOR ##############################
latency-monitor-threshold 0
############################# EVENT NOTIFICATION ##############################
notify-keyspace-events ""
############################### ADVANCED CONFIG ###############################
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
################################## INCLUDES ###################################
# include /path/to/local.conf
# include /path/to/other.conf
主从复制,是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器
master被称为主节点,slave被称为从节点,数据的复制是单向的,只能由主节点到从节点。
Master 以写为主,Slave 以读为主。
一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
默认情况下,每台 Redis 服务器都是主节点。
作用
数据冗余,主从复制实现数据的热备份,是持久化之外的一种数据冗余实现方式
数据恢复,主节点崩掉,从节点立刻顶上去,防止服务崩溃
负载均衡,读写分离,主机写,从机读,分担主节点的负载,提高redis服务器的并发量
查看主从复制信息info replication
Pessimistic Lock
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。这样别人想拿到这个数据就会 堵塞 直到它拿到锁。
传统的关系型数据库使用的这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。
Optimistic Lock 每次去拿数据的时候都认为别人不会修改,所以不会上锁。
但是在更新的时候会判断一下再此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。
乐观锁策略:提交版本必须大于记录当前版本才能执行更新。
单位都是 bytes
https://redis.io/docs/manual/scaling/
由于电脑带不起redis的集群,所以采取docker搭建redis的集群
首先创建网卡
docker network create redis --subnet 172.38.0.0/16
redis-node.sh这个文件位置任意
根目录下创建集群节点的数据
# 创建文件
vim redis-node.sh
# 内容
#!/bin/sh
for port in $(seq 1 6);
do
mkdir -p /mydata/redis/node-${port}/conf
mkdir -p /mydata/redis/node-${port}/data
touch /mydata/redis/node-${port}/conf/redis.conf
cat <<EOF>> /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 添加执行权限
chmod 777 redis-node.sh
#执行脚本文件
./redis-node.sh
编写脚本redis-run.sh批量开启redis的节点
vim redis-run.sh
#!/bin/bash
for port in $(seq 1 6);
do
docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${port} redis redis-server /etc/redis/redis.conf
done
# 添加执行权限
chmod 777 redis-run.sh
#执行脚本文件
./redis-run.sh
集群搭建完毕,查看和进入redis的集群中进行测试,发现集群具有高可用的性能
# 查看开启的容器服务
docker ps
# 进入redis-1节点容器
docker exec -it redis-1 /bin/sh
# 查看一下文件
ls
# 集群分配主节点和从节点
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
# 查看搭建好的集群信息
cluster info
# 查看集群节点的信息
cluster nodes
# 存放值,可见将a存放在了 3节点中
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
# 在开启一个会话,将redis-3停了
docker stop redis-3
# redis-3已经崩了,取不到值,且连接不到,重新连接一下集群,再次获取 a,发现a存储在redis-4中,此时主节点是1,2,3,4,不过172.38.0.13:6379@16379 master,fail
172.38.0.13:6379> get a
Could not connect to Redis at 172.38.0.13:6379: No route to host
(16.91s)
not connected> redis-cli -c
(error) ERR unknown command `redis-cli`, with args beginning with: `-c`,
172.38.0.13:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
# 高可用已经满足,查看节点信息,在开启redis-3服务,发现redis-4变为主节点了,它的从节点变为redis-3
172.38.0.14:6379> cluster nodes
6833635ea5931eac8038167eb4c91ed834fe8051 172.38.0.16:6379@16379 slave f26a16c880e89ccc95b39bccb802746a1f0e4810 0 1665018276000 2 connected
c7701e07f2da209e66fc331edd3e19500041d32f 172.38.0.15:6379@16379 slave 11aa05b5435a39b2160200c1fb8674fd96d9b3bf 0 1665018277000 1 connected
f26a16c880e89ccc95b39bccb802746a1f0e4810 172.38.0.12:6379@16379 master - 0 1665018277764 2 connected 5461-10922
cbec022e01523937ab3f5fb21b4e90cb70e36844 172.38.0.14:6379@16379 myself,master - 0 1665018276000 7 connected 10923-16383
11aa05b5435a39b2160200c1fb8674fd96d9b3bf 172.38.0.11:6379@16379 master - 0 1665018277000 1 connected 0-5460
e81450c6d2cb620d377dc51bbcc12ce2c765f014 172.38.0.13:6379@16379 slave cbec022e01523937ab3f5fb21b4e90cb70e36844 0 1665018277250 7 connected
# 退出集群
exit
shutdown
Redis 是内存型数据库,如果不将内存中的数据同步保存到磁盘上的话,一旦服务器进程退出,那么服务器中的数据就会丢失。
指定时间间隔将内存中的数据存入磁盘中,可以理解成为快照,恢复的操作就是将快照文件直接读取到内存中。
Redis会单独的创建 fork 一个子进程来进行持久化。会现将数据写入到一个临时文件中,待持久化过程结束了,再使用这个临时文件代替上次持久化好的文件。
整个过程中,主进程不会进行IO,保证了极大的性能。如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是很敏感【具有一定的容错性】,RDB比AOF更加的高效。
RDB的缺点就是最后一次的持久化后的数据可能丢失。
复制
fork的作用就是复制一个与当前进程一样的进程,新的进程的所有数据(变量,环境变量,程序计数器)的数值都和原进程一致。这是一个新的进程作为原进程的子进程。
RDB保存的是dump.rdb的二进制文件
save
save 3600 1
save 300 100
save 60 10000
默认
1 分钟内改了 1 万次
5 分钟内改了 10 次
15 分钟内改了 1 次
如果想禁用 RDB 持久化的策略,只要不设置任何 save 指令,或者给 save 传入一个空字符串参数也可以。
手动使用 save 命令,立马生效 。
stop-writes-on-bgsave-error
如果配置为 no,表示你不在乎数据不一致或者有其他的手段发现和控制,默认为 yes。
rbdcompression
对于存储到磁盘中的快照,可以设置是否进行压缩存储。
如果是的话,redis 会采用 LZF 算法进行压缩,如果你不想消耗 CPU 来进行压缩的话,可以设置为关闭此功能。
rdbchecksum
在存储快照后,还可以让 redis 使用 CRC64 算法来进行数据校验。
但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
默认为 yes
以日志的形式记录每一个写的操作。
只允许尾追加文件,但是不可以改写文件
AOF保存的是appendonly.aof文件。
哨兵是一个独立的进程,它会独立运行。其原理是哨兵通过发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例。
哨兵的作用
通过发送命令,让Redis的服务器返回监控其运行的状态,包括主机和从机
当哨兵检测到其他的master宕机,会自动的将slave切换到master,通过发布订阅模式通知其他的从机,修改配置文件,让他们切换主机。
多哨兵的模式,假设主机宕机,哨兵1先检测到这个信息,系统并不会马上进行故障的转移,仅仅是哨兵1 主观的认为主机不可用,称之为主观下线
后面的哨兵检测到这个主机不可用,当到达一定的数量的时候,哨兵之间会进行一次投票,投票的结果有一个哨兵发起为即可,进行故障转移的操作。
切换成功之后,通过发布订阅的模式,让各个哨兵自己的监控实现切换主机,客观下线
使用
配置文件的建立
redis目录下新建myconfig的目录并且创建sentinel.conf
文件
配置内容如下,末尾的 2 是选票到达 2 选举成功
sentinel monitor myredis 127.0.0.1 6379 2
优点
Redis缓存的使用,极大的提高了应用程序运行的性能和效率,特别是数据查询的方面。
但是存在问题即是数据一致性的问题,对于数据一致性要求高的就不能使用缓存。另外缓存存在着一系列的问题比如韩缓存穿透,缓存雪崩,缓存击穿
日常正确的使用缓存的逻辑:
查询一个数据,先到缓存中查询。
如果缓存中存在,则返回。
如果缓存中不存在,则到数据库查询。
如果数据库中存在,则返回数据,且存到缓存。
如果数据库中不存在,则返回空值。
但是缓存穿透就是数据库和缓存中都没有
这样缓存就不能拦截,数据库中查不到,就不能存到缓存中。这样每次这样的查询都会直接查询到数据库,就是穿透,这样数据库的承受压力很大。
解决方案就是:布隆过滤器,缓存空对象
布隆过滤器是一种数据结构,对所有可能查询到的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。
缓存空对象
就是当存储层无法命中后,返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,避免了从后端数据的获取
这种方法存在的问题
如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键。
即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
是指一个key非常的热点,在不断的抗住大的并发,大并发集中对一个点进行访问,在这个key失效的瞬间,持续的大并发机会穿破缓存,直接请求数据库,就相当在屏障上开了一个口子。
当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般都是热点数据。由于缓存过期,会同时访问数据库查询最新的数据,并且写入到缓存中,瞬间使数据库的压力过大。
解决方案是设置热点数据永不过时,加互斥锁
从缓存来看,没有设置过期时间,所以不会出现热点key过期后产生的问题
分布式锁:使用分布式锁,保证对于每个 key 同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只能等待。这种方式将高并发的压力转移到了分布式锁
在某一时间段内,缓存集中过期失效,大量的查询请求全部对数据库进行操作,产生周期性的压力波峰。缓存服务节点的宕机,对数据库服务器的压力不可预知,有可能瞬间将数据库压垮
解决方案:搭建集群,限流降级,数据预热,
搭建集群,实现redis的高可用,搭建集群
限流降级,缓存失效之后,通过加锁或者队列来控制数据库写入缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待
数据预热,在所有数据正式部署之前,先把可能的数据预先访问一边,这样部分可能大量的数据就会加载到缓存中。在即将大量访问前手动加载缓存不同的key,设置不同的过期时间,让缓存失效时间点尽量均匀。