博客园 首页 私信博主 显示目录 隐藏目录 管理

redis

Redis

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。

NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

NoSQL特点

1、方便扩展

2、大数据量高性能

3、数据类型是多样性的

4、传统RDBMS和NoSQL

RDBMS vs NoSQL

RDBMS(关系型数据库)
- 高度组织化结构化数据
- 结构化查询语言(SQL) (SQL)
- 数据和关系都存储在单独的表中。
- 数据操纵语言,数据定义语言
- 严格的一致性
- 基础事务

NoSQL
- 代表着不仅仅是SQL
- 没有声明性查询语言
- 没有预定义的模式
-键 - 值对存储,列存储,文档存储,图形数据库
- 最终一致性,而非ACID属性
- 非结构化和不可预知的数据
- CAP定理
- 高性能,高可用性和可伸缩性


大数据时代的3V:主要是描述问题的

1、海量Volume

2、多样Variety

3、实时Velocity

大数据时代的3高:主要是对程序的要求

1、高并发

2、高可拓

3、高性能

NoSQL 的四大分类

  • KV键值对

    Redis

  • 文档型数据库(bson格式:类似json)

    MongoDB

  • 列存储数据库

    Hbase

  • 图关系数据库(不是存储图形,而是存储关系的,类似社交网络的关系图谱)

    Neo4j,InfoGrid

分类 数据模型 优点 缺点 典型应用场景
键值(Key-Value)存储数据库 Key指向Value的键值对,通常用hash表来实现 查找速度快 数据无结构化(通常只被当作字符串或者二进制数据) 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等
列存储数据库 以列簇式存储,将同一列数据存在一起 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限 分布式的文件系统
文档型数据库 Key-Value对应的键值对,Value为结构化数据 数据结构要求不严格,表结构可变(不需要像关系型数据库一样需预先定义表结构) 查询性能不高,而且缺乏统一的查询语法 Web应用
图形(Graph)数据库 图结构 利用图结构相关算法(如最短路径寻址,N度关系查找等) 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案 社交网络,推荐系统等

Redis作用

1、内存存储、持久化

2、效率高,可以用于高速缓存

Redis 安装使用(Linux)

https://redis.io/download【官网下载】

下载好了上传服务器指定地址解压安装

tar -zxvf redis-6.2.3.tar.gz

解压之后进入redis文件夹,先安装基础环境(C环境,因为redis是C语言写的),创建新的redis配置文件(就是对原有的配置文件进行备份)

//进入redis的解压目录
cd redis-6.2.3
//安装C环境
yum install gcc-c++
//检查环境
gcc -v
//安装环境
make
//验证
make install
//创建新的配置环境
mkdir kconfig
cp redis.conf kconfig

redis默认不是后台运行的,需要修改配置文件中的daemonize yes

启动redis服务

//通过配置文件启动
redis-server kconfig/redis.conf
//使用redis客户端验证是否启动,输入ping,返回pong即为成功
redis-cli -p 6379
ping
//也可以通过查看端口号的形式
ps -ef|grep redis
//结果
root      3750     1  0 15:18 ?        00:00:01 redis-server 127.0.0.1:6379
root      6711  3338  0 15:38 pts/1    00:00:00 grep --color=auto redis

redis关闭服务

在redis中输入shutdown后exit

redis 相关命令

更多命令请参考:https://redis.io/commands

在这里可以查看全部【https://www.redis.net.cn/order/】

Key 相关

序号 命令及描述
1 DEL key 该命令用于在 key 存在时删除 key。
2 DUMP key 序列化给定 key ,并返回被序列化的值。
3 EXISTS key 检查给定 key 是否存在。
4 EXPIRE key seconds 为给定 key 设置过期时间,以秒计。
5 EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
6 PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计。
7 PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
8 KEYS pattern 查找所有符合给定模式( pattern)的 key 。
9 MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中。
10 PERSIST key 移除 key 的过期时间,key 将持久保持。
11 PTTL key 以毫秒为单位返回 key 的剩余的过期时间。
12 TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
13 RANDOMKEY 从当前数据库中随机返回一个 key 。
14 RENAME key newkey 修改 key 的名称
15 RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey 。
16 [SCAN cursor MATCH pattern] [COUNT count] 迭代数据库中的数据库键。
17 TYPE key 返回 key 所储存的值的类型。

Redis性能测试 redis-benchmark

redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000

redis 性能测试工具可选参数如下所示:

序号 选项 描述 默认值
1 -h 指定服务器主机名 127.0.0.1
2 -p 指定服务器端口 6379
3 -s 指定服务器 socket
4 -c 指定并发连接数 50
5 -n 指定请求数 10000
6 -d 以字节的形式指定 SET/GET 值的数据大小 2
7 -k 1=keep alive 0=reconnect 1
8 -r SET/GET/INCR 使用随机 key, SADD 使用随机值
9 -P 通过管道传输 请求 1
10 -q 强制退出 redis。仅显示 query/sec 值
11 --csv 以 CSV 格式输出
12 *-l*(L 的小写字母) 生成循环,永久执行测试
13 -t 仅运行以逗号分隔的测试命令列表。
14 *-I*(i 的大写字母) Idle 模式。仅打开 N 个 idle 连接并等待。
//测试
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
//部分输出:
====== SET ======                                                   
  100000 requests completed in 1.10 seconds//100000个请求进行set测试
  100 parallel clients//100个并发客户端
  3 bytes payload//每次写入3个字节
  keep alive: 1//只有一台服务器来处理(单机性能)
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no
Latency by percentile distribution:
0.000% <= 0.191 milliseconds (cumulative count 1)
50.000% <= 0.527 milliseconds (cumulative count 52127)
75.000% <= 0.583 milliseconds (cumulative count 75872)
87.500% <= 0.663 milliseconds (cumulative count 88050)
93.750% <= 0.767 milliseconds (cumulative count 93995)
96.875% <= 0.943 milliseconds (cumulative count 96909)
98.438% <= 1.279 milliseconds (cumulative count 98469)
99.219% <= 1.471 milliseconds (cumulative count 99220)
99.609% <= 1.631 milliseconds (cumulative count 99613)
99.805% <= 1.807 milliseconds (cumulative count 99806)
99.902% <= 2.247 milliseconds (cumulative count 99903)
99.951% <= 3.439 milliseconds (cumulative count 99952)
99.976% <= 3.863 milliseconds (cumulative count 99976)
99.988% <= 4.063 milliseconds (cumulative count 99988)
99.994% <= 4.167 milliseconds (cumulative count 99994)
99.997% <= 4.199 milliseconds (cumulative count 99997)
99.998% <= 4.239 milliseconds (cumulative count 99999)
99.999% <= 4.255 milliseconds (cumulative count 100000)
100.000% <= 4.255 milliseconds (cumulative count 100000)//所有请求在5毫秒内处理完成

Redis 基本数据类型

Redis String 数据类型

下表列出了常用的 redis 字符串命令:

序号 命令及描述
1 SET key value 设置指定 key 的值
2 GET key 获取指定 key 的值。
3 GETRANGE key start end 返回 key 中字符串值的子字符
4 GETSET key value 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
5 GETBIT key offset 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
6 [MGET key1 key2..] 获取所有(一个或多个)给定 key 的值。
7 SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
8 SETEX key seconds value 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。
9 SETNX key value 只有在 key 不存在时设置 key 的值。
10 SETRANGE key offset value 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。
11 STRLEN key 返回 key 所储存的字符串值的长度。
12 [MSET key value key value ...] 同时设置一个或多个 key-value 对。
13 [MSETNX key value key value ...] 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
14 PSETEX key milliseconds value 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。
15 INCR key 将 key 中储存的数字值增一。
16 INCRBY key increment 将 key 所储存的值加上给定的增量值(increment) 。
17 INCRBYFLOAT key increment 将 key 所储存的值加上给定的浮点增量值(increment) 。
18 DECR key 将 key 中储存的数字值减一。
19 DECRBY key decrement key 所储存的值减去给定的减量值(decrement) 。
20 APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。

Redis Hash数据类型

下表列出了 redis hash 基本的相关命令:

序号 命令及描述
1 [HDEL key field1 field2] 删除一个或多个哈希表字段
2 HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。
3 HGET key field 获取存储在哈希表中指定字段的值。
4 HGETALL key 获取在哈希表中指定 key 的所有字段和值
5 HINCRBY key field increment 为哈希表 key 中的指定字段的整数值加上增量 increment 。
6 HINCRBYFLOAT key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。
7 HKEYS key 获取所有哈希表中的字段
8 HLEN key 获取哈希表中字段的数量
9 [HMGET key field1 field2] 获取所有给定字段的值
10 [HMSET key field1 value1 field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。
11 HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。
12 HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。
13 HVALS key 获取哈希表中所有值。
14 [HSCAN key cursor MATCH pattern] [COUNT count] 迭代哈希表中的键值对。

Redis List数据类型

下表列出了列表相关的基本命令:

序号 命令及描述
1 [BLPOP key1 key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
2 [BRPOP key1 key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
3 BRPOPLPUSH source destination timeout 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
4 LINDEX key index 通过索引获取列表中的元素
5 LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素
6 LLEN key 获取列表长度
7 LPOP key 移出并获取列表的第一个元素
8 [LPUSH key value1 value2] 将一个或多个值插入到列表头部
9 LPUSHX key value 将一个值插入到已存在的列表头部
10 LRANGE key start stop 获取列表指定范围内的元素
11 LREM key count value 移除列表元素
12 LSET key index value 通过索引设置列表元素的值
13 LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
14 RPOP key 移除列表的最后一个元素,返回值为移除的元素。
15 RPOPLPUSH source destination 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
16 [RPUSH key value1 value2] 在列表中添加一个或多个值
17 RPUSHX key value 为已存在的列表添加值

Redis Set数据类型

下表列出了 Redis 集合基本命令:

序号 命令及描述
1 [SADD key member1 member2] 向集合添加一个或多个成员
2 SCARD key 获取集合的成员数
3 [SDIFF key1 key2] 返回第一个集合与其他集合之间的差异。
4 [SDIFFSTORE destination key1 key2] 返回给定所有集合的差集并存储在 destination 中
5 [SINTER key1 key2] 返回给定所有集合的交集
6 [SINTERSTORE destination key1 key2] 返回给定所有集合的交集并存储在 destination 中
7 SISMEMBER key member 判断 member 元素是否是集合 key 的成员
8 SMEMBERS key 返回集合中的所有成员
9 SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合
10 SPOP key 移除并返回集合中的一个随机元素
11 [SRANDMEMBER key count] 返回集合中一个或多个随机数
12 [SREM key member1 member2] 移除集合中一个或多个成员
13 [SUNION key1 key2] 返回所有给定集合的并集
14 [SUNIONSTORE destination key1 key2] 所有给定集合的并集存储在 destination 集合中
15 [SSCAN key cursor MATCH pattern] [COUNT count] 迭代集合中的元素

Redis Zset数据类型

下表列出了 redis 有序集合的基本命令:

序号 命令及描述
1 [ZADD key score1 member1 score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数
2 ZCARD key 获取有序集合的成员数
3 ZCOUNT key min max 计算在有序集合中指定区间分数的成员数
4 ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
5 [ZINTERSTORE destination numkeys key key ...] 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 destination 中
6 ZLEXCOUNT key min max 在有序集合中计算指定字典区间内成员数量
7 [ZRANGE key start stop WITHSCORES] 通过索引区间返回有序集合指定区间内的成员
8 [ZRANGEBYLEX key min max LIMIT offset count] 通过字典区间返回有序集合的成员
9 [ZRANGEBYSCORE key min max WITHSCORES] [LIMIT] 通过分数返回有序集合指定区间内的成员
10 ZRANK key member 返回有序集合中指定成员的索引
11 [ZREM key member member ...] 移除有序集合中的一个或多个成员
12 ZREMRANGEBYLEX key min max 移除有序集合中给定的字典区间的所有成员
13 ZREMRANGEBYRANK key start stop 移除有序集合中给定的排名区间的所有成员
14 ZREMRANGEBYSCORE key min max 移除有序集合中给定的分数区间的所有成员
15 [ZREVRANGE key start stop WITHSCORES] 返回有序集中指定区间内的成员,通过索引,分数从高到低
16 [ZREVRANGEBYSCORE key max min WITHSCORES] 返回有序集中指定分数区间内的成员,分数从高到低排序
17 ZREVRANK key member 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
18 ZSCORE key member 返回有序集中,成员的分数值
19 [ZUNIONSTORE destination numkeys key key ...] 计算给定的一个或多个有序集的并集,并存储在新的 key 中
20 [ZSCAN key cursor MATCH pattern] [COUNT count] 迭代有序集合中的元素(包括元素成员和元素分值)

Redis 特殊数据类型

参考网址 : https://www.redis.net.cn/order/

Redis geospatial数据类型

geospatial的底层实现是用Zset实现的,它的一些方法可以使用Zset相关方法

### geoadd添加地理位置数据
### 两极数据无法直接添加
### geoadd key 经度 维度 名称
### 有效的经度从-180度到180度。
### 有效的纬度从-85.05112878度到85.05112878度。
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijin
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shengzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
### geopos 获取指定城市的经纬度数值
127.0.0.1:6379> geopos china:city beijin
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
### geodist 查看两地经纬度的直线距离
### 如果两个位置之间的其中一个不存在, 那么命令返回空值。
### 指定单位的参数 unit 必须是以下单位的其中一个:
### m 表示单位为米。
### km 表示单位为千米。
### mi 表示单位为英里。
### ft 表示单位为英尺。
### 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位
127.0.0.1:6379> geodist china:city beijin shanghai
"1067378.7564"
127.0.0.1:6379> geodist china:city beijin shanghai km
"1067.3788"
127.0.0.1:6379> geodist china:city beijin shanghai ft
"3501898.8071"
127.0.0.1:6379> geodist china:city beijin shanghai mi
"663.2401"
### georadius 以给定的经纬度为中心,找出某一半径内的元素   
127.0.0.1:6379> georadius china:city 110 30 500 km
1) "chongqing"
2) "xian"
### 加上直线距离
127.0.0.1:6379> georadius china:city 110 30 500 km withdist
1) 1) "chongqing"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
### 加上数量限制   
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 1
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
### georadiusbymember 找出位于指定范围内的元素,中心点是由给定的位置元素决定
127.0.0.1:6379> georadiusbymember china:city beijin 1000 km
1) "beijin"
2) "xian"
### geohash  返回一个或多个位置元素的 Geohash 表示 (极少使用)
### 该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示。返回的geohashes具有以下特性:
### 他们可以缩短从右边的字符。它将失去精度,但仍将指向同一地区。
### 它可以在 geohash.org 网站使用,网址 http://geohash.org/<geohash-string>。查询例子:http://geohash.org/sqdtr74hyu0.
### 与类似的前缀字符串是附近,但相反的是不正确的,这是可能的,用不同的前缀字符串附近。
127.0.0.1:6379> geohash china:city beijin
1) "wx4fbxxfke0"

