由浅入深了解Redis

Redis


1.1概述

redis是什么?

官网概述

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库缓存消息中间件。 它支持多种类型的数据结构,如 字符串(strings),散列(hashes),列表(lists), 集合(sets), 有序集合(sorted sets)与范围查询(bitmaps), 地理空间(hyperloglogs) 和 索引半径查询 (geospatial) 。Redis 内置了复制(replication), LUA脚本(Lua scripting), LRU驱动事件(LRU eviction), 事务(transactions) 和 不同级别的磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel) 和 自动分区(Cluster)提供高可用性(high availability)。

redis特性及功能

Redis (Remote Dictionary Server) 远程字典服务

开源、免费、非关系型数据库、K-V数据库、内存数据库,支持持久化、事务、订阅和备份(aof 和 rdb )、集群(支持16个库)等高可用功能。并且性能极高(可以达到100000+的QPS[每秒内查询次数]),易扩展,丰富的数据类型,所有操作都是单线程,原子性的

使用场景

  1. 热点数据的缓存
  2. 限时业务的运用 eg:秒杀、验证码
  3. 计数器相关问题 eg:浏览数目
  4. 排行榜相关问题 eg:微博热搜
  5. 分布式锁 #有待了解
  6. 延时操作 eg:发布订阅功能
  7. 分页、模糊搜索
  8. 点赞、好友等相互关系的存储
  9. 队列

Redis 为什么单线程还这么快?

误区

  • 高性能的服务器一定是多线程的?
  • 多线程一定比单线程效率高?

读写速度:CPU>内存>硬盘

核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作!!!),对内存系统来说,如果没有上下文切换,效率就是最高的。多次读写都是在一个CPU上面,在内存的情况下,这个是最佳方案!!!

:CPU上下文切换是指CPU从一个进程或线程切换到另一个进程或线程。

redis安装

通过docker容器安装

systemctl start docker.service #启动docker
docker pull redis  # 下载redis
mkdir /usr/local/docker #在容器外创建放置配置文件等信息文件夹
#从官网下载redis.conf文件到此目录下 http://download.redis.io/redis-stable/redis.conf
docker run -p 6379:6379 --name redis --privileged=true -v /usr/local/docker/redis.conf:/etc/redis/redis.conf -v /usr/local/docker/data:/data -d docker.io/redis redis-server /etc/redis/redis.conf
# -p 6379:6379 端口映射 主机:docker容器
# --name redis 指定该容器名称
# -v 挂载目录 规则  主机目录:docker容器目录
# conf 容器启动时会把主机的redis.conf文件自动映射到该目录下,这样修改redis.conf文件时候,就不用进入容器内部修改了。
# data 持久化文件的映射
# -d docker.io/redis 表示后台启动redis
# redis-server /etc/redis/redis.conf 以配置文件形式启动redis,加载容器内的conf文件,最终找到挂载目录 /usr/local/docker/redis.conf 
docker ps #查看运行容器
docker logs [name、id] # 查看容器日志
docker exec -it [name、id] bash
docker exec -it [name、id] /bin/bash
#在运行的容器中执行命令
redis-cli #通过内置客户端进行连接
exit #退出命令
############################################################
[root@localhost docker]# docker exec -it redis bash
root@5350a5da9f5b:/data# cd /etc/redis/
root@5350a5da9f5b:/etc/redis# ls
redis.conf
root@5350a5da9f5b:/etc/redis# vim redis.conf
bash: vim: command not found                   # 容器内部没有vim命令
root@5350a5da9f5b:/etc/redis# cd .. 
root@5350a5da9f5b:/etc# cd /data
root@5350a5da9f5b:/data# redis-cli
127.0.0.1:6379> 

1.2数据类型

五种常用数据类型:string、hash、list、set、zset(sorted set)

三种特殊数据类型:geospatial、hyperloglog、bitmaps

公用命令

官方命令手册

# 不区分大小写
set key value  :会覆盖相同的key的value值
keys * :查询所有的key
get key:得到key指定的value
del key:移除key
dump key: 序列化给定key,返回被序列化的值
exists key: 检查key是否存在
expire key seconds:为key设定过期时间
ttl key :返回key剩余时间 -1表示永不过期,-2表示已过期
persist key:移除key的过期时间,key将永不过期
keys pattern: 查询所有符号给定模式的key eg: keys *
randomkey:随机返回一个key
rename key newkey:修改key的名称
move key db:移动key到指定数据库中
type key:返回key所存储的值的类型
flushdb :清除当前库内容
flushall :清除所有库内容 

keys pattern 实例演示

127.0.0.1:6379[1]> set zzf1 v1
OK
127.0.0.1:6379[1]> set zzf2 v2
OK
127.0.0.1:6379[1]> set zzf3 v3
OK
127.0.0.1:6379[1]> keys zz* # pattern
1) "zzf2"
2) "zzf1"
3) "zzf3"

expire key second的使用场景

  • 限时的优惠活动
  • 网站数据缓存
  • 手机验证码
  • 限制网站访问频率

key的命名建议

  1. key不要太长,尽量不要超过1024字节。不仅消耗内存,也会降低查找的效率
  2. key不要太短,太短可读性会降低
  3. 在一个项目中,key最好使用统一的命名模式。例如user:123:password
  4. key区分大小写

string

string类型是二进制安全的,redis的string可以包含任何数据,如图像、序列化对象。一个键最多能存储512MB。二进制安全是指,在传输数据的时候,能保证二进制数据的信息安全,也就是不会被篡改、破译;如果被攻击,能够及时检测出来

常用命令

