redis使用-基本命令+进阶配置

常用命令

redis 常用命令

		redis-cli   进入redis操作命令行
		keys*       查看所有键
		get "键名"   获取指定键
		keys  xxx*   获取xxx开头的键名
		del key      删除指定键名的值
		flushall     删除全部数据库的全部数据
		move  键名 1   删除键值对  1  代表当前数据库
		redis-cli -n 0 keys "*" | xargs redis-cli -n 0 del   下面的命令指定数据序号为0,即默认数据库 
		dbsize       查看key的数量:
		ttl  键名     检查键名过期时间
		type  键名    查看当前key的类型

五大基础类型

1.String类型 (字符串)

结构图:
在这里插入图片描述

①追加、拼接、字符串长度

myRedis:2>set key1 ab  # 设置key
"OK"
myRedis:2>get key1  #查看 key
"ab"
myRedis:2>APPEND key1 hello #给key值 追加拼接字符串,如果本来不存在,就新建
"7"
myRedis:2>get key1
"abhello"
myRedis:2>strlen key1 # 获取key值的长度
"7"
myRedis:2>

② i++、增加、减去固定值

I++ 、固定步长的 i++

做 i++  操作
myRedis:2>set view 0  # 设置浏览量 为 0 
"OK"
myRedis:2>get view
"0"
myRedis:2>incr view  # 加一
"1"
myRedis:2>incr view   # 加一
"2"
myRedis:2>incr view   # 加一
"3"
myRedis:2>get view    #获取值
"3"
myRedis:2>decr view   #减一
"2"
myRedis:2>decr view   #减一
"1"
myRedis:2>get view
"1"
myRedis:2>incrby view 10   #加固定值
"11"
myRedis:2>incrby view 10   #加固定值
"21"
myRedis:2>decrby view 5   #减去固定值
"16"
myRedis:2>decrby view 5   #减去固定值
"11"
myRedis:2>

③ 截取字符串

截取字符串

myRedis:2>set key1 hello,chenchong
"OK"
myRedis:2>get key1
"hello,chenchong"
myRedis:2>getrange key1 0 3  #截取字符串 下标0 开始
"hell"
myRedis:2>getrange key1 0 -1   #截取字符串 下标0 开始 -1代表全部长度
"hello,chenchong"
myRedis:2>

④ 根据是否已经存在判断是否存入

根据键名是否已经存在,来决定操作跟返回值

myRedis:2>keys *   #检查键
 1)  "key1"
myRedis:2>setnx key2 222  # 键不存在,直接创建
"1"
myRedis:2>setnx key1 111  #键已经存在,创建失败,返回 0 
"0"
myRedis:2>
myRedis:2>mset k1 v1 k2 v2  # 一次设置多个键值对 空格键分开
"OK"
myRedis:2>keys *
 1)  "k1"
 2)  "k2"
myRedis:2>msetnx k3 v3 k2 v2  # 批量判断是否存在,不存在才插入,其中一个存在就全部失败 (原子性)
"0"
myRedis:2>

⑤ 组合命令 getset

先 get 再 set

myRedis:2>getset key 123   # 如果键名不存在,就创建赋值,并返回null
null
myRedis:2>get key
"123"
myRedis:2>getset key 456  #如果键名存在,就返回原来的值,替换为新值
"123"
myRedis:2>get key
"456"

2.list类型 (列表)

■ redis 中 list 相当于一个双端队列,它可以充当完成 堆、栈、队列的功能

■ list 中,数据是分左右操作的,
从左边进行的所有操作命令都是以 L 开头的。
从左边进行的所有操作命令都是以 R开头的

■ list中允许重复值

结构图:

在这里插入图片描述

① 存入、取出 - lpush rpush

redis中,向list中存入数据是以 栈 的存储方式进行的,先存入的在最里面(可能是左边也可能是右边)

myRedis:2>lpush list one  # 从左边存入 第一个 one
"1"
myRedis:2>lpush list two  # 从左边存入 第二个 two
"2"
myRedis:2>lpush list three  # 从左边存入 第三个 three
"3"
myRedis:2>lrange list 0 1  # 根据下标来从左边获取前两个 得到 three、two
 1)  "three"
 2)  "two"
myRedis:2>rpush list four  # 从右边存入 第一个 four
"4"
myRedis:2>rpush list five  # 从右边存入 第二个 five
"5"
myRedis:2>

存储结构:
在这里插入图片描述

② 移除数据 - lpop rpop

