# redis 配置
```
daemonize : 默认为no,修改为yes启用守护线程
port :设定端口号,默认为6379
bind :绑定IP地址
databases :数据库数量,默认16
save <second> <changes> :指定多少时间、有多少次更新操作,就将数据同步到数据文件
#redis默认配置有三个条件,满足一个即进行持久化
save 900 1 #900s有1个更改
save 300 10 #300s有10个更改
save 60 10000 #60s有10000更改
dbfilename :指定本地数据库的文件名,默认为dump.rdb
dir :指定本地数据库的存放目录,默认为./当前文件夹
requirepass :设置密码,默认关闭
redis -cli -h host -p port -a password
```
# redis 常用命令
严禁`keys *`!!!
```
SET key value
GET key
DEL key
DUMP key:序列化给定key,返回被序列化的值
EXISTS key:检查key是否存在
EXPIRE key second:为key设定过期时间
PEXPIRE key milliseconds:为key设定过期时间,单位为毫秒
TTL key:返回key剩余时间,-2代表不存在,-1代表永久有效
PERSIST key:移除key的过期时间,key将持久保存
KEY pattern:查询所有符号给定模式的key
RANDOM key:随机返回一个key
RANAME key newkey:修改key的名称
MOVE key db:移动key至指定数据库中
TYPE key:返回key所储存的值的类型
```
# redis 内存淘汰策略
## 1、设置超时时间
```
expire key time(以秒为单位)--这是最常用的方式
setex(String key, int seconds, String value)--字符串独有的方式
```
> - 除字符串自己独有设置过期时间的方法外,其他数据类型都需要依靠expire方法来设置时间
> - 如果没有设置超时时间,那缓存永不过期
> - 如果设置了过期时间,之后又想让缓存永不过期,使用persist key
## 2、采用LRU算法动态将不用的数据删除
> 操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据
1、volatile-lru:设定超时时间的数据中,删除最不常用的数据
2、allkeys-lru:查询所有的key中最近最不常用的数据进行删除,这是最广泛使用的策略
3、noeviction:如果设置为该属性,则不会进行删除操作,如果内存溢出则报错返回
# key的命名建议
**单个key允许存入512M大小**
- key不要太长,尽量不要超过1024字节,这不仅消耗内存,而且会降低查找的效率
- key也不要太短,太短的话,可读性会降低
- 在一个项目中,key最好使用统一的命名模式,例如:`user:123:passwd`
# redis 数据类型
## String类型
string是二进制安全的。意思是redis的string可以包含任何数据
比如序列化的对象进行存储,比如一张图片进行二进制存储,比如一个简单的字符串、数值等
```
赋值:
1、SET key value
2、SETNX key value:如果key不存在,则设值 并返回1,如果key存在,则不设值 返回0。分布式锁解决方案之一
3、SETEX key seconds value:设置值并设置过期时间
4、MSET key1 value1 [key2 value2…]:插入多个key
取值:
1、GET key
2、GETRANGE key start end:用于获取指定key中字符串的子字符串。子字符串的取值范围由start、end决定
3、MGET key1 [key2 …]:获取多个key
自增/自减:
1、INCR key:Incr 命令将 key 中储存的值增1.如果 key 不存在,那么key的值会初始化为0,然后再进行Incr 操作
2、DECR key:Decr 减1,可以为负数
3、INCRBY key 增量值:Incrby 命令将 key 中储存的数字加上指定的增量值
4、DECRBY key 减值:Decrby 减少对应的值
STRLEN key:字符串长度
```
**String的应用场景**
>1、String通常用于保存单个字符串或JSON字符串数据
>
>2、因为String是二进制安全的,所以可以把保密要求高的图片文件内容作为字符串来存储
>
>3、计数器:常规Key-Value缓存应用,如微博数、粉丝数。INCR本身就具有原子性特性,所以不会有线程安全问题
## Hash类型
Redis hash是一个string类型的field和value的映射表,**hash特别适用于存储对象**。每个hash可以存储232-1键值对。可以看成KEY和VALUE的MAP容器。相比于JSON,hash占用很少的内存空间。
```
赋值:
1、HSET key FIELD value:为指定key,设定FILD/VALUE
例如:HSET user:1 FILED name zhangsan
2、HMSET key FILED value [FILED1 value1 ...]:同时赋值多个
3、HSETNX key FILED value:只有字段filed不存在时,设置哈希表字段的值
取值:
1、HGET key FIELD
2、HMGET key FILED1 [FILED2]
3、HGETALL key:返回所有的字段和值
4、HEXISTS key FILED
删除:
HDEL key FILED1 [FILED2]:删除一个或多个HASH表字段
```
**Hash的应用场景**
>Hash的应用场景,通常用来存储一个用户信息的对象数据。
>
>1、相比于存储对象的string类型的json串,json串修改单个属性需要将整个值取出来。而hash不需要。
>
>2、相比于多个key-value存储对象,hash节省了很多内存空间
>
>3、如果hash的属性值被删除完,那么hash的key也会被redis删除
## List类型
List类型是一个链表结构的集合,其主要功能有push、pop、获取元素等。可以对头部或者尾部添加和删除元素。类似JAVA中的LinkedList
```
赋值:
1、LPUSH key value1 [value2]:将一个或多个值插入到列表头部(从左侧添加)
2、RPUSH key value1 [value2]:在尾部添加一个或多个值(从右侧添加)
3、LPUSHX key value:将一个值插入到已存在的列表头部。如果列表不存在,操作无效
4、RPUSHX key value
取值:
1、LLEN key:获取列表长度
2、LINDEX key index:通过索引获取列表中的元素
3、LRANGE key start stop:获取列表指定范围内的元素
删除:
1、LPOP key:从左侧移除第一个元素
2、RPOP key:从右侧移除第一个元素
3、BLPOP key timeout:移出并获取列表的第一个元素,如果列表没有元素会阻塞列表,直到等待超时或发现可弹出元素为止
4、BRPOP key timeout:移出并获取列表的最后一个元素,同上面相同
5、LTRIM key start stop :对列表进行修改,让列表只保留指定区间的元素,不在指定区间的元素就会被删除
修改:
1、LSET key index value:通过索引设置列表元素的值
2、LINSERT key BEFORE|AFTER word value:在列表的元素前或者后插入元素, 描述:将值 value 插入列表 key 当中,位于 word 之前或者之后
高级命令:
RPOPLPUSH source destination:移除列表的最后一个元素,并将该元素添加到另一个列表并返回
例如:
RPOPLPUSH a1 a2:a1的最后一个元素移到a2的左侧
RPOPLPUSH a1 a1:循环列表,将最后元素移到左侧
BRPOPLPUSH source destination timeout
```
**List的应用场景**
>1、对数据大的集合数据删减
>
> 列表显示、关注列表、粉丝列表、留言评价...分页、热点新闻等
>
>2、任务队列
>
> list通常用来实现一个消息队列,而且可以确保先后顺序,不必像MySQL那样通过order by来排序
# redis 多数据库
redis下,数据库由一个整数索引标识,而不是一个数据库名称。默认情况下,一个客户端连接到数据库0。
```
select db:切换
move key db:移动key
flushdb:清空当前数据库
flushall:清空所有数据库
```
# redis 事务
Redis事务可以一次执行多个命令,(按顺序地串行化执行,执行过程中不允许其他命令插入执行序列中)。
1、Redis会将一个事务中的所有命令序列化,然后按顺序执行
2、执行中不会被其他命令插入,不允许加塞行为
```
1、DISCARD:取消事务,放弃执行事务块内的所有命令
2、EXEC:执行所有事务块的命令
3、MULTI:标记一个事务块的开始
4、UNWATCH:取消WATCH命令对所有key的监视
5、WATCH key [key ...]:监视一个(或多个)key,如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断
```
>1、输入MULTI命令开始,输入的命令都会依次进入命令队列中,但不会执行
>
>2、直到输入EXEC后,Redis会将之前队列中的命令依次执行
>
>![redis事务.png](https://blog.zs-fighting.cn/upload/2021/07/redis%E4%BA%8B%E5%8A%A1-954724b817984e1c903674b3ec22441b.png)
>
>3、如果某个命令报出错,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。
>
>4、如果队列中某个命令出现报告错误(语法错误),执行时整个队列都会被取消
**应用场景**
一组命令必须同时都执行,或者都不执行
我们想要保证一组命令在执行的过程中不被其他命令插入
# redis 持久化
Redis提供了两种持久化方式:RDB(默认)和AOF
## RDB
RDB是Redis默认持久化机制。RDB相当于快照,保存的是一种状态
优点:
- 快照保存数据极快、还原数据极快
- 适用于灾难备份
缺点:
- 小内存机器不适合使用,RDB机制符合要求就会照快照
**快照条件**
```
1、服务器正常关闭时 ./bin/redis-cli shutdown
2、key满足一定条件,会进行快照
save <second> <changes> :指定多少时间、有多少次更新操作,就将数据同步到数据文件
#redis默认配置有三个条件,满足一个即进行持久化
save 900 1 #900s有1个更改
save 300 10 #300s有10个更改
save 60 10000 #60s有10000更改
```
## AOF
由于快照方式是一定间隔时间做一次的,所以如果redis意外down掉的话,就会失去最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用AOF持久化方式
Append-only file:AOF比快照方式有更好的持久化性,是由于在使用AOF持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中。当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容
![AOF执行过程.png](https://blog.zs-fighting.cn/upload/2021/07/AOF%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B-8c68f0a863274634ab1d38541bf4693e.png)
**每当执行服务器任务或者函数时flushAppendOnlyFile函数都会被调用,这个函数执行以下两个工作**
- WRITE:根据条件,将aof_buf中的缓存写入到aof文件
- SAVE:根据条件,调用sync或fdatasync函数,将aof文件保存到磁盘中
**产生的问题:**
持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条是多余的
# 总结
## 穿透
**缓存穿透是指查询一个一定不存在的数据,由于缓存不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要查询数据库,造成缓存穿透**
解决办法:持久层查询不到就缓存空结果,查询时先判断缓存中是否exists(key),如果有直接返回空,没有则查询后返回
注意insert时需清除查询的key,否则即便DB中有值也查询不到。(也可以设置空缓存的过期时间)
## 雪崩
**雪崩:缓存大量失效的时候,引发大量查询数据库**
解决办法:
- 用锁/分布式锁或者队列串行访问
- 缓存失效时间均匀分布
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有查询都落在数据库上,造成了缓存雪崩
# redis cluster 集群
## 简介
**集群模式是实际使用最多的模式**
Redis Cluster是社区版推出的Redis分布式集群解决方案,主要解决Redis分布式方面的需求,比如,当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster能起到很好的负载均衡的目的
## 集群描述
Redis集群搭建的方式有很多种,3.0之后的版本支持redis-cluster集群,**至少需要3(Master)+3(Slave)才能建立集群**,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。
![rediscluster架构.png](https://blog.zs-fighting.cn/upload/2021/07/redis-cluster%E6%9E%B6%E6%9E%84-7af003ba6eb94205ab7d9d6f4384d858.png)
Redis Cluster 集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
**Redis集群特点**
![rediscluster特点.png](https://blog.zs-fighting.cn/upload/2021/07/redis-cluster%E7%89%B9%E7%82%B9-8e9ad969ca4d4ff6b8e6c7327f6690e2.png)
>1、所有的redis节点彼此互联(PING.PONG机制)
>
>2、节点的fail是通过集群超过半数的节点检测失败时才生效
>
>3、客户端与redis节点直连,客户端不需要连接集群所有节点,连接集群中任意一个可用节点即可
>
>4、redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster负责维护
>
>5、Redis集群预分了16384个哈希槽,当需要在Redis集群中放置一个key-value时,redis先对key使用才crc16算法算出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之前的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同节点
## Redis Cluster集群搭建
5.0.x版本以上的可以直接使用`redis-cli`创建集群,可以在一台服务器启动6个端口,也可以在6台服务器上搭建
```
mkdir -p /usr/local/redis_cluster
mkdir 7000 7001 7002 7003 7004 7005
cp /opt/redis-5.0.4/redis.conf ./7000
修改redis.conf
# 关闭保护模式,用于公网访问
protected-mode no
port 7000
# 开启集群模式
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
# 后台启动
daemonize yes
pidfile /var/run/redis_7000.pid
logfile "7000.log"
#dir /redis/data
# 此处绑定ip,可以注释,代表全网监听
#bind 127.0.0.1
# 用于连接主节点的密码
masterauth 123456
# 设置redis密码,各个节点请保持密码一致
requirepass 123456
拷贝配置文件到其他节点
cp ./7000/redis.conf ./7001 ./7002 ./7003 ./7004 ./7005
启动所有节点
cp -a /opt/redis-5.0.4/src /usr/local/redis_cluster
./src/redis-server ./7000/redis.conf
./src/redis-server ./7001/redis.conf
./src/redis-server ./7002/redis.conf
./src/redis-server ./7003/redis.conf
./src/redis-server ./7004/redis.conf
./src/redis-server ./7005/redis.conf
```
redis 5版本后,通过redis-cli客户端命令创建集群
```
./src/redis-cli --cluster create -a 123456 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
```
# redis cluster 集群验证
```
redis-cli -h 127.0.0.1 -c -p 7000 -a 123456 :加参数 -c 可连接到集群
```
redis cluster 在设计的时候,接考虑到去中心化,也就是说,集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他节点连接,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据
```
1、info replication:查看当前节点的信息
2、cluster nodes:查看集群的信息
每个redis的节点都有一个ID值,此ID将被此特定redis实例永久使用,而不是通过ip+端口号,因为ip和端口号可能改变
```
Redis介绍