set key value # 设置值。命令不区分大小写,但是key区分大小写。
get key # 获取值。
keys * # 获取所有的key值。
exists key # 判断key是否存在。
append key value # 字符串拼接,追加至末尾,如果不存在,就为它设置。相当于 set key value。
strlen key # 获取key所存储的字符串的长度。
incr key # 将key中存储的数字值增一,如果key不存在,那么先给key的值初始化为0,再执行incr自增操作。
incrby key increment # 将key中所存储的值加上增量increment,如果key不存在同上。 
decr key # 将key中存储的数字值减一。如果不存在,那么先给key的值初始化为0,再执行decr自减操作。
decrby key decrement # 将key中所存储的值减去减量decrement,如果不存在同上。
getrange key start end # 获取key中字符串的子字符串,从start开始,end结束。 -1代表最后一个字符,-2 代表倒数第二个 有点python的感觉!!!
setrange key offset value # 用value参数覆写给定key所对应的字符串,从偏移量offset开始。不存在的key当空白字符串处理;当字符串长度小于offset时,原字符串与偏移量之间将用零字节(“\x00”)填充。
setex key seconds value #将值value关联到key,并将key的生存时间设为seconds秒。如果key存在,将覆写旧值。setex 是一个原子性操作,关联值和设置生存时间两个动作会在同一时间内完成。
setnx key value #将key的值设置为value,当且仅当key不存在。 set if not exist (在分布式锁中会常常用到)。
mset key value [key value ...] # 同时设置一个或多个key-value对。如果key存在,则覆写旧值。具有原子性。
mget key [key ...] #获取所有(一个或多个)给定key的值。其中有key不存在,返回nil。

getset key value # 将给定key设置为value,并返回key的旧值;如果key不存在,返回nil,并给key设置值。
##################################
getset 和 incr 组合使用 实现计数器

string应用场景

  • string通常用于保存单个字符串或JSON字符串数据。
  • 保密要求高的图片文件内容作为字符串来存储。
  • 计数器 如粉丝数 点赞数 。incr 本身就具有原子性,不会有线程安全问题。

hash

redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。每个hash可以存储2^32-1(键值对)。可以看成key和value的map容器。相比于JSON,hash占用很少的内存空间。

常用命令

hset key field value #为指定的key设定field和value
hmset key field value [field value ...] # 同时设置多个
hsetnx key field value # 当且仅当域field不存在 设置值为value;若存在,则操作无效。
hget key field #返回哈希表 key 中给定域 field 的值。
hmget key field [field ...] # 同上
hgetall key #获取hash表 key中字段和值。
hkeys key # 获取hash表 key中所有字段。
hvals key #获取hash表 key中所有值。
hlen key # 获取hash表 key中字段数目。
hdel key field [field ...] #删除一个或多个hash表 key中的字段。
hexists key field # 判断hash表 key中字段是否存在。
hincrby key field increment #hash表key中字段field 自增 increment。若 field 不存在,那么在执行命令前,域的值被初始化为 0 。

hash应用场景

  • 通常用于存储用户的对象数据。
  • hash更适合于对象的存储,string更适合字符串的存储。

list

redis list类似于Java中的LinkedList双向队列的形式。是一个字符串链表;操作头尾效率高,中间效率低。特点 如果key不存在,则创建新的列表;如果值全移除,对应的列表也就消失。

常用命令

lpush list1 value #从左边添加值
rpush list1 value #从后边添加值
lpushx list1 value # list不存在,则不操作
rpushx list1 value #同上
lrange list1 start stop # 获取 list1 [start,end]区间元素 
lrange list1 0 -1 #获取list1中值
lpop list1   #从左边移除值
rpop list1   #从右边移除值
lindex list1 index #通过下标获取list中的某一个值
llen list1 #获取list1的长度
lrem list1 count value #移除指定个数的value
ltrim list1 index1 index2 #通过下标截取长度,这个list已经改变了,截断了只剩下截取的元素
rpoplpush list1 otherlist# 移除list列表的最后一个元素,移动到新的列表otherlist中。
lset list1 index value # 更新列表对应下标的值,如果列表或下标不存在,则报错。
linsert list1 before|after pivot value # 将value值插入列表key,位于pivot值之前或之后。如果key或pivot不存在,则不执行;若key不是列表类型,则报错。
blpop key [key ...] timeout # 返回并移除列表第一个元素,如果没有元素,则会阻塞列表,等待超时或发现可弹出元素为止。
brpop key [key ...] timeout #返回并移除列表最后一个元素,如果没有元素,则会阻塞列表,等待超时或发现可弹出元素为止。

list应用场景

  • 对数据大的集合数据删减 eg:列表显式、关注列表、粉丝列表、留言评价、热点新闻等。
  • 消息队列

补充:

​ rpoplpush list1 otherlist# 移除list列表的最后一个元素,移动到新的列表otherlist中。

可以用此命令实现订单下单流程

set

redis set 类似Java中的set无序、不可重复

常用命令

sadd key value # 向集合中添加元素
scard key # 返回指定set中元素个数
smembers key # 返回指定set中所有元素
sismember key member # 判断member是否在指定set中
srandmember key [count] #随机返回指定set中一个或多个元素
spop key #随机移除并返回指定set中的一个元素
srem key member [member ...] #移除指定set中一个和多个元素
smove source destination member # 将member元素从source集合移动到destination集合
sdiff key [key ...] # 返回第一个set集合与其他集合的差集
sinter key [key ...] # 返回所有集合的交集
sunion key [key ...] #返回所有集合的并集

set应用场景

  • 共同关注、共同爱好、二度好友等
  • 唯一性,可以统计访问网站的所有独立的IP

zset

redis zset(sorted set) 有序且不可重复。每一个元素都会关联一个double类型的分数,通过分数进行从小到大的排序,分数可以重复

常用命令