myRedis:2>lrange list 0 -1  # 打印list中全部数据
 1)  "three"
 2)  "two"
 3)  "one"
 4)  "four"
 5)  "five"
myRedis:2>lpop list  # 左边移除一个,返回移除的值
"three"
myRedis:2>lrange list 0 -1  # 打印list中全部数据
 1)  "two"
 2)  "one"
 3)  "four"
 4)  "five"
myRedis:2>rpop list  # 右边移除一个,返回移除的值
"five"
myRedis:2>lrange list 0 -1  # 打印list中全部数据
 1)  "two"
 2)  "one"
 3)  "four"
myRedis:2>

③ 通过下标获取指定位置的值

myRedis:2>lrange list 0 -1  #打印数据
 1)  "two"
 2)  "one"
 3)  "four"
myRedis:2>lindex list 0  #获取左边第一个
"two"
myRedis:2>lindex list 1  #获取左边第二个
"one"

④ 获取列表长度 - llen

myRedis:2>llen list
"3"

⑤ 移除指定的元素

因为list中允许重复值的出现,因此移除的时候,需要指定移除几个

myRedis:2>lrange list 0 -1  # 打印list
 1)  "two"
 2)  "one"
 3)  "four"
myRedis:2>lrem list 1 two  # 移除 一个 值 two
"1"
myRedis:2>lrange list 0 -1
 1)  "one"
 2)  "four"
myRedis:2>

⑥ 指定下标截断

截取的时候,已经修改了原本的list数据

myRedis:2>lrange list 0 -1  #打印
 1)  "d"
 2)  "c"
 3)  "b"
 4)  "a"
myRedis:2>ltrim list 1 2  # 从 下标为1 开始截取,取 2 个值
"OK"
myRedis:2>lrange list 0 -1
 1)  "c"
 2)  "b"
myRedis:2>

⑦ 移除并移动到新list

localhost:2>lpush list a  # 向 list 中赋值
"1"

localhost:2>lpush list b
"2"

localhost:2>lpush list c
"3"

localhost:2>lrange list 0 -1  #打印
 1)  "c"
 2)  "b"
 3)  "a"
localhost:2> lpush list2 1  # 向list2 赋值
"1"

localhost:2>lrange list2 0 -1  #打印
 1)  "1"
 
localhost:2>rpoplpush list list2  # 从list中移除,并放入 list2中
"a"

localhost:2>lrange list 0 -1
 1)  "c"
 2)  "b"
localhost:2>lrange list2 0 -1
 1)  "a"
 2)  "1"
localhost:2>

⑧ 在某个元素之前插入

localhost:2>lpush list b # 插入数据
"1"
localhost:2>lpush list a
"2"
localhost:2>lrange list 0 -1 #打印
1) "a"
2) "b"
localhost:2>linsert list before b c  # 从左边,在 b 之前插入 c
"3"
localhost:2>lrange list 0 -1
1) "a"
2) "c"
3) "b"
localhost:2>
localhost:2>lrange list 0 -1
1) "a"
2) "c"
3) "b"
localhost:2>linsert list after b d  # 在后边插入
"4"
localhost:2>lrange list 0 -1
1) "a"
2) "c"
3) "b"
4) "d"
localhost:2>

总结:
在这里插入图片描述

3.Set类型 (集合)

set 里面存储的数据不允许重复,存储是无序的

set 的语句都是以 s 开头的

结构图:
在这里插入图片描述

①基础语句 插入 查询 判断是否存在


localhost:2>sadd set1 hello  # 存入
"1"
localhost:2>sadd set1 world
"1"
localhost:2>smembers set1  #查看集合中所有成员
1) "world"
2) "hello"
localhost:2>sismember set1 hello  # 判断成员是否存在  存在1   不存在0
"1"
localhost:2>sismember set1 hello123
"0"
localhost:2>

② 重复插入测试,集合长度,移除元素

localhost:2>smembers set1  #打印
1) "world"
2) "hello"
localhost:2>sadd set1 hello # 重复添加 返回0 插入失败
"0"
localhost:2>scard set1 #获得集合的长度
"2"
localhost:2>srem set1 hello  #移除指定元素
"1"
localhost:2>scard set1
"1"
localhost:2>

③随机获取 , 随机删除