Redis HyperLogLog数据类型

HyperLogLog 是一种用于计算唯一事物的概率数据结构(从技术上讲,这称为估计集合的基数)。通常,计算唯一项需要使用与要计算的项数成正比的内存量,因为您需要记住过去已经看过的元素,以避免对它们进行多次计数。然而,有一组算法可以用内存来换取精度:在 Redis 实现的情况下,您最终会得到一个带有标准误差的估计度量,该误差小于 1%。该算法的神奇之处在于您不再需要使用与计数的项目数量成正比的内存量,而是可以使用恒定量的内存!最坏情况下为 12k 字节,

Redis 中的 HLL 虽然在技术上是一种不同的数据结构,但被编码为 Redis 字符串,因此您可以调用GET以序列化 HLL,并将SET 其反序列化回服务器。

从概念上讲,HLL API 就像使用 Sets 来完成相同的任务。您将 SADD每个观察到的元素放入一个集合中,并SCARD用于检查集合内元素的数量,这些元素是唯一的,因为SADD不会重新添加现有元素。

虽然您并没有真正HLL添加项目,因为数据结构只包含不包含实际元素的状态,API 是相同的:

  • 每次看到一个新元素时,您都可以使用将它添加到计数中PFADD
  • 要检索的独特元素的当前近似每次PFADD至今,您使用PFCOUNT

优点:占用的内存是固定的,2^64不同的元素的技术,只需要12KB的内存

### pfadd 创建第一组元素
127.0.0.1:6379> pfadd mykey1 a b c d e f g
(integer) 1
### pfcount 统计元素的基数数量
127.0.0.1:6379> pfadd mykey5 s s s s 
(integer) 1
127.0.0.1:6379> pfcount mykey5
(integer) 1
127.0.0.1:6379> pfcount mykey1
(integer) 7
127.0.0.1:6379> pfadd mykey2 s
(integer) 1
127.0.0.1:6379> pfadd mykey3 s s d f e g h j s e 4
(integer) 1
### pfmerge 合并mykey2和mykey1到meykey4中
127.0.0.1:6379> pfmerge mykey4 mykey1 mykey2
OK
127.0.0.1:6379> pfcount mykey4
(integer) 8

基数的统计如果接受容错,推荐使用HyperLogLog

Redis Bitmap数据类型(位存储)

状态只存在0和1两种的可用bitmap

### setbit 设置bitmap数据
127.0.0.1:6379> setbit sign 0 0
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
### getbit 获取指定数据的值
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 0
(integer) 0
### bitcount 统计1的总数
127.0.0.1:6379> bitcount sign
(integer) 5

Redis事务

redis 事务本质:一组命令的集合,一个事务的所有命令都会被序列化,在事务执行过程中,会按照顺序执行

redis单条命令是保存原子性的,但是事务不保证原子性