zadd key score member [[score member] ...] #添加一个或多个值 ;如果member已经存在,那么就更新这个member的score值
zcard key # 获取集合元素个数
zcount key min max #获取集合在指定区间分数的元素个数 
zrange key start stop # 获取指定区间的元素,元素位置通过score从小到大排序
zrevrange key start stop # 元素位置通过score从大到小排序
zrangebyscore key min max #获取指定score区间的元素
zrank key member #获取元素排名(索引)
zscore key memeber #获取元素的分数值
zrem key member [member] #移除集合中指定元素
zremrangebyscore key min max #移除给定score区间中元素
zremrangebyrank key start stop # 移除有序集 key中,指定排名(rank)区间内的所有成员

zset应用场景

  • 存储成绩、工资
  • 带权重进行判断
  • 排行榜

geospatial

geospatial 地理位置。可以推算地理位置信息,两地之间的距离,方圆周边人数等信息。

常用命令

###
有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
###
geoadd key 纬度 经度 member [纬度 经度 名称] # 添加一个或多个地理位置信息。
geopos key member [member] # 返回所有给定位置元素的位置(经度和纬度)。
geodist key member1 member2 [unit (m、km、mi、ft)] # 返回两个给定位置之间的距离。
georadius key 纬度 经度 radius unit [withcoord、withdist、withhash] count # 以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有(选取前count个)位置元素。
withcoord: 将位置元素的经度和维度也一并返回。
withdist: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
withhash: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
georadiusbymember key member radius unit [withcoord、withdist、withhash] count # 可以找出位于指定范围内的元素,心点是由给定的member位置元素决定的
geohash key member [member ...] # 返回一个或多个位置元素的 11个字符Geohash字符串 二维经纬度转换成一维字符串

注意:由于使用的距离公式是Haversine公式,因此仅假设地球是一个球体。当应用于地球时,该公式只是一个近似值,它不是一个完美的球体。当在需要按半径和大多数其他应用程序查询的社交网站的上下文中使用时,引入的错误不是问题。但是,在最坏的情况下,错误可能高达0.5%,因此您可能需要考虑将其他系统用于关键错误的应用程序。

geo的底层使用了zset实现,可以使用zset命令操作

hyperloglog

hyperloglog 基数统计的算法(高级数据结构 )

原理

常用命令

pfadd key element [element ...] #添加元素
pfcount key  #统计元素数目
pfmerge destkey sourcekey [sourcekey...] # 多个合并到一个新的集合中

hyperloglog 优点:占用的内存是固定的,只需要12kb内存

缺点:有 0.81% 标准错误(standard error)的近似值.

使用 :统计一个网站访问的用户数目 (允许容错)

bitmaps

bitmaps 位图 数据结构,都是操作二进制来记录,就只有0和1两个状态

常用命令

setbit key offset value #给位图指定索引设置值,返回该索引位置的原始值  
getbit key offset # 获取位图指定索引的值
bitcount key [start end] #获取位图指定范围(start到end,单位为字节,如果不指定就是获取全部)位值为1的个数。

bitmaps应用场景

  • 统计用户状态人数 eg:活跃 、不活跃,登录、未登录
  • 打卡状态 、统计打卡天数

1.3解析配置文件

################################## network ##############################################
#是否在后台运行;no:不是后台运行 
daemonize yes 

#指定 redis 只接收来自于该 IP 地址的请求,如果不进行设置,那么将处理所有请求 
bind 127.0.0.1 

#是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,拒绝外部访
#问。 
protected-mode yes 

#redis的进程文件 
pidfile /var/run/redis/redis-server.pid 

#redis监听的端口号。 
port 6379 

#此参数确定了TCP连接中已完成队列(完成三次握手之后)的长度, 当然此值必须不大于Linux系统定义
#的/proc/sys/net/core/somaxconn值,默认是511,而Linux的默认参数值是128。当系统并发量大并且客户端速度
#缓慢的时候,可以将这二个参数一起参考设定。该内核参数默认值一般是128,对于负载很大的服务程序来说大大的不
#够。一般会将它修改为2048或者更大。在/etc/sysctl.conf中添加:net.core.somaxconn = 2048,然后在终端中
#执sysctl -p。 
tcp-backlog 511 

# 此参数为设置客户端空闲超过timeout,服务端会断开连接,为0则服务端不会主动断开连接,不能小于0。
timeout 0 

#tcp keepalive参数。如果设置不为0,就使用配置tcp的SO_KEEPALIVE值,使用keepalive有两个好处:检测挂掉的
#对端。降低中间设备出问题而导致网络看似连接却已经与对端端口的问题。在Linux内核中,设置了keepalive,redis
#会定时给对端发送ack。检测到对端关闭需要两倍的设置值。 
tcp-keepalive 0 

#指定了服务端日志的级别。级别包括:
#debug(很多信息,方便开发、测试)
#verbose(许多有用的信息,但是没有debug级别信息多)
#notice(适当的日志级别,适合生产环境)
#warn(只有非常重要的信息) 
loglevel notice 

#指定了记录日志的文件。空字符串的话,日志会打印到标准输出设备。后台运行的redis标准输出是/dev/null。 
logfile /var/log/redis/redis-server.log 

#是否打开记录syslog功能 
# syslog-enabled no 

#syslog的标识符。 
# syslog-ident redis 

#日志的来源、设备 
# syslog-facility local0 

#数据库的数量,默认使用的数据库是DB 0。可以通过SELECT命令选择一个db 
databases 16 


############################# snapshotting(快照) #########################################
# redis是基于内存的数据库,可以通过设置该值定期写入磁盘。 
# 注释掉“save”这一行配置项就可以让保存数据库功能失效 
# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化) 
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化) 
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
# 可以通过save命令立即保存数据
save 900 1 
save 300 10 
save 60 10000 

#当RDB持久化出现错误后,是否依然进行继续进行工作,yes:不能进行工作,no:可以继续进行工作,可以通过info中
#的rdb_last_bgsave_status了解RDB持久化是否有错误 
stop-writes-on-bgsave-error yes 

#使用压缩rdb文件,rdb文件压缩使用LZF压缩算法,yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁
#盘空间 
rdbcompression yes