localhost:2>smembers set
1) "c"
2) "b"
3) "d"
4) "f"
5) "e"
6) "a"
localhost:2>srandmember set 1  #随机抽出指定个数的元素
"a"
localhost:2>srandmember set 1
"c"
localhost:2>srandmember set 1
"f"
localhost:2>srandmember set 1
"c"
localhost:2>srandmember set 1
"e"
localhost:2>srandmember set 1
"b"
localhost:2>
localhost:2>spop set  #随机删除
"c"
localhost:2>spop set
"a"
localhost:2>smembers set
1) "b"
2) "d"
3) "f"
4) "e"
localhost:2>

④ 求交集 , 差集 , 并集

set1 : 1,2,3

set2 : 3,4,5

localhost:2>smembers set1 # 两个集合
1) "1"
2) "2"
3) "3"
localhost:2>smembers set2
1) "3"
2) "4"
3) "5"

localhost:2>sdiff set1 set2  #求差集  前面的比后面的差的是什么
1) "1"
2) "2"
localhost:2>sdiff set2 set1   #求差集  
1) "4"
2) "5"
localhost:2>sinter set1 set2 #求交集
1) "3"
localhost:2>sunion set1 set2 #求并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

4.Hash类型 (哈希)

map集合,它里面存得是键值对,前面的类型,要么是一个键对应一个string,要么是一个键对应很多数据,这个,一个键,对应的是很多 key-value

Hash类型的操作,一般都是以 h 字母开头

结构图:
在这里插入图片描述

① 单个存入,取出 多个存入,取出

myRedis:2>hset myHash key1 value1  #存入单个 key-value 键值对
"1"
myRedis:2>hget myHash key1  #取出单个 key 的值
"value1"
myRedis:2>hmset myHash key2 value2 key3 value3 key4 value4 #存入多个
"OK"
myRedis:2>hmget myHash key2 key3 #取出多个
1) "value2"
2) "value3"
myRedis:2>

②查看所有键值对,删除指定键值对

myRedis:2>hgetall myHash  # 查看所有
1) "key1"
2) "value1"
3) "key2"
4) "value2"
5) "key3"
6) "value3"
7) "key4"
8) "value4"
myRedis:2>hdel myHash key1 删除指定Hash中指定键值对
"1"
myRedis:2>hgetall myHash
1) "key2"
2) "value2"
3) "key3"
4) "value3"
5) "key4"
6) "value4"
myRedis:2>

③查看其中存在多个键值对的数量

myRedis:2>hgetall myHash  #打印
1) "key2"
2) "value2"
3) "key3"
4) "value3"
5) "key4"
6) "value4"
myRedis:2>hlen myHash # 键值对数量
"3"
myRedis:2> hdel myHash key3 # 删除其中一对
"1"
myRedis:2>hlen myHash #再次检查
"2"

④判断是否存在某个key

myRedis:2>hgetall myHash  #打印
1) "key2"
2) "value2"
3) "key4"
4) "value4"
myRedis:2>hexists myHash key2 #判断是否存在,存在返回1  不存在返回0
"1"
myRedis:2>hexists myHash key7
"0"
myRedis:2>

⑤获取所有key , 获取所有value

myRedis:2>hgetall myHash  # 打印
1) "key2"
2) "value2"
3) "key4"
4) "value4"
myRedis:2>hkeys myHash  # 获取所有key
1) "key2"
2) "key4"
myRedis:2>hvals myHash #获取所有value
1) "value2"
2) "value4"
myRedis:2>

⑥ 指定增量

localhost:2>hset myHash key 5  # 设置一个初始值
"1"
localhost:2>hgetall myHash  # 检查
1) "key"
2) "5"
localhost:2>hincrby myHash key 2  #增量 指定为2 
"7"
localhost:2>hgetall myHash    # 检查
1) "key"
2) "7"
localhost:2>hincrby myHash key 2  #再次增量 指定为2 
"9"
localhost:2>hgetall myHash  # 检查
1) "key"
2) "9"
localhost:2>hincrby myHash key -1  #可以指定为负值,相当于减去
"8"
localhost:2>

5.Zset类型 (有序集合)

Zset 实际上是另外一种set 其中存入的数据也不允许重复,但是在此基础上增加了一个排序.

可以用来做一些排序功能

Zset的命令一般都是以 z 字母开头的

结构图:
在这里插入图片描述

①普通存入,读取

myRedis:2>zadd age 12 chen # 存入  :  zadd 键名 权重 值
"1"
myRedis:2>zadd age 22 wang # 存入  :  zadd 键名 权重 值
"1"
myRedis:2>zadd age 10 li # 存入  :  zadd 键名 权重 值
"1"
myRedis:2>zadd age 35 ma  # 存入  :  zadd 键名 权重 值
"1"
myRedis:2>zrange age 0 -1  #打印,默认存储结构为升序
1) "li"
2) "chen"
3) "wang"
4) "ma"
myRedis:2>