redis事务是没有隔离级别的概念

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务(multi)
  • 命令入队(......)
  • 执行事务(exec)
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set name zhangsan
QUEUED
127.0.0.1:6379(TX)> set age 1
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK

discard 取消事务,事务队列中的命令不会执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set kk 1
QUEUED
127.0.0.1:6379(TX)> set kz 1
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get kk
(nil)

错误命令

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> getset k2 ### 错误命令,整个事务的命令都不执行【编译不过】
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k3
(nil)

运行错误

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incr k1 ### 错误命令执行失败,但是其他命令执行成功
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get k2
"v2"

Redis 实现乐观锁

正常执行:

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
127.0.0.1:6379> 

测试多线程修改值,使用watch可以实现redis的乐观锁

127.0.0.1:6379> watch money ### 监视 money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec ### 执行之前,存在另外一个线程修改了money的值,这个时候会导致事务执行失败
(nil)

解决问题:

127.0.0.1:6379> unwatch ### 解除监视【非必要,redis事务执行失败也会自动解除监视】
OK
127.0.0.1:6379> watch money ### 重新监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 40
2) (integer) 60

Jedis

Jedis是redis的java连接工具

远程连接redis的时候,需要修改redis的配置文件,将redis.conf中的bind 127.0.0.1注释,并且将protected-mode yes 修改为 no

Redis 配置文件

单位unit

# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.

网络

bind 127.0.0.1 -::1  ### 绑定的IP
protected-mode yes  ### 保护模式【远程连接时需要修改为no】
port 6379  ### 端口号

general

daemonize yes ### 以守护线程的方式运行,默认是no,需要手工修改
pidfile /var/run/redis_6379.pid ### 如果一后台的方式运行,我们需要指定一个 pid 文件
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice  ### 日志级别
logfile "" ### 日志的文件存储位置
databases 16 ### redis的默认数据库数量
always-show-logo no  ### 是否总是显示LOGO

快照

持久化,在规定时间内,执行了多少操作,则会持久化到文件.rdb.aof

redis是内存数据库,如果没有持久化,那么数据断电即失

### 3600s内,如果至少有1个key进行了修改,就会执行持久化操作
# save 3600 1
### 300s内,如果至少有100个key进行了修改,就会执行持久化操作
# save 300 100
### 60s内,如果至少有10000个key进行了修改,就会执行持久化操作
# save 60 10000

stop-writes-on-bgsave-error yes ### 如果持久化出现错误是否继续执行持久化
rdbcompression yes ### 是否压缩 rdb 文件,需要消耗CPU资源
rdbchecksum yes ### 保持 rdb 文件时进行错误的检查校验
dir ./ ### rdb 文件保存的目录

REPLICATION 主存复制


SECURITY

requirepass ### 设置密码

CLIENTS

maxclients 10000 ### 设置最大客户端数量
maxmemory <bytes> ### redis 配置最大的内存容量
maxmemory-policy noeviction ### 内存达到上限之后的处理策略
### 1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
### 2、allkeys-lru : 删除lru算法的key   
### 3、volatile-random:随机删除即将过期key   
### 4、allkeys-random:随机删除   
### 5、volatile-ttl : 删除即将过期的   
### 6、noeviction : 永不过期,返回错误

APPEND ONLY MODE(aof配置)

appendonly no ### 默认时不开启 aof 模式,默认使用的是 rdb 方式进行持久化的
appendfilename "appendonly.aof" ### 持久化文件的名称
appendfsync everysec ### 每秒执行一次sync 可能会丢失这1s的数据
# appendfsync always ### 每次修改都会执行sync(持久化),消耗性能
# appendfsync no ### 不执行sync,这个时候操作系统自己同步数据,速度最快

Redis 持久化

RDB

RDB持久化是把当前进程数据生成快照保存到硬盘的过程。

rdb 保存的文件是 dump.rdb,可以在配置文件中修改

触发机制

​ 1、save 规则满足的情况下会自动触发sync,生成dump.rdb文件

​ 2、执行flushall或flushdb时也会触发

​ 3、退出redis时,也会触发

如何恢复RDB

1、只需要将rdb文件放在redis的启动目录下。redis启动会自动检查rdb文件,恢复数据

优势:

(1)RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。