#是否校验rdb文件。从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。这更有利于文件的容错性,
#但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置。 
rdbchecksum yes 

#rdb文件的名称 
dbfilename dump.rdb 

#数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录 
dir /var/data/redis



################################### 主从复制 #############################################
#复制选项,slave复制对应的master。
# replicaof <masterip> <masterport>

#如果master设置了requirepass,那么slave要连上master,需要有master的密码才行。masterauth就是用来配置
#master的密码,这样可以在连上master后进行认证。
# masterauth <master-password>

#当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:1) 如果slave-serve-stale-data设置为yes(默
#认设置),从库会继续响应客户端的请求。2) 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之
#外的任何请求都会返回一个错误”SYNC with master in progress”。
replica-slave-serve-stale-data yes

#作为从服务器,默认情况下是只读的(yes),可以修改成NO,用于写(不建议)。
replica-read-only yes

#是否使用socket方式复制数据。目前redis复制提供两种方式,disk和socket。如果新的slave连上来或者重连的
#slave无法部分同步,就会执行全量同步,master会生成rdb文件。有2种方式:disk方式是master创建一个新的进程
#把rdb文件保存到磁盘,再把磁盘上的rdb文件传递给slave。socket是master创建一个新的进程,直接把rdb文件以
#socket的方式发给slave。disk方式的时候,当一个rdb保存的过程中,多个slave都能共享这个rdb文件。socket的
#方式就的一个个slave顺序复制。在磁盘速度缓慢,网速快的情况下推荐用socket方式。
repl-diskless-sync no

#diskless复制的延迟时间,防止设置为0。一旦复制开始,节点不会再接收新slave的复制请求直到下一个rdb传输。所
#以最好等待一段时间,等更多的slave连上来。
repl-diskless-sync-delay 5

#slave根据指定的时间间隔向服务器发送ping请求。时间间隔可以通过 repl_ping_slave_period 来设置,默认10
#秒。
# repl-ping-slave-period 10

#复制连接超时时间。master和slave都有超时时间的设置。master检测到slave上次发送的时间超过repl-timeout,
#即认为slave离线,清除该slave信息。slave检测到上次和master交互的时间超过repl-timeout,则认为master离
#线。需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时。 
# repl-timeout 60

#是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no,即使用tcp nodelay。如果master设置
#了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。但是这也可能带来
#数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes
repl-disable-tcp-nodelay no
 
#复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。这样在slave离线的时候,不需要完全复制
#master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。缓冲区的大
#小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。没有slave的一段时间,内存
#会被释放出来,默认1mb
# repl-backlog-size 1mb
 
# master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。
# repl-backlog-ttl 3600
 
# 当master不可用,Sentinel会根据slave的优先级选举一个master。最低的优先级的slave,当选master。而配置
#成0,永远不会被选举
replica-priority 100
 
#redis提供了可以让master停止写入的方式,如果配置了min-replicas-to-write,健康的slave的个数小于N,
#mater就禁止写入。master最少得有多少个健康的slave存活才能执行写命令。这个配置虽然不能保证N个slave都一定
#能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。设置为0是关
#闭该功能
# min-replicas-to-write 3
# 延迟小于min-replicas-max-lag秒的slave才认为是健康的slave
# min-replicas-max-lag 10


################################### 安全特性 ##############################################
#requirepass配置可以让用户使用AUTH命令来认证密码,才能使用其他命令。这让redis可以使用在不受信任的网络
#中。为了保持向后的兼容性,可以注释该命令,因为大部分用户也不需要认证。使用requirepass的时候需要注意,因为
#redis太快了,每秒可以认证15w次密码,简单的密码很容易被攻破,所以最好使用一个更复杂的密码
# requirepass foobared
#把危险的命令给修改成其他名称。比如CONFIG命令可以重命名为一个很难被猜到的命令,这样用户不能使用,而内部工具
#还能接着使用
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#设置成一个空的值,可以禁止一个命令
# rename-command CONFIG ""

################################### 客户端 ############################################## 
# 设置能连上redis的最大客户端连接数量。默认是10000个客户端连接。由于redis不区分连接是客户端连接还是内部打
#开文件或者和slave连接等,所以maxclients最小建议设置到32。如果超过了maxclients,redis会给新的连接
#发送’max number of clients reached’,并关闭连接
# maxclients 10000
 
################################### 内存管理 ############################################
#redis配置的最大内存容量。当内存满了,需要配合maxmemory-policy策略进行处理。注意slave的输出缓冲区是不计
#算在maxmemory内的。所以为了防止主机内存使用完,建议设置的maxmemory需要更小一些
# maxmemory <bytes>
 
#内存容量超过maxmemory后的处理策略。
#volatile-lru:利用LRU算法移除设置过过期时间的key。
#volatile-random:随机移除设置过过期时间的key。
#volatile-ttl:移除即将过期的key,根据最近过期时间来删除(辅以TTL)
#allkeys-lru:利用LRU算法移除任何key。
#allkeys-random:随机移除任何key。
#noeviction:不移除任何key,只是返回一个写错误。
#上面的这些驱逐策略,如果redis没有合适的key驱逐,对于写命令,还是会返回错误。redis将不再接收写请求,只接
#收get请求。写命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert 
#lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby 
#zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec 
#sort。
# maxmemory-policy noeviction
 
# lru检测的样本数。使用lru或者ttl淘汰算法,从需要淘汰的列表中随机选择sample个key,选出闲置时间最长的key移除
# maxmemory-samples 5
 
# 是否开启salve的最大内存
# replica-ignore-maxmemory yes


################################### aof持久化 ###########################################
#Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并
#追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作默认redis使用的
#是rdb方式持久化,这种方式在许多应用中已经足够用了。但是redis如果中途宕机,会导致可能有几分钟的数据丢失,
#根据save来策略进行持久化,Append Only File是另一种持久化方式,可以提供更好的持久化特性。Redis会把每次
#写入的数据在接收后都写入 appendonly.aof 文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略
#RDB文件。若开启aof则将no改为yes
appendonly no
 