②排序

myRedis:2>zrange age 0 -1  # 默认打印的是升序
1) "li"
2) "chen"
3) "wang"
4) "ma"
myRedis:2>ZREVRANGE age 0 -1  #ZREVRANGE 命令是降序
1) "ma"
2) "wang"
3) "chen"
4) "li"

③ 排序+操作

myRedis:2>zrange age 0 -1  # 普通排序,升序
1) "li"
2) "chen"
3) "wang"
4) "ma"
myRedis:2>ZRANGEBYSCORE age -inf +inf withscores # 升序排序,但是指定查询区间 ,如果不知道区间,就取 -inf +inf 取从最大到最小, withscores表示显示权重
1) "li"
2) "10"
3) "chen"
4) "12"
5) "wang"
6) "22"
7) "ma"
8) "35"
myRedis:2>ZRANGEBYSCORE age 10 30 withscores # 升序排序,查询权重在 10到30之间的.
1) "li"
2) "10"
3) "chen"
4) "12"
5) "wang"
6) "22"
myRedis:2>ZRANGEBYSCORE age -inf 20 withscores #搭配使用,查出所有权重小于20的
1) "li"
2) "10"
3) "chen"
4) "12"

查询 满足区间内的元素 数量

myRedis:2>ZRANGEBYSCORE age -inf +inf withscores #打印显示权重
1) "li"
2) "10"
3) "chen"
4) "12"
5) "wang"
6) "22"
7) "ma"
8) "35"
myRedis:2>zcount age 10 30 # 查询 10~30区间内的元素数量
"3"
myRedis:2>zcount age 10 20 # 查询 10~20区间内的元素数量
"2"
myRedis:2>zcount age 40 60 # 查询 40~60区间内的元素数量
"0"
myRedis:2>

④移除元素

myRedis:2>zrange age 0 -1  #打印
1) "li"
2) "chen"
3) "wang"
4) "ma"
myRedis:2>zrem age li   #移除一个元素
"1"
myRedis:2>zrange age 0 -1  #打印
1) "chen"
2) "wang"
3) "ma"
myRedis:2>zcard age  #元素个数检测
"3"
myRedis:2>

三大特殊数据类型

Geospatial 地理位置

事先存入redis 经纬度信息,reids可以直接算出需要的数据
结构图
一般命令是以 geo 开头的
在这里插入图片描述

① 添加地点经纬度 - geoadd

规则:两级(南极北极)无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
有效的经度从-180度到180度。 有效的纬度从-85.05112878度到85.05112878度。
当坐标位置超出上述指定范围时,该命令将会返回一个错误。

http://www.jsons.cn/lngcode/ 查询经纬度

myRedis:2>geoadd china:city 113.66 34.75 zhenzhou  # 添加地点 键 经纬度 地点名
"1"
myRedis:2>geoadd china:city 114.34 34.797 kaifeng
"1"
myRedis:2>geoadd china:city 120.15 38.28 hangzou
"1"
myRedis:2>geoadd china:city 114.64 33.62 zoukou
"1"
myRedis:2>

② 获取经纬度 - geopos

myRedis:2>geopos china:city zhenzhou # 获取经纬度
1) 1) "113.65999907255173"
   2) "34.749999265106908"

myRedis:2>geopos china:city kaifeng
1) 1) "114.33999806642532"
   2) "34.797000599564534"

myRedis:2>geopos china:city zhoukou
1) null
myRedis:2>geopos china:city zoukou
1) 1) "114.63999778032303"
   2) "33.620000294504329"

myRedis:2>

③计算两点之间的距离 - geodist

m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。

myRedis:2>geodist china:city kaifeng zoukou km  # 计算两地之间的距离
"133.7899"
myRedis:2>geodist china:city kaifeng zoukou m
"133789.9169"
myRedis:2>geodist china:city kaifeng zoukou mi
"83.1334"
myRedis:2>geodist china:city kaifeng zoukou ft
"438943.2969"
myRedis:2>

④ 查出某地 某个距离范围内的所有地点 - GEORADIUSBYMEMBER

myRedis:2>GEORADIUSBYMEMBER china:city zoukou 1000 km
1) "zoukou"
2) "zhenzhou"
3) "kaifeng"
4) "beijing"
5) "hangzou"
myRedis:2>GEORADIUSBYMEMBER china:city zoukou 500 km
1) "zoukou"
2) "zhenzhou"
3) "kaifeng"
myRedis:2>