(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

劣势:

RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。

AOF

全量备份总是耗时的,有时候我们提供一种更加高效的方式AOF,工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。

aof 的备份文件是 appendonly.aof

如果appendonly.aof 出现问题,可以使用 redis-check-aof --fix appendonly.aof 修复

优点:

对于持久化要求比较高的场景,AOF比RDB更加合适。
AOF文件根据RESP协议生成,阅读性较好,可以修改。

缺点:

体积文件较大,恢复时间相比RDB也要长很多。
开启AOF需要额外处理日志数据 的aof_buf写入和磁盘同步,开启awayls模式,性能损耗会更多。
服务端进程处理重写缓冲区中的数据时会阻塞客户端请求。

Redis 发布订阅

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

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

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

img

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

img

序号 命令及描述
1 [PSUBSCRIBE pattern pattern ...] 订阅一个或多个符合给定模式的频道。
2 [PUBSUB subcommand argument [argument ...]] 查看订阅与发布系统状态。
3 PUBLISH channel message 将信息发送到指定的频道。
4 [PUNSUBSCRIBE pattern [pattern ...]] 退订所有给定模式的频道。
5 [SUBSCRIBE channel channel ...] 订阅给定的一个或多个频道的信息。
6 [UNSUBSCRIBE channel [channel ...]] 指退订给定的频道。

Redis 主从复制

主从复制:是指将一台redis服务器的数据,复制到其他的redis服务器中,前者称之为主节点(master/leader),后者称为从节点(slave/follower);数据的复制时单向的,只能从主节点到从节点。Master以写为主,Slave以读为主【读写分离】

默认情况下,每台redis服务器都是主节点;且一个主节点可以有多个从节点(或者没有从节点)。但是,一个从节点只能有一个主节点。

主从复制的作用:

1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式

2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余

3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,从节点提供读服务(即写redis数据时连接主节点,读redis数据时连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读数据负载,可以大大提高redis服务求的并发量

4、高可用(集群)基石:主从复制还是哨兵模式和集群能够实施的基础。因此说主从复制时redis高可用的基础

一般来说,要将redis使用在工程项目中,只使用一台redis时不行的:

1、从结构上,单个的redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大

2、从容量上,单个redis服务器内存容量有限,就算一台redis服务器的内存容量有256G,也不能把所有的内存用作redis存储内存,一般来说,单台redis服务器的最大使用内存不超过20G

环境配置

命令配置(暂时的)

只需要配置从库,主库不需要配置

### info replication 查看当前库的信息
127.0.0.1:6379> info replication
# Replication
role:master  ### 角色
connected_slaves:0  ### 连接的从机数量
master_failover_state:no-failover
master_replid:6f9587b16f591bb60d812d716fd31e3bfc36d176
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

在两个从机中配置

127.0.0.1:6380> slaveof 127.0.0.1 6379 ### 将127.0.0.1 6379当做127.0.0.1 6380的主机
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:1b8ac7e98d88643a786ae33453bc27c05c810a6d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:126
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:1b8ac7e98d88643a786ae33453bc27c05c810a6d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:126
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:127
repl_backlog_histlen:0
127.0.0.1:6381> 

主机信息查询

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 ### 此时主机的从机数量变成了2
slave0:ip=127.0.0.1,port=6380,state=online,offset=210,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=210,lag=0
master_failover_state:no-failover
master_replid:1b8ac7e98d88643a786ae33453bc27c05c810a6d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
配置文件配置(永久)

也是在从机的配置文件中修改

################################# REPLICATION #################################

# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
#   +------------------+      +---------------+
#   |      Master      | ---> |    Replica    |
#   | (receive writes) |      |  (exact copy) |
#   +------------------+      +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition replicas automatically try to reconnect to masters
#    and resynchronize with them.
#
replicaof 127.0.0.1 6380

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
#
masterauth <master-password>  ### 主机密码
#
# However this is not enough if you are using Redis ACLs (for Redis version
# 6 or greater), and the default user is not capable of running the PSYNC
# command and/or other commands needed for replication. In this case it's
# better to configure a special user to use with replication, and specify the
# masteruser configuration as such:
#
masteruser <username>   ### 主机用户名

主机可以写,从机中只能读

127.0.0.1:6380> get k1
"v1"
127.0.0.1:6380> set k2 v2
(error) READONLY You can't write against a read only replica.

复制原理:

slave启动成功连接到master后会发送一个sync同步命令

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

全量复制:slave服务接受数据文件,存盘并加载到内存

增量复制:master将新的所有收集到的修改命令依次传输给slave,完成同步

只要重新连接master,一次全量复制将自动执行

从机变主机

127.0.0.1:6380> slaveof no one ### 不是任何主机的从机,就变成主机了
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:bbec2597407cf431c9dac929cb0028bba5fa8674
master_replid2:1b8ac7e98d88643a786ae33453bc27c05c810a6d
master_repl_offset:1942
second_repl_offset:1943
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1942

Redis 哨兵模式【自动选举主机】

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

Redis哨兵

这里的哨兵有两个作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

用文字描述一下故障切换(failover)的过程。

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。

流程:

1、创建哨兵配置文件(sentinel.conf)

### sentinel monitor 被监控的名称 主机地址 端口 1【数字1表示如果主机挂了,slave投票看让谁接替成为主机,票数最多的就会成为主机】
sentinel monitor myredis 127.0.0.1 6379 1

2、启动哨兵

### 启动哨兵 redis-sentinel kconfig/sentinel.conf 
[root@VM_0_14_centos redis-6.2.3]# redis-sentinel kconfig/sentinel.conf 
9637:X 02 Jun 2021 15:03:04.010 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
9637:X 02 Jun 2021 15:03:04.010 # Redis version=6.2.3, bits=64, commit=00000000, modified=0, pid=9637, just started
9637:X 02 Jun 2021 15:03:04.010 # Configuration loaded
9637:X 02 Jun 2021 15:03:04.011 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.2.3 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 9637
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

9637:X 02 Jun 2021 15:03:04.011 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
9637:X 02 Jun 2021 15:03:04.123 # Sentinel ID is 0b496874451783aaf9089d5c6c0b9d469e6d724e
9637:X 02 Jun 2021 15:03:04.123 # +monitor master myredis 127.0.0.1 6379 quorum 1
9637:X 02 Jun 2021 15:03:04.124 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:03:04.192 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379

当主机关闭后,哨兵会发送心跳包

[root@VM_0_14_centos redis-6.2.3]# redis-cli -p 6379
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> shutdown
not connected> exit
9637:X 02 Jun 2021 15:04:58.290 # +sdown master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.290 # +odown master myredis 127.0.0.1 6379 #quorum 1/1
9637:X 02 Jun 2021 15:04:58.290 # +new-epoch 1
9637:X 02 Jun 2021 15:04:58.290 # +try-failover master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.372 # +vote-for-leader 0b496874451783aaf9089d5c6c0b9d469e6d724e 1
9637:X 02 Jun 2021 15:04:58.372 # +elected-leader master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.372 # +failover-state-select-slave master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.440 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.440 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.517 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.869 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.869 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:58.869 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:59.936 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:04:59.936 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:05:00.007 # +failover-end master myredis 127.0.0.1 6379
9637:X 02 Jun 2021 15:05:00.007 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6380
9637:X 02 Jun 2021 15:05:00.007 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380
9637:X 02 Jun 2021 15:05:00.007 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380

其中一个从机变成了主机

127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=13067,lag=1
master_failover_state:no-failover
master_replid:f9e9e327a40187873d3740a001c759981b75f5e4
master_replid2:1b8ac7e98d88643a786ae33453bc27c05c810a6d
master_repl_offset:13199
second_repl_offset:8737
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2111
repl_backlog_histlen:11089

如果此时6379主机重新上线,会变成从机

[root@VM_0_14_centos redis-6.2.3]# redis-server kconfig/redis01.conf 
[root@VM_0_14_centos redis-6.2.3]# redis-cli -p 6379
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:21947
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:f9e9e327a40187873d3740a001c759981b75f5e4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:21947
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:21948
repl_backlog_histlen:0

哨兵模式的全部配置

# Example   sentinel.conf
# 哨兵sentinel实例运行的端口   默认是26379,如果有哨兵集群,我们还需要配置每个哨兵端口
port 26379
#哨兵sentinel的工作目录
dir /tmp
#哨兵 sentine1 监控的redis主节点的 ip port   
# master-name  ,可以自己命名的主节点名字 只能由字母A-Z、数字0-9、这三个字符"  .   -  _ "组成。
# quorum配置多少个sentine1哨兵统- -认为master主节点失联那么这时客观上认为主节点失联了
# sentine1 monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster   127.0.0.1   6379   2
#当在Redis实例中开启了requirepass foobared 授权密码这样所有连接kedis实例的客户端都要提供密码
#设置哨兵sentinel连接主从的密码注意必须为主从设置- - 样的验证密码
# sentine1 auth-pass <master-name> <password>
sentine1 auth-pass mymaster MySUPER--secret-0123passwOrd
#指定多少毫秒之后主节点没有应答哨兵sentine1 此时哨兵主观上认为主节点下线默认30秒
# sentinel down-after-mi 11i seconds <master-name> <mi 11iseconds>
sentine1 down-after-mi 11iseconds mymaster 30000
#这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成fai lover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而 不可用。可以通过将这个值设为1来保证每次只有一个slave处于不能处理命令请求的状态。
# sentine1 paralle1-syncs <master-name> <numslaves>
sentine1 paralle1-syncs mymaster 1
#故障转移的超时时间failover-timeout 可以用在以下这些方面:
#1.同一个sentine1对同一 个master两次fai lover之间的间隔时间。
#2.当一个slave从一 个错误的master那里同步数据开始计算时间。直到s1ave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有s1aves指向新的master所需的最大时间。不过,即使过了这个超时,slaves 依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
#默认三分钟
# sentine1 failover-timeout <master-name> <milliseconds>
sentine1 fai lover-ti meout mymaster 180000
# SCRIPTS EXECUTION
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被-一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当sentine1有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等 方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一 个是事件的类型,一个是事件的描述。如果sentine1. conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentine1无法正常启动成功。
#通知脚本
# she11编程
# sentine1 notification-script <master-name> <script-path>
sentine1 notificati on-script mymaster /var/redis/notify.sh
#客户端重新配置主节点参数脚本
#当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
#以下参数将会在调用脚本时传给脚本: 
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#目前<state>总是“failover",
# <role>是“Teader"或者"observer"中的-一个。
#参数from-ip, from-port, to-ip,to-port是用来和旧的master和新的master(即旧的s lave)通信的
#这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentine1 client-reconfig-script <master-name> <script-path>
sentine1 client-reconfig-script mymaster /var/redis/reconfig.sh #一般都是由运维来配置!

Redis 缓存穿透和雪崩

redis缓存使用流程

客户端向服务器发送读请求,此时后台会先去缓存中查数据,如果数据命中,那么返回结果,反之去数据库中查询,如果数据库中查到数据,那么返回数据,并且写入缓存,如果没有查到该数据即返回空结果

  • 缓存穿透(缓存和数据库都查询不到数据)

    概念:

    缓存穿透的概念很简单,用户想要查询一个数据,发现Redis缓存中没有,也就是缓存没有命中,于是就向数据库查询,然后发现也没有,于是本次查询失败。当用户很多的时候(秒杀场景),如果在缓存都没有命中,于是都去请求了数据库DB,一瞬间就给数据库造成巨大的压力,这种情况就是常说的缓存穿透。

    解决方案:

    1、布隆过滤器

    布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。

    布隆过滤器

    2、缓存空对象

    当存储层不命中时,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,从而保护了后端数据源。

    缓存空对象

    但是这种方式存在两个问题:

    • 如果空值能够被缓存起来,这就意味着需要更多的空间存储更多的键,因为其中可能会有很多空值的键。
    • 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口不一致的问题,这对于需要保持一致的业务会有影响。
  • 缓存击穿

    概念:

    这里和缓存穿透不同,缓存穿透是查询不到数据,所以都去查询数据库,给数据库造成很大压力;而缓存击穿是一个key十分热点(比如微博某明星热搜),缓存在不停地抗着高并发,始终对一个点访问,当这个缓存数据失效后,大量的高并发请求穿破缓存,在很短时间去请求数据库(就好比一梭子子弹打容器上),就像在屏幕中凿了个洞。

    当这个热点key失效过期后,大量并发请求前往数据库查询最新数据,查询完后并写入缓存,会使数据库压力过大。

    解决方案:

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

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

    加互斥锁

  • 缓存雪崩

    概念:

    缓存雪崩是因为大面积的缓存在一个时间点集中失效,打崩了数据库。

    举个简单的例子:如果所有首页的Key失效时间都是12小时,中午12点刷新的,在零点的时候有个秒杀活动会有大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求,但是这个时候缓存所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能DBA(管理员)都没反应过来就直接挂了。此时,如果没用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是缓存雪崩。

解决方案:

1、Redis高可用
这个思想的含义就是:既然Redis有可能会挂掉,那我多增设几台Redis,这样一台挂掉了之后其它的还可以继续工作,高可用其实就是搭建的Redis集群。将热点数据均匀分布在不同的Redis库中。

2、限流降级
这个解决方案的思想就是:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待。

3、数据预热
数据预热的含义就是在正式部署之前,先把可能高访问的数据预先访问一遍,这样可能大部分的数据就能加载到缓存中。在即将发生大并发访问前手动触发加载缓存中不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀一点。

4、在批量往Redis存数据的时候,把每个key的失效时间都加个随机值,这样保证数据不会在同一时间大面积失效。

posted @ 2021-07-07 09:54  莫逆追风  阅读(48)  评论(0)    收藏  举报