#指定本地数据库文件名,默认值为 appendonly.aof
appendfilename "appendonly.aof"
 
#aof持久化策略的配置
#no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
#always表示每次写入都执行fsync,以保证数据同步到磁盘
#everysec表示每秒执行一次fsync,可能会导致丢失这1s数据
# appendfsync always
appendfsync everysec
# appendfsync no
 
# 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成
#阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以
#设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。设置为yes表示rewrite期间对新写操作不
#fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的默认fsync策略是30秒。可能丢失
#30秒数据
no-appendfsync-on-rewrite no
 
#aof自动重写配置。当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定
#大小的时候Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的
#二倍(设置为100)时,自动启动新的日志重写过程
auto-aof-rewrite-percentage 100
 
#设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写
auto-aof-rewrite-min-size 64mb
 
#aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所在的主机操
#作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项(redis宕机或者异常终止不会造成尾部不完整现
#象。)出现这种现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的aof文件被导入的
#时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以
aof-load-truncated yes
 
#加载redis时,可以识别AOF文件以“redis”开头。
#字符串并加载带前缀的RDB文件,然后继续加载AOF尾巴
aof-use-rdb-preamble yes

############################### LUA SCRIPTING (lua脚本)################################
# 如果达到最大时间限制(毫秒),redis会记个log,然后返回error。当一个脚本超过了最大时限。只有SCRIPT 
#KILL和SHUTDOWN NOSAVE可以用。第一个可以杀没有调write命令的东西。要是已经调用了write,只能用第二个命令
#杀
lua-time-limit 5000

###############################REDIS CLUSTER redis 集群 ################################
# 集群开关,默认是不开启集群模式
# cluster-enabled yes
 
#集群配置文件的名称,每个节点都有一个集群相关的配置文件,持久化保存集群的信息。这个文件并不需要手动配置,这
#个配置文件有Redis生成并更新,每个Redis集群节点需要一个单独的配置文件,请确保与实例运行的系统中配置文件名
#称不冲突
# cluster-config-file nodes-6379.conf
 
#节点互连超时的阀值。集群节点超时毫秒数
# cluster-node-timeout 15000
 
#在进行故障转移的时候,全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间
#了,导致数据过于陈旧,这样的slave不应该被提升为master。该参数就是用来判断slave节点与master断线的时
#间是否过长。判断方法是:
#比较slave断开连接的时间和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果节点超时时间为三十秒, 并且slave-validity-factor为10,假设默认的repl-ping-slave-period是10
#秒,即如果超过310秒slave将不会尝试进行故障转移
# cluster-replica-validity-factor 10
 
# master的slave数量大于该值,slave才能迁移到其他孤立master上,如这个参数若被设为2,那么只有当一
#个主节点拥有2 个可工作的从节点时,它的一个从节点会尝试迁移
# cluster-migration-barrier 1
 
#默认情况下,集群全部的slot有节点负责,集群状态才为ok,才能提供服务。设置为no,可以在slot没有全
#部分配的时候提供服务。不建议打开该配置,这样会造成分区的时候,小分区的master一直在接受写请求,而
#造成很长时间数据不一致
# cluster-require-full-coverage yes

###############################SLOW LOG  ################################
# slow log是用来记录redis运行中执行比较慢的命令耗时。当命令的执行超过了指定时间,就记录在slow log
#中,slow log保存在内存中,所以没有IO操作。
#执行时间比slowlog-log-slower-than大的请求记录到slowlog里面,单位是微秒,所以1000000就是1秒。注
#意,负数时间会禁用慢查询日志,而0则会强制记录所有命令。
slowlog-log-slower-than 10000
 
#慢查询日志长度。当一个新的命令被写进日志的时候,最老的那个记录会被删掉。这个长度没有限制。只要有足
#够的内存就行。你可以通过 SLOWLOG RESET 来释放内存
slowlog-max-len 128

################################ LATENCY MONITOR ##############################
#延迟监控功能是用来监控redis中执行比较缓慢的一些操作,用LATENCY打印redis实例在跑命令时的耗时图表。
#只记录大于等于下边设置的值的操作。0的话,就是关闭监视。默认延迟监控功能是关闭的,如果你需要打开,也
#可以通过CONFIG SET命令动态设置
latency-monitor-threshold 0

############################# EVENT NOTIFICATION 订阅 ##############################
#键空间通知使得客户端可以通过订阅频道或模式,来接收那些以某种方式改动了 Redis 数据集的事件。因为开启键空间#通知功能需要消耗一些 CPU ,所以在默认配置下,该功能处于关闭状态。
#notify-keyspace-events 的参数可以是以下字符的任意组合,它指定了服务器该发送哪些类型的通知:
##K 键空间通知,所有通知以 __keyspace@__ 为前缀
##E 键事件通知,所有通知以 __keyevent@__ 为前缀
##g DEL 、 EXPIRE 、 RENAME 等类型无关的通用命令的通知
##$ 字符串命令的通知
##l 列表命令的通知
##s 集合命令的通知
##h 哈希命令的通知
##z 有序集合命令的通知
##x 过期事件:每当有过期键被删除时发送
##e 驱逐(evict)事件:每当有键因为 maxmemory 政策而被删除时发送
##A 参数 g$lshzxe 的别名
#输入的参数中至少要有一个 K 或者 E,否则的话,不管其余的参数是什么,都不会有任何 通知被分发。详细使用可以参考http://redis.io/topics/notifications
 
notify-keyspace-events ""

############################### ADVANCED CONFIG 高级配置 ###############################
# 数据量小于等于hash-max-ziplist-entries的用ziplist,大于hash-max-ziplist-entries用hash
hash-max-ziplist-entries 512
 