Hyperloglog 基数

什么是基数
A {1,3,5,7,8,7}
B{1,3,5,7,8}
A、B集合的基数(不重复的元素) = 5,可以接受误差!

优点:占用的内存是固定,2^64 不同的元素的技术,只需要废 12KB内存!如果要从内存角度来比较的话 Hyperloglog 首选!
网页的 UV (一个人访问一个网站多次,但是还是算作一个人!)
传统的方式, set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断 !
这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;
0.81% 错误率! 统计UV任务,可以忽略不计的!

一般命令以 pf 开头

需要注意的是:基数求得是不相同的元素的个数 。 相当于去重后取个数

① 存入 , 单个计算基数 , 组合计算基数

将两个组合到一块之后,就会生成一个新的合并之后的组合

localhost:2>pfadd key1 a b c d e   # 存入数据
"1"
localhost:2>pfcount key1  # 计算基数个数
"5"
localhost:2>pfadd key2 d e f f    # 存入数据
"1"
localhost:2>pfcount key2 # 计算基数个数
"3"
localhost:2>pfmerge key3 key1 key2  #合并组合,计算基数
"OK"
localhost:2>pfcount key3
"6"
localhost:2>

生成了新的组合:
在这里插入图片描述

Bitmap 位存储

位存储 是一种位图的数据结构,都是操作二进制进行记录。就只有 0 和 1 两种状态
它因为只存储 0 1 因此占有内存极小

适合用来处理只有两个状态的情况。例如 打卡/未打卡 ,登录/未登录 ,活跃/不活跃

① 存入

记录周一到周五的打卡情况

localhost:2>setbit flag 1 0  # 周一  未打卡
"0"
localhost:2>setbit flag 2 0  # 周二  未打卡
"0"
localhost:2>setbit flag 3 1  # 周三  打卡
"0"
localhost:2>setbit flag 4 1  # 周四  打卡
"0"
localhost:2>setbit flag 5 1  # 周五  打卡
"0"
localhost:2>

②检查某一天的状态

localhost:2>getbit flag 3   # 获取周三打卡情况
"1"
localhost:2>getbit flag 1   # 获取周一打卡情况
"0"
localhost:2>

③统计 状态为 1 的数量

localhost:2>bitcount flag  #统计 状态为 1 的数量
"3"
localhost:2>

事务

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

开启事务

顺序

  • 开启事务(multi)
  • 命令入队 (…)
  • 执行事务 (exec)
localhost:2>keys *   #打印

localhost:2>multi     #开启事务
"OK"
localhost:2>set k1 v1  #命令入队(正常输入操作命令)
"QUEUED"
localhost:2>set k2 v2  #命令入队(正常输入操作命令)
"QUEUED"
localhost:2>get k2  #命令入队(正常输入操作命令)
"QUEUED"
localhost:2>exec  #执行事务,执行命令才会开启事务
1) "OK"
2) "OK"
3) "OK"
4) "OK"
5) "OK"
6) "v2"
7) "OK"
localhost:2>
  • 取消事务 (discard)
localhost:2>multi  # 开始事务
"OK"
localhost:2>set k3 v3
"QUEUED"
localhost:2>set k4 v4
"QUEUED"
localhost:2>discard  # 取消事务的编写
"OK"
localhost:2>get k3  #打印
null
localhost:2>

异常:

  • 编译型异常,(代码有问题,输入命令就是错误的),事务中所有的命令都不会执行
localhost:2>multi  # 开启事务
"OK"
localhost:2>set k3 v3
"QUEUED"
localhost:2>set k4 v4
"QUEUED"
localhost:2>getset  #输入错误的命令
"ERR wrong number of arguments for 'getset' command"
localhost:2>get k4 v4
"ERR wrong number of arguments for 'get' command"
localhost:2>set k5 v5
"QUEUED" 
localhost:2>exec  #事务也开启失败
"EXECABORT Transaction discarded because of previous errors."
localhost:2>
  • 运行时异常,如果事务中,多个命令中有个别出现运行异常,那么此条错误语句会报错抛出异常,其他语句还是会正常运行 (redis中事务不保证原子性
localhost:2>set k1 "v1"  # 先创建一个值
"OK"
localhost:2>multi  #开启事务
"OK"
localhost:2>incr k1  #对字符串进行 加以操作,会导致运行时错误
"QUEUED"
localhost:2>set k2 v2 #进行输入正确的命令入队
"QUEUED"
localhost:2>get k2
"QUEUED" 
localhost:2>exec  #执行
1) "OK"
2) "ERR value is not an integer or out of range"  # 错误的语句提示 抛出异常
3) "OK"   #后续其他正确的命令依旧执行
4) "OK"   #后续其他正确的命令依旧执行
5) "OK"   #后续其他正确的命令依旧执行
6) "v2"   #后续其他正确的命令依旧执行
7) "OK"   #后续其他正确的命令依旧执行
localhost:2>

redis的锁

乐观锁

很乐观,认为什么时候都不会出现问题,只在更新的时候去判断一下,在此期间有没有人懂这条数据,一般是通过 version 字段来处理

先获取version

在啊更新时判断version 是否一致 在redis中,使用 watch 字段来监视字段,实现事务。

正常流程

localhost:2>set money 100  # 余额设为 100
"OK"
localhost:2>set out 0     #花费设为0
"OK"
localhost:2>watch monry  # 乐观锁,进行watch 监视
"OK"

localhost:2>multi   #开启事务
"OK"
localhost:2>decrby money 20
"QUEUED"
localhost:2>incrby out 20
"QUEUED"
localhost:2>exec  # 执行事务,此时没有其他线程来打扰,因此流程进行正常
1) "OK"
2) "80"
3) "OK"
4) "20"
5) "OK"
localhost:2>get money 
"80"
localhost:2>get out
"20"
localhost:2>

多线程扰乱情况

localhost:2>watch money   #正常流程,先不执行事务
"OK"
localhost:2>multi
"OK"
localhost:2>decrby money 20
"QUEUED"
localhost:2>incrby out 20
"QUEUED"
localhost:2>get money   #在另一个线程对money 进行修改值
"100"
localhost:2>decrby money 50
"50"
localhost:2>
localhost:2>watch money  
"OK"
localhost:2>multi
"OK"
localhost:2>decrby money 20
"QUEUED"
localhost:2>incrby out 20
"QUEUED"
localhost:2>exec    #线程执行后没有任何返回,证明事务提交失败

localhost:2>exec
"ERR EXEC without MULTI"
localhost:2>

如果遇见事务提交失败,需要再次提交时,需要先放弃当前字段监视,重新获取该字段监视才可以。

localhost:2>unwatch money  # 放弃当前监视
"OK"
localhost:2>watch money  #从新监视
"OK"

悲观锁

很悲观,认为任何情况下都会出现问题,都会加锁。会导致性能低下。
redis 不使用悲观锁,在此不研究。

conf配置文件

1. 单位控制

# 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.  #大小写不敏感

配置文件 unit 单位对大小写不敏感

2.包含/引入 其他文件

相当于Java中的 import


################################## INCLUDES ###################################

# Include one or more other config files here.  This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings.  Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include .\path\to\local.conf    # 引入其他配置文件
# include c:\path\to\other.conf    # 引入其他配置文件

3。网络配置

在这里插入图片描述

bind 127.0.0.1   #IP

port 6379   #端口

protected-mode yes   #保护模式  默认yes 开启

4.通用配置

在这里插入图片描述

daemonize no  #以守护进程的方式允许。默认是no,需要我们自己手动开启为 yes


 pidfile /var/run/redis.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
# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output.
logfile ""   #指定生成文件的位置名


databases 16  #默认数据库的数量

5.快照

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

redis是内存数据库,如果不持久化,那么数据断电就会丢失
在这里插入图片描述

# 如果900s内,如果至少有一个key进行了修改,就进行持久化操作
save 900 1

#如果30s内,如果至少有10个key进行了修改,就进行持久化操作
save 300 10

#如果60s内,如果至少有10000个key进行了修改,就进行持久化操作
save 60 10000
# 一般实际应用时,会自己配置这个时间频率

#持久化如果出错,是否还需要继续工作
stop-writes-on-bgsave-error yes  

#是否压缩 rdb 文件,需要消耗一些cpu资源
rdbcompression yes

#保存rdb文件时 进行错误的校验检查
rdbchecksum yes

# rdb文件的保存位置
dir ./

6.主从复制

在这里插入图片描述

在这里插入代码片

7.安全

在这里插入图片描述

# 设置密码  默认为空
# requirepass foobared   

#设置密码  为 123456
requirepass 123456 

在这里插入图片描述

8.限制

在这里插入图片描述

9.aof模式

在这里插入图片描述

appendonly no    #默认关闭,默认是使用 rdb 方式来持久化的

Redis 持久化

RDB (Redis DataBase)