# value大小小于等于hash-max-ziplist-value的用ziplist,大于hash-max-ziplist-value用hash
hash-max-ziplist-value 64
 
#-5:最大大小:64 KB<--不建议用于正常工作负载
#-4:最大大小:32 KB<--不推荐
#-3:最大大小:16 KB<--可能不推荐
#-2:最大大小:8kb<--良好
#-1:最大大小:4kb<--良好
list-max-ziplist-size -2
 
#0:禁用所有列表压缩
#1:深度1表示“在列表中的1个节点之后才开始压缩,
#从头部或尾部
#所以:【head】->node->node->…->node->【tail】
#[头部],[尾部]将始终未压缩;内部节点将压缩。
#2:[头部]->[下一步]->节点->节点->…->节点->[上一步]->[尾部]
#2这里的意思是:不要压缩头部或头部->下一个或尾部->上一个或尾部,
#但是压缩它们之间的所有节点。
#3:[头部]->[下一步]->[下一步]->节点->节点->…->节点->[上一步]->[上一步]->[尾部]
list-compress-depth 0
 
# 数据量小于等于set-max-intset-entries用intset,大于set-max-intset-entries用set
set-max-intset-entries 512
 
#数据量小于等于zset-max-ziplist-entries用ziplist,大于zset-max-ziplist-entries用zset
zset-max-ziplist-entries 128
 
#value大小小于等于zset-max-ziplist-value用ziplist,大于zset-max-ziplist-value用zset
zset-max-ziplist-value 64
 
#value大小小于等于hll-sparse-max-bytes使用稀疏数据结构(sparse),大于hll-sparse-max-bytes使
#用稠密的数据结构(dense)。一个比16000大的value是几乎没用的,建议的value大概为3000。如果对CPU要
#求不高,对空间要求较高的,建议设置到10000左右
hll-sparse-max-bytes 3000
 
#宏观节点的最大流/项目的大小。在流数据结构是一个基数
#树节点编码在这项大的多。利用这个配置它是如何可能#大节点配置是单字节和
#最大项目数,这可能包含了在切换到新节点的时候
# appending新的流条目。如果任何以下设置来设置
# ignored极限是零,例如,操作系统,它有可能只是一集
#通过设置限制最大#纪录到最大字节0和最大输入到所需的值
stream-node-max-bytes 4096
stream-node-max-entries 100
 
#Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。当你
#的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置
#为no。如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存
activerehashing yes
 
##对客户端输出缓冲进行限制可以强迫那些不从服务器读取数据的客户端断开连接,用来强制关闭传输缓慢的客户端。
#对于normal client,第一个0表示取消hard limit,第二个0和第三个0表示取消soft limit,normal 
#client默认取消限制,因为如果没有寻问,他们是不会接收数据的
client-output-buffer-limit normal 0 0 0
 
#对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续
#60秒,那么服务器就会立即断开客户端连接
client-output-buffer-limit replica 256mb 64mb 60
 
#对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就
#会立即断开客户端连接
client-output-buffer-limit pubsub 32mb 8mb 60
 
# 这是客户端查询的缓存极限值大小
# client-query-buffer-limit 1gb
 
#在redis协议中,批量请求,即表示单个字符串,通常限制为512 MB。但是您可以更改此限制。
# proto-max-bulk-len 512mb
 
#redis执行任务的频率为1s除以hz
hz 10
 
#当启用动态赫兹时,实际配置的赫兹将用作作为基线,但实际配置的赫兹值的倍数
#在连接更多客户端后根据需要使用。这样一个闲置的实例将占用很少的CPU时间,而繁忙的实例将反应更灵敏
dynamic-hz yes
 
#在aof重写的时候,如果打开了aof-rewrite-incremental-fsync开关,系统会每32MB执行一次fsync。这
#对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
aof-rewrite-incremental-fsync yes
 
#在rdb保存的时候,如果打开了rdb-save-incremental-fsync开关,系统会每32MB执行一次fsync。这
#对于把文件写入磁盘是有帮助的,可以避免过大的延迟峰值
rdb-save-incremental-fsync yes

1.4持久化

rdb

介绍

rdb (redis dataBase)在指定的时间间隔内生成内存中整个数据集的持久化快照。快照文件默认被存储在当前文件夹中,名称为dump.rdb。可以通过dir和dbfilename参数来修改默认值。

redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到临时文件中。待持久化过程都结束了,再用这个临时文件替换上次持久化的文件。整个过程中,主进程是不进行任何的IO操作的,这保证了极高的性能

fork的作用相当于复制一个与当前进程一样的进程。但是是一个全新的进程,并作为原进程的子进程。

配置文件
# redis是基于内存的数据库,可以通过设置该值定期写入磁盘。 
# 注释掉“save”这一行配置项就可以让保存数据库功能失效 
# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化) 
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化) 
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
# 可以通过save命令立即保存数据
save 900 1 
save 300 10 
save 60 10000 

#当RDB持久化出现错误后,是否依然进行继续进行工作,yes:不能进行工作,no:可以继续进行工作,可以通过info中
#的rdb_last_bgsave_status了解RDB持久化是否有错误 
stop-writes-on-bgsave-error yes 

#使用压缩rdb文件,rdb文件压缩使用LZF压缩算法,yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁
#盘空间 
rdbcompression yes

#是否校验rdb文件。从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。这更有利于文件的容错性,
#但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置。 
rdbchecksum yes 

#rdb文件的名称 
dbfilename dump.rdb  #可以自定义文件名

#数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录 
dir /var/data/redis  #可以自定义路径
触发机制
  1. 配置文件中save的规则满足情况下,会自动触发rdb规则
  2. 手动通过命令来触发
    • save : save时只管保存,其他命令操作全部阻塞。
    • bgsave:redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次执行快照的时间。
    • flushall:会产生dump.rdb文件,但里面是空的,无意义。
    • shutdown:安全退出,也会生成dump.rdb文件。
恢复
恢复rdb文件

开发中应做好备份rdb文件,以防flushall命令清空数据。

将备份文件(dump.rdb)移到redis安装目录并启动服务即可。

恢复数据

当配置文件中 appendonly 设置为no时,默认rdb持久化。redis启动时,会加载dir 设置的目录下的dump.rdb文件来进行数据恢复。

config get dir 获取目录

优点
  • 适合大规模的数据恢复
  • 对数据的完整性和一致性要求不高
缺点
  • 需要一定的时间间隔进程操作!如果redis意外宕机了,会丢失最后一次快照后的所有修改数据。
  • fork进程的时候,内存中数据被克隆了一份,大致2倍的膨胀性需要考虑。

aof

介绍

aof (append only file)以日志的形式来记录每一个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,保存的是appendonly.aof文件。

aof机制默认关闭,可以通过appendonly = yes 开启aof机制。重启生效!!!

配置文件

aof持久化的一些策略配置

#aof持久化策略的配置 
#no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。 
#always表示每次写入都执行fsync,以保证数据同步到磁盘。 
#everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。 
appendfsync everysec

对于触发aof重写机制也可以通过配置文件来进行设置

#aof自动重写配置。当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定
#大小的时候Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的
#二倍(设置为100)时,自动启动新的日志重写过程
auto-aof-rewrite-percentage 100
 
#设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写
auto-aof-rewrite-min-size 64mb

当aop重写时会引发重写和持久化追加同时发生的问题

# 在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成
#阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以
#设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。设置为yes表示rewrite期间对新写操作不
#fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的默认fsync策略是30秒。可能丢失
#30秒数据
no-appendfsync-on-rewrite no
如何恢复
正常恢复

​ 将文件放到dir指定的文件夹下,当redis启动的时候会自动加载数据,注意:aof文件的优先级比dump大

异常恢复
  • 有些操作可以直接到appendonly.aof文件里去修改。

    eg:使用了flushall这个命令,此刻持久化文件中就会有这么一条命令记录,把它删掉就可以了

  • 写坏的文件可以通过 redis-check-aof --fix进行修复

优点
  • 根据不同的策略,可以实现每秒,每一次修改操作的同步持久化,就算在最恶劣的情况下只会丢失不会超过两秒数据。
  • 当文件太大时,会触发重写机制,确保文件不会太大。
  • 文件可以简单的读懂
缺点
  • aof文件的大小太大,就算有重写机制,但重写所造成的阻塞问题是不可避免的
  • aof文件恢复速度慢

总结

  1. 如果你只希望你的数据在服务器运行的时候存在,可以不使用任何的持久化方式

  2. 一般建议同时开启两种持久化方式。AOF进行数据的持久化,确保数据不会丢失太多,而RDB更适合用于备份数据集,留着一个做万一的手段。

  3. 性能建议:

    因为RDB文件只用做后备用途,建议只在slave上持久化RDB文件,而且只要在15分钟备份一次就够了,只保留save 900 1这条规则。

    如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价:1、带来了持续的IO;2、AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

    如果不Enable AOF,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时宕掉,会丢失10几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。

1.5redis事务

是什么?

可以一次执行多个命令,本质是一组命令的集合。一个事务中所有命令都会被序列化,按顺序的串行执行而不会被其他命令插入,不许加塞。

能干什么?

一个队列中,一次性,顺序的,排他的执行一系列命令。

常用命令

命令描述
multi标记一个事务的开始
exec执行所有事务块内的命令
discard取消事务,放弃执行事务块内的所有命令
watch key [key]监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
unwatch取消watch命令对所有 key 的监视。

怎么玩?

  1. 正常执行

    1. 放弃事务

    2. 全体连坐

    3. 冤头债主

悲观锁:当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。

乐观锁,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。

watch监控

watch指令,类似乐观锁,如果key的值已经被修改了,那么整个事务队列都不会被执行,同时返回一个nli应答以通知调用者事务执行失败。

注意:一旦执行了exec或者discard,之前加的所有监控锁都会被取消掉了。

例子:

  1. 无加塞修改

    1. 有加塞修改,当watch的key被修改,后面的那个事务全部执行失败

  2. unwatch

    1. 二处同时操作一个数据时

3阶段

开启:以multi开启事务

入队:将多个命令入队到事务中,接到这些命令不会立刻执行,而是放到等待执行的事务队列里面

执行:有exec命令触发事务

3特性

  1. 单独的隔离操作:事务中的所有命令都会序列化,按顺序的执行。事务在等待执行的时候,不会被其他客户端发送来的命令请求打断。
  2. 没有隔离级别的概念:队列中的所有命令没有提交exec之前都是不会被执行的。
  3. 不保证原子性:redis中如果一条命令执行失败,其后的命令仍然会被执行,没有回滚。

1.6redis发布订阅(一般不用)

发布订阅

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

命令

subscribe channel [channel…] #订阅一个或多个频道的信息
psubscribe pattern [pattern…] #订阅一个或多个符合规定模式的频道
publish channel message  #将信息发送到指定频道
unsubscribe [channel[channel…]] #退订频道
punsubscribe [pattern[pattern…]] #退订所有给定模式的频道

举例

127.0.0.1:6379> subscribe codelnn #订阅一个频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "codelnn"
3) (integer) 1
#等待读取推送的消息
1) "message" #消息
2) "codelnn" #频道名称
3) "hello lnn" #内容
127.0.0.1:6379> publish codelnn "hello lnn" # 发布者发布消息到频道
(integer) 1 
127.0.0.1:6379> 

应用场景:

1、构建实时的消息系统,比如普通聊天、群聊等功能。

2、博客网站订阅,当作者发布就可以推送给粉丝 。

3、微信公众号模式。

1.7redis主从复制

是什么?

主从复制:是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave 以读为主。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