什么是 RDB
在这里插入图片描述
工作原理:
在这里插入图片描述
保存文件
在这里插入图片描述
触发条件

  1. save规则满足的情况下,会自动触发rdb规则
  2. 执行 flushdb 命令,也会触发rdb规则
  3. 退出redis,也会产生 rdb 文件
    触发之后,都会自动生成一个 dump.rdb 文件

如何将rdb文件恢复为内存数据

  1. 只需要将rdb文件放在redis启动目录即可,redis启动时会自动检测 dump.rdb 恢复其中的数据
  2. 查看需要存放的位置的命令
myRedis:1>config get dir
1) "dir"
2) "D:\Program Files\Redis"
myRedis:1>

优点与缺点:
在这里插入图片描述

AOF (Append Only File)

什么是 AOF
将我们执行的所有命令都记录下来,history,恢复的时候把这个文件都执行一遍。

ps.默认是不开启使用 aof 的,需要自己手动修改配置文件来开启

在这里插入图片描述
工作原理
在这里插入图片描述
保存文件
在这里插入图片描述

触发条件
每进行一个命令的输入,就会追加保存到文件中。

优点与缺点

在这里插入图片描述

ps. AOF模式有校验机制,如果aof文件有错误,是redis启动不起来的,需要使用redis提供的修复工具来修复

redis -check-aof --fix appendonly.aof

扩展总结

在这里插入图片描述

在这里插入图片描述

Redis订阅发布

在这里插入图片描述

订阅频道

SUBSCRIBE

localhost:2>SUBSCRIBE  chenchong   # 订阅一个频道,频道不需要提前创建,订阅即可
切换到推送/订阅模式,关闭标签页来停止接收信息。  # 提示消息
1) "subscribe"   #正在监听中
2) "chenchong"
3) "1"

频道发布消息

PUBLISH

localhost:2>PUBLISH chenchong hello,chen  # 发布频道消息
"1"   #代表有几个订阅者收到消息
localhost:2>
localhost:2>SUBSCRIBE  chenchong
切换到推送/订阅模式,关闭标签页来停止接收信息。
1) "subscribe"
2) "chenchong"
3) "1"
1) "message"   # 收到消息 提示
2) "chenchong"   # 频道信息
3) "hello,chen"  #信息内容

订阅多个频道

PSUBSCRIBE

localhost:2>PSUBSCRIBE chen chong   # 同时订阅 chen  与  chong  频道
切换到推送/订阅模式,关闭标签页来停止接收信息。
1) "psubscribe"
2) "chen"
3) "1"
localhost:2>PUBLISH chen hello,123 # chen频道发布消息
"1"
localhost:2>PUBLISH chong hello,123 # chong频道发布消息
"1"
localhost:2>
localhost:2>PSUBSCRIBE chen chong
切换到推送/订阅模式,关闭标签页来停止接收信息。
1) "psubscribe"
2) "chen"
3) "1"
1) "pmessage"  # 接受到 chen 频道的消息
2) "chen"
3) "chen"
4) "hello,123"
1) "pmessage"    # 接受到 chong 频道的消息
2) "chong"
3) "chong"
4) "hello,123"

退订频道

PUNSUBSCRIBE

localhost:2>PUNSUBSCRIBE chenchong  # 推定指定频道
1) "punsubscribe"
2) "chenchong"
3) "0"

localhost:2>PUBLISH chenchong hello,chen
"1"
localhost:2>PUBLISH chenchong hello,redis
"1"
localhost:2>PUBLISH chenchong hello,123   #频道继续发布,但是未订阅不会收到消息
"0"
localhost:2>
localhost:2>PUNSUBSCRIBE chenchong
1) "punsubscribe"
2) "chenchong"
3) "0"
localhost:2>

原理

在这里插入图片描述

Redis 主从复制

概念

在这里插入图片描述

为什么使用

在这里插入图片描述

环境配置

只配置主从库,不用配置主库(因为redis都默认自己是主库,所有只需要将当作从库的配置一下)

查看本机信息:info replication

localhost:2>info replication  #查看当前库的信息
"# Replication
role:master  # 角色 master (主库)
connected_slaves:0  #从机连接数 
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
"
localhost:2>

在这里插入图片描述
在这里插入图片描述
到此,三台redis服务已经启动,开始配置 一主二从 的配置

配置从机

将主机修改为 认某一个主机为上位,则自己就变为从机。

SLAVEOF

localhost:2>SLAVEOF 127.0.0.1 6379   #设定 本机的 6379 端口的服务为主机,主机为从机