能干什么?

  • 读写分离
  • 容灾恢复

怎么玩?

准备启动三个redis容器进行实验

redis.conf
需修改端口 port
pid名字
log名字
dump.rdb名字
protected-mode no

# 6379 主机
docker run -d -p 6379:6379 --name redis6379 --privileged=true -v /usr/data/redis/redis6379/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6379/data:/data docker.io/redis redis-server /etc/redis/redis.conf
#6380 从机
 docker run -d -p 6380:6380 --name redis6380 --privileged=true -v /usr/data/redis/redis6380/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6380/data:/data docker.io/redis redis-server /etc/redis/redis.conf
#6381 从机
docker run -d -p 6381:6381 --name redis6381 --privileged=true -v /usr/data/redis/redis6381/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6381/data:/data docker.io/redis redis-server /etc/redis/redis.conf

进入容器

配从不配主

从库配置

#配置从库
slaveof 主库ip 主库端口
#查看主从信息
info replication

#主机6379
172.17.0.2:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.4,port=6381,state=online,offset=84,lag=0
slave1:ip=172.17.0.3,port=6380,state=online,offset=84,lag=1
master_replid:082fca9124ab941709644f16c77111552b588440
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
#从机6380
172.17.0.4:6381> info replication
# Replication
role:slave
master_host:172.17.0.2
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:84
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:082fca9124ab941709644f16c77111552b588440
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

每次与master断开后,都需要重新连接,除非你配置进redis.conf文件。

常用的主从方式

一主二仆 :一个master两个slave

注意点

  • 第一次slave1和slave2切入点,是全量复制,之后是增量复制。
  • 主机可以写,但是从机不可以写,从机只能读。
  • 主机shutdown后从机待机状态,等主机回来后,主机新增记录从机可以顺利复制。
  • 从机复制到的数据,会被从机持久化,就算shutdown断开连接依然会有数据。
  • 重新连接或者变更master,会清除之前的数据,重新建立拷贝最新的数据。

薪火相传:上一个slave可以是下一个slave的master,slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力。

注意点

​ 同上一主二仆

反客为主

如果主机断开了连接,我们可以使用 slaveof no one 让自己变成主机!其他的节点就可以手动连接到最新的这个主节点(手动)。

哨兵模式

反客为主的自动版,能够后台监控master库是否故障,如果故障了根据投票自动将slave库转换为主库。一组sentinel能同时监控多个master。底层是一个投票算法。

使用步骤

  1. 在对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错。

  2. 配置哨兵,在sentinel.conf文件中填入内容(可以配置多个)

    #说明:最后一个数字1,表示主机挂掉后slave投票看让谁接替成为主机,得票数多则成为主机。
    sentinel monitor 被监控数据库名字(自己起名字) ip port 1
    sentinel monitor mymaster 172.17.0.2 6379 1
    
    
    port 26379
    dir "/data"
    logfile "sentinel-26379.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
    port 26380
    dir "/data"
    logfile "sentinel-26380.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
    port 26381
    dir "/data"
    logfile "sentinel-26381.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
  3. 启动哨兵

    docker run -d -p 26379:26379 --name sentinel26379 --privileged=true -v /usr/data/redis/redis6379/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6379/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    
    docker run -d -p 26380:26380 --name sentinel26380 --privileged=true -v /usr/data/redis/redis6380/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6380/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    
    docker run -d -p 26381:26381 --name sentinel26381 --privileged=true -v /usr/data/redis/redis6381/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6381/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    

    1. 日志记录

注意点

  • 当master挂掉后,会通过选票进行选出下一个master。而且只有使用了sentinel.conf启动的才能开启选票。
  • 当原来的master回来后,会变成slave。

复制原理

slave 启动成功连接到 master 后,会发送个sync同步命令,master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

增量复制:master 继续将新的所有收集到的修改命令依次传给slave,完成同步但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中看到!

1.8redis缓存穿透、击穿和雪崩

缓存处理流程

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

缓存穿透

概念

缓存穿透:key对应的数据在数据库并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据库,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方法

  • 缓存空对象:当他第一次查询时,判断缓存没有就会去数据库查找,可以在缓存中添加这个key,并且赋值为null,第二次查询时就会查询缓存,不会再查询数据库,就可以避免这个问题,如果之后确实添加了这个key的值,也会将之前的值覆盖 。缺点就是这样做的话,如果发送了很多不存在的key,会给redis造成大量的空间浪费,也是治标不治本。

  • 布隆过滤器:将所有可能存在的key哈希到一个足够大的bitmap中,一个一定不存在的key会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

缓存击穿

概念

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方法

  • 设置热点数据永不过期 :从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

  • 加互斥锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

    SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

    public String get(key) {
          String value = redis.get(key);
          if (value == null) { //代表缓存值过期
              //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
    		  if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功
                   value = db.get(key);
                          redis.set(key, value, expire_secs);
                          redis.del(key_mutex);
                  } else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
                          sleep(50);
                          get(key);  //重试
                  }
              } else {
                  return value;      
              }
     }
    

缓存雪崩

概念

缓存雪崩,是指在某一个时间段,缓存集中过期失效或者Redis 宕机!

产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都 过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决方法

  • redis高可用:这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
  • 限流降级:这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 数据预热:数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

才设置,可以利用它来实现锁的效果。

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //代表缓存值过期
          //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
		  if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功
               value = db.get(key);
                      redis.set(key, value, expire_secs);
                      redis.del(key_mutex);
              } else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
                      sleep(50);
                      get(key);  //重试
              }
          } else {
              return value;      
          }
 }

缓存雪崩

概念

缓存雪崩,是指在某一个时间段,缓存集中过期失效或者Redis 宕机!

产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都 过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决方法

  • redis高可用:这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。
  • 限流降级:这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 数据预热:数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

参考链接 docker实现redis的主从复制+读写分离+哨兵模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值