再次检查自己的信息,已经变为从机

在这里插入图片描述
1.这种命令行的形式配置的是临时的,如果从机断掉再启动,会自动变成主机。

2.要想永久生效得在配置文件中配置

3.主机才可以读写操作,从机只有读操作

从机复制数据原理

在这里插入图片描述

哨兵模式

概述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置

与上面主从复制一样,也是新建一个配置文件,填写内容:

在这里插入图片描述
在这里插入图片描述

优点与缺点

在这里插入图片描述

哨兵模式的全部配置

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


Redis 缓存穿透、击穿、雪崩

缓存穿透 (在数据库查不到,无法存入缓存,导致每次都去数据库查)

概念

在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。

解决方案

布隆过滤器
在这里插入图片描述
直接缓存为空对象

一次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求。

在这里插入图片描述

这样做有一个缺陷:存储空对象也需要空间,大量的空对象会耗费一定的空间,存储效率并不高。解决这个缺陷的方式就是设置较短过期时间

即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

缓存击穿 (穿透的特例,缓存过期,同时有大量访问请求该值。热点数据)

概念

​ 相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。

​ 比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。

解决方案

设置热点数据永不过期
这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。

加互斥锁(分布式锁)

在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。当线程访问结束后,缓存即生成,就不会对数据库造成过大压力。这样对锁的要求就十分高。

缓存雪崩 (大量key同一时间过期)

概念

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
在这里插入图片描述

解决方案

  • redis高可用

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群

  • 限流降级

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

  • 数据预热

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

内存过期、淘汰机制

在这里插入图片描述

过期策略 (定期检测删除+惰性删除)

redis中的键被设置了过期时间,当到了过期时间mredis会将其删除,这个删除的策略就是过期策略.

  • 定期检测删除
指Redis默认每隔 一定时间 就 随机抽取 一些设置了过期时间的key,检测这些key是否过期,如果过期了就将其删除。
而这个 一定时间+一些key  都是可以在配置文件 redis.conf 中设置的。
  • 惰性删除
	因为定期检测删除是检测一部分,这样就会造成有些key已经过期失效了,但是因为没有被检测所有仍然存在。因此就引入惰性删除。
 	惰性删除不是主动删除,是被动的在有请求访问这些key的时候,先去检测key是否过期失效,如果没有过期,就把key返回;如果过期就删除掉这个key,不会返回给你。

缺点:定期检测删除+惰性删除 的复合机制能够保证这个过期的key最终肯定会被删除,但是不保证时效性。如果这个key过期了,一直没有请求它,并且没有被定期删除掉,那么它还会大量占据内存。最后导致内存耗尽。

为了解决上面的问题,引入内存淘汰机制

内存淘汰机制

内存淘汰机制就是在redis内存占用量达到一定值时,去按照某种策略去进行内存淘汰(也就是删除一部分key),以此保证redis的内存占用率不会过高。

而这个 一定值+某种策略 也可以在redis.conf配置文件中进行配置

     *  淘汰机制的执行时机以及过程
     *  1.当有操作需要向redis中新增数据时。
     *  2.redis会去检查当前redisn内存使用情况,如果当前内存超过了设定值,就会按照设定好的策略进行删除一些key。
     *  3.然后再执行新增新数据的操作。

常见八种内存淘汰机制配置:

  *  ①no-eviction:当内存不足以容纳新写入数据时,新写入操作会报错,无法写入新数据,(一般不采用)。
     *
     *  ②allkeys-lru:当内存不足以容纳新写入数据时,移除 ’最近+最少' 使用的key,(这个是最常用的)
     *  ③allkeys-random:当内存不足以容纳新写入的数据时,随机移除key。
     *  ④allkeys-lfu:当内存不足以容纳新写入数据时,移除 '最不经常(最少,但未必是最近的)'使用的key
     *
     *  下面开始,移除key都是在设定了过期时间的key中操作。上面是在所有的key中操作。
     *volatile-lru:当内存不足以容纳新写入数据时,在'设置了过期时间的key'中,移除'最近最少使用'的key。
     *volatile-random:内存不足以容纳新写入数据时,在设置了过期时间的key中,随机移除某个key 。
     *volatile-lfu:当内存不足以容纳新写入数据时,在设置了过期时间的key中,移除最不经常(最少)使用的key
     *volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,优先移除过期时间最早(剩余存活时间最短)的key。
     *
 * 过期策略与内存淘汰机制是相辅相成的。

参考文章链接
参考视频链接

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值