Redis6(学习)

安装

  1. 在windows上下载redis,使用软件放在opt目录下,在linux上安装c语言编译环境,先检查有没有gcc 用gcc –version 如果没有用命令yum install gcc -y
  2. 安装完成后,先解压,tar -zxvf redis-6.2.3.tar.gz -C /opt/javasoftware/
    进入到解压后的文件夹中,用make命令编译,然后用make in stall
  3. 前台启动redis-server
  4. 后台启动:先将redis.conf移动到etc目录下,然后将daemonize后的no改为yes可用/daemo搜索,修改好后,切换到安装的默认目录,用redis-server xxx xxx为redis.conf文件被复制的位置 启动,最后可用ps -ef|grep redis.conf查看进程
  5. 使用redis-cli:通过客户端连接redis,输入ping 如果为Pong则为正常连接状态
    redis-cli shutdown关闭也可查找进程再kill -9 端口号关闭

关于Key的命令

keys *					查看所有key
esists k1				查看k1这个key存不存在,返回1存在0不存在
type k1					查看k1这个key为什么类型
unlink k3或者del k3 	都是删除k3这个key,del是直接删掉,unlink是选择非阻塞删除,真正的删除要后续异步删除
expire key 10  			10秒钟,给key设置过期时间
ttl key 				查看key还有多久过期,-1代表永不过期,为-2代表已经过期

select 					切换数据库0-15 默认为0
dbsize 					查看数据库有多少个key
flushdb 				清空当前库
flushall  				通杀全部库

数据类型使用

字符串

get key1 				获取key1中的值
append key1 abc 		在key1的value后追加上abc
strlen key1 			获取key1的长度
setnx key1 value 		只有当key不存在时,才能设置key的值
incr key1 				将key1中的数字值增1,只能对数字值使用如果为空新增值为1
decr key1 				将key1中的数字值减1,只能对数字值使用如果为空新增值为-1
incrby key1 20 			将key1中的值增加20,自定义步长
decrby key1 20 			将key1中的值减少20,自定义步长

原子性操作(不会被影响,有一个失败都失败)

mset k1 v1 k2 v2 		给k1和k2同时设置value
mget k1 k2 				同时取k1和k2的value
msetnx k1 v1 k2 v2 		给k1和k2同时设置value(但是只能当所有的key都唯一时才行)
getrange key 0 3 		取key中value 03位置字符 包括3位置的也会取
setrange key 3 			设置key中value 3位置后面的字符 包括3位置的也会设置
setex key time value 	设置key时把过期时间也加上 时间为秒
getset key value 		新值换旧值,但是当前值获取到的是之前的,获取之后值就变成新设置的

value值扩容规律
类似于Java中的ArrayList
在这里插入图片描述

List单键多值

lpush k1 v1 v2 v3 		可放多个,从左边开始放(相当于推),所以先放的在右边。
rpush k2 v1 v2 v3 		可放多个,从右边开始放(相当于推),所以先放的在左边。
lrange k1 0 1			查看value值,查看第0个和第1个,从0开始,第二位为-1代表看k1所有
lpop k2 				从左边弹出,如果没有值了键就不存在了
rpop k2 				从右边弹出,如果没有值了键就不存在了
rpoplpush k1 k2 		从k1的最右边取一个值放入k2的最左边
lindex k1 1 			从k1中取下标为1的value,下标从0开始
llen k1 				获取k1的列表长度
linsert k1 before v1 nv 在v1的前面插入nv值
linsert k1 after v1 nv 	在v1的后面插入nv值
lrem k1 2 zhangsan 		从k1的左边开始删,删除两个value为zhangsan的
lset k1 1 wangwu 		将k1中下标为1位置的value替换成wangwu

特性
列表元素较少时,使用一块连续的内存存储,这个结构为ziplist,当数据量大时,改为quicklist,将这些ziplist以链表形式连起来
在这里插入图片描述

Set常用命令

sadd k1 v1 v2 v3 v1 	创建一个k1,将v1 v2 v3放入,因为重复了v1,所以第二个v1不会放进去
smembers k1 			将k1的值全部取出,不会删除value
sismember k1 v2 		判断k1中是否有v2,有返回1,无返回0
scard k1 				返回该集合中的元素个数
srem k1 v1 v3			将k1中的v1和v3元素删除
spop k1 				随机从k1中吐出一个数(会删除)
srandmember k1 2 		随机从k1中吐出两个数,不会删除
sinter k1 k2 			返回k1和k2的交集
sunion k1 k2 			返回k1和k2的并集
sdiff k1 k2 			返回k1和k2的差集(k1中的不含k2中)

特性
底层结构是字典,字典是用哈希表实现的,所有的value都指向同一个内部值

哈希类型常用命令

hset user:1001 id 1 	设置一个user为1001的属性id为1
hset user:1001 			name wangwu设置user为1001的属性name为wangwu
hget user:1001 id 		从user:1001里面取id这个属性的值
hmset user:1002 id 2 	name lisi age 23 批量设置属性
hexists user:1002 id 	判断user:1002中是否存在id这个域 有返回1,无返回0
hkeys user:1002 		查看user:1002中的所有域
hvals user:1002 		查看user:1002中的所有域中的值
hincrby user:1002 id 2 	使user:1002中id域值加2
hsetnx user:1002 gender '男' 	往user:1002中填加域和值,当且仅当添加的这个值不存在,成功返回1 否则0

特性
hash对应的数据结构有两种,ziplist(压缩列表)和hashtable(哈希表),当field-value长度较短且个数较少使用ziplist,否则使用hashtable

有序集合Zset

zadd k1 200 java 300 c++ 400 mysql 500 php 	将元素和评分有序的加到集合中去
zrange k1 0 -1 					取出k1中的所有元素,排名为评分从小到大,无评分
zrange k1 0 1 withscores 		取出下标0-1的元素,包含他们的评分
zrangebyscore k1 300 400 		从k1中取出,评分在300-400之间的元素,从小到大排
zrevrangebyscore k1 400 300 	从k1中取出,评分在300-400之间的元素,从大到小排
zincrby k1 50 java 				增加k1中成员java的评分
zrem k1 php 					删除k1中的php元素
zcount k1 200 400 				统计k1中评分在200400之间元素的个数
zrank k1 java 					算k1中java的排名,从0开始

数据结构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

配置文件(外部连接redis)

  1. 找到修改后的配置文件,将里面的bind 127.0.0.1 -::1注释掉,就可进行外部连接,否则只能进行本地连接。
  2. protected-mode yes 把yes改为no。
  3. tcp-backlog 511 正在进行TCP三次握手+已经完成三次握手的队列的总和。
  4. timeout 0 秒为单位,代表如果超过这么久时间没操作就断开连接,重新使用需要再连接,配置为0代表永不超时。
  5. tcp-keepalive 300 每隔300s检测连接是否还活着就继续服务,否则停止服务。
  6. loglevel 默认是notice级别
  7. logfile “” 输出日志文件路径,默认为空
  8. 有16个数据库默认为0
    注意:连接不上查看下防火墙,要关闭防火墙,再重启Redis

发布和订阅

先开两个redis的客户端。

  1. subscribe channel1订阅channel1通道
  2. publish channel1 hello 向channel1中发送hello,订阅了channel1的通道会收到hello

Redis6新数据类型

Bitmaps

统计用户活跃数量

  1. 本质也是字符串,是进行位操作的字符串
  2. 在第一次初始化时,如果偏移量很大,那么整个初始化就比较慢,可能会造成Redis阻塞。值只能是0和1
setbit users:3114658 1 1 		设置key为users:3114658 其中在偏移量1上的值为1,没设置过的都为0,偏移量从0开始。
getbit users:3114658 20 		取users:3114658中偏移量为20的值
bitcount users:3114658 			返回users:3114658中值为1的个数
bitcount users:3114658 0 1 		返回users:3114658中在01个字节中值为1的个数(一个字节8位)
bitop and users:and:3114658_1 users:3114658 users:3114651 
求users:3114658 users:3114651这两个用户中偏移量相同且都为1时的个数

在这里插入图片描述
用户较少就用set,多用Bitmap

HyperLogLog

基数:不重复元素个数

pfadd lisi python 			往lisi中加入python,加入成功返回1,否则返回0
pfcount lisi 				计算lisi中基数的数量
pfmerge zhangsan lisi hy 	将lisi和hy中的值都存进zhangsan中,合并时,相同的也只会有一个

GEO

元素的二维坐标,在地图上就是经纬度。
元素的二维坐标,在地图上就是经纬度。

geoadd china:city 121.47 31.23 shanghai 	添加上海的经纬度在china:city中
geopos china:city chongqing 				取得chongqing在china:city中的经纬度

在这里插入图片描述

geodist china:city chongqing shanghai km 	求china:city中上海到重庆的直线距离,单位是km
georadius china:city 110 30 1000 km 		在china:city中位于经纬度11030附近1000km以内的城市

事务

悲观锁
认为每次操作都不安全,每次操作都要上锁,用完后释放锁。
乐观锁
操作完成后会升级版本号,如果两个同时操作,当要进行操作时会检测自己的版本号和当前的数据库版本号是否一致,不一致的话不能操作,一致才能操作。

multi 				开启事务,之后进行的操作都会进入队列
exec 				执行在队列中的事务
discard 			放弃事务中的队列,都不执行
错误处理:
		组队阶段出错,则整个队列都会被取消,都不执行
		执行阶段出错,只有出错的不执行,其他都执行
watch key			监视key,当key被改动时,当前事务对key的操作会失效,返回nil
可以监视多个watch key key1 key2这样写
unwatch key key1 	取消监视

dump.rdb文件,持久化操作

在哪个目录启动就会在哪个目录生成dump.rdb文件。
Redis的配置文件里面的snopshotting中有:

  1. dir ./表示在当前目录生成,可以修改成自己想要的位置。
  2. dbfilename dump.rdb 表示生成的文件名
  3. save 3600 1 如果3600s内有1个key发生变化,就保存
  4. save 300 100 如果300s内有100个key发生变化,就保存
  5. save 60 10000 如果60s内有10000个key发生变化,就保存。(这三个相当于改变的key个数不同持久化时间就不同)可以改变这个规则。
    注意:改变后需要重新启动redis,否则持久化时间不会生效
  6. 一般持久化都交给redis,不去手动操作,因为手动是阻塞操作,期间只会做这个,其他的都不管。save是手动阻塞,bgsave是自动异步。
  7. stop-writes-on-bgsave-error当Redis无法写入磁盘的话,直接关掉Redis的写操作。默认yes。
  8. rdbcompression压缩文件,对于存储到磁盘中的快照进行压缩,默认为yes,按照LZF算法进行压缩。
  9. rdbshecksum检查完整性,使用CRC64算法进行数据校验,但这样做会增加10%的性能消耗,默认yes。

RDB和AOF

RDB
默认是开启的

  1. RDB的缺点是最后一次持久化后的数据可能丢失。对于数据的完整性不是非常敏感的时候用。(最后一次持久化到一部分,Redis突然挂掉,剩下的就不能进行持久化了)
  2. fork子进程通过临时文件替换dump.rdb文件。写时复制技术,先复制一份dump.rdb出来,然后往里面写,写好后替换。

优势

  1. 适合大规模的数据恢复
  2. 对数据的完整性和一致性要求不高更适合使用
  3. 节省磁盘空间
  4. 恢复速度快

劣势

  1. Fork的时候内存中的数据被克隆了一份,大约2倍的膨胀性需要考虑
  2. 虽然Redis在fork使用了写时拷贝技术,但数据量庞大时比较消耗性能,会丢失一部分数据。

AOF(Append Only File)

  1. 默认不开启的将Redis配置文件中的appendonly no改为appendonly yes就开启了.
  2. appendfilename “appendonly.aof” 生成aof文件的名字
  3. AOF和RDB同时开启时,Redis听AOF的(数据不存在丢失)
  4. 文件异常恢复,修复后也要重启redis ,redis-check-aof --fix /appendonly.aof,redis-check-aof为默认安装位置的这个文件,/appendonly.aof为需修复的aof文件的位置,需先切换到/usr/local/bin文件夹下输入以上命令。
  5. appendfsync always 始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好。
  6. appendsync everysec每秒同步,但是如果宕机,本秒数据可能会丢失。
  7. appendsync no Redis不主动同步,把同步时机交给操作系统
  8. 重写操作,例如:文件大小大于64M,文件达到100%128M开始重写
  9. 也和RDB的fork一致。

流程:

  1. 客户端的请求写命令会被append追加到AOF缓冲区内;
  2. AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
  3. AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
  4. Redis重启时回家再AOF文件的写操作,达到恢复数据的目的。

优势

  1. 备份机制更稳健,丢失数据概率更低。
  2. 可读的日志文本,通过操作AOF稳健,可以处理误操作。

劣势

  1. 比起RDB占用更多的磁盘空间;
  2. 恢复备份速度要慢;
  3. 每次读写都要同步的话,有一定性能压力;
  4. 存在个别Bug,造成恢复不能。
    在这里插入图片描述

主从复制

一主多从 或 一主一从 Master/Slave,主以写为主,从以读为主
原理

  1. 当从连接上主服务器后,从服务器向主服务器发送要进行数据同步的消息;
  2. 主服务器接到从服务器发送过来同步消息,把主服务器数据进行持久化,把rdb文件发送从服务器,从服务器拿到rdb进行读取;
  3. 每次主服务器进行写操作后,就会和从服务器进行数据同步。

好处

  1. 读写分离
  2. 容灾快速恢复

模拟一主两从

  1. 创建/myredis文件夹
  2. 复制redis.conf文件夹到新创建的文件夹中
  3. 配置一主两从,创建三个配置文件 redis6379.conf redis6380.conf redis6381.conf
  4. 在三个配置文件中写入配置
    6379配置 pid的6379 端口号 6379 还有文件名6379 其他的两个配置文件也只变这三个地方
include /myredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379 
dbfilename dump6379.rdb 
  1. 分别启动三个redis,ps -ef|grep redis 查看是否都启动
  2. redis-cli -p 6379通过端口号连接,info replication 查看redis服务器状态(需先进入客户端redis-cli)
  3. slaveof 127.0.0.1 6379将当前的这个redis作为127.0.0.1 6379的从机,主机写进去的从机可以读到,但是从机不能进行写操作。
  4. 从服务器挂掉重启以后,又变为了主服务器,需要重新操作变为从服务器,操作后变成
    的从服务器能够和之前一样,有所有数据。

模拟薪火相传
从服务器下面再挂一台从服务器。原理和一主两仆类似。

反客为主
主机挂掉后,从机作为主机,但是只能手动用 slaveof no one 命令,但是会有哨兵模式,可以自动实现。

反客为主自动版–哨兵模式

  1. 创建sentinel.conf文本在/myredis文件夹下;
  2. 在sentinel.conf文本中输入sentinel monitor mymaster 127.0.0.1 6379 1 解释:mymaster为监控对象起的服务器名字,1为至少有多少个哨兵同意迁移的数量;
  3. redis-sentinel sentinel.conf 启动哨兵,sentinel.conf为刚才创建的文件夹位置和名字;
  4. 主挂掉以后,哨兵会从从机中选一个变为一个主,原先的主恢复后会变为从;
  5. 存在复制延时问题;
  6. 选举从机为主机的原理,根据优先级,redis.conf(redis 6)默认replica-priority 100,值越小优先级越高,如果优先级一样就看偏移量选择偏移量大的,如果偏移量也相同,选择runid最小的从服务器,runid是每个redis实例启动后随机生成的一个40位的runid。

Java代码实现主从复制点这

Redis容量不够的扩容、并发写操作解决方案

在这里插入图片描述
批量修改Linux命令:%s/6379/6380

搭建集群

  1. 在之前的redis63xx.conf文件中加入以下三行,弄6个这样的文件出来。
cluster-enable yes  #开启集群
cluster-config-file nodes-6379.conf #配置文件
cluster-node-timeout 15000  #多长时间没动作断开
  1. 修改完成后,分别启动这六个redis,会生成6个nodes-63xx.conf配置文件
  2. 以上都无误后,先进入安装redis的目录(低版本的redis需要配环境), cd /opt/javasoftware/redis-6.2.3/
  3. 在上一步进入的src目录下执行redis-cli --cluster create --cluster-replicas 1 192.168.111.130:6379 192.168.111.130:6380 192.168.111.130:6381 192.168.111.130:6382 192.168.111.130:6383 192.168.111.130:6384 解释:–cluster-replicas 选择集群方式 1为最简单的为每个主节点创建1个从机,刚好三组;192.168.111.130为LInux的ip;6379为redis的端口号。
  4. 运行后会有[OK] All 16384 slots covered.这样的一个值,一个Redis集群中包含16384个插槽(hash slot)数据库中的每个键都属于这16384个插槽中的1个。至此集群就搭建好了。
  5. 集群方式连接命令: redis-cli -c -p 6379
  6. cluster nodes 查看集群信息命令,根据很长的序列号来判断,相同的就是主从关系

在16384个插槽中节点:
A负责0-5460
B负责5461-10922
C负责10923-16383
当使用集群中的任意一个入口进行写入操作时,根据写入的值会生成一个插槽,他在哪个范围就跳到哪个节点去进行操作(相当于跳端口)。
注意!!!:不能一次直接输入多个key value,除非把它包装成组,类似于以下命令:mset name{user} lisi age{user} 22 gender{user} 1

一些命令

cluster keyslot k1  			计算k1插槽为多少
cluster countkeysinslot 12706 	查看这个插槽的key(只能看自己插槽中的值),有返回1无返回0
cluster getkeysinslot 12706 1	得到12706这个插槽中的1个key

分配原则
主机和从机要在不同的ip上

故障恢复

某一主机出现故障时,会将从机提升为主机进行服务,当主机恢复时挂掉的主机会变为从机进行服务。
在这里插入图片描述
如果某一插槽断都挂掉(主从都掉线)根据你的配置决定集群挂不挂掉.
cluster-require-full-coverage yes 这样的话整个集群都挂掉 no的话是该插槽的数据全部不能使用,也无法存储。
集群的Java代码

Redis集群好处与不足

优势

  1. 实现扩容
  2. 分摊压力
  3. 无中心配置相对简单

劣势

  1. 多键操作是不被支持的
  2. 多键的Redis事务是不被支持的。lua脚本不被支持
  3. 集群出现晚,许多公司已经采用其他集群方案,整体迁移复杂度大

缓存穿透

原因

  1. redis查询不到数据库;
  2. 出现很多非正常url访问。

现象

  1. 应用服务器压力变大了;
  2. redis命中率降低,查不到数据;
  3. 导致一直查询数据库。

解决方案

  1. 对空值缓存,虽然数据库没有但是在redis中做null缓存,但是设置它的过期时间不超过5分钟;
  2. 设置可访问白名单(白名单),使用bitmaps里面的id进行比较,如果访问的id不存在就进行拦截,不允许访问;
  3. 采用布隆过滤器,但是命中率不是很高;
  4. 进行实时监控,当发现redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合设置黑名单限制服务。

缓存击穿

现象

  1. 数据库访问压力瞬时增加;
  2. redis中并没有出现key过期
  3. redis运行正常

原因

  1. redis的有个key过期了,但是大量访问都用到了这个key;

解决方案

  1. 预先设置一些热门数据,加大这些key的访问时长;
  2. 实时调整,现场监控哪些数据热门,实时调整key的过期时长;
  3. 使用锁,为空就设置它的使用时效。

击穿是热频key过期了,然后一直访问数据库,穿透是大量无效的url访问,缓存中没有,增大服务器压力。

雪崩问题

现象

  1. 数据库压力变大,响应变慢,应用访问也变慢,造成redis里面大量的访问等待,就造成全部崩溃。

原因

  1. 在极少时间段内,查询大量key的集中过期情况。
    解决方案

  2. 构建多级缓存机构: nginx+redis+其他缓存;

  3. 使用锁或队列,但是不适用高并发;

  4. 设置过期标志更新缓存,如果快过期了就更新一下过期时间;

  5. 将缓存失效时间分散开,将原有的失效时间基础上增加1个随机值比如1-5分钟。

分布式锁

跨JVM的互斥机制来控制共享资源的访问,共享锁。
分布式锁的最简单应用
setnx user 10 返回1
setnx user 20 返回0
del user 10
setnx user 20 返回1
相当于加锁就是setnx 释放锁就是del,但是会出现一直占用的情况所以给锁设置过期时间expire,但是会出现还没进行设置时间时断电,导致时间没设置上。
在上锁的时候就设置过期时间 set users 10 nx ex 12

释放锁的过程中可能出现误释放
https://editor.csdn.net/md/?articleId=116494523

java代码实现uuid防误删

在这里插入图片描述
没有原子性,导致有可能锁的uuid一致,但是过期自动释放了,然后还进行了删除操作,把别人的锁删掉了。

LUA脚本保证删除的原子性java代码

在这里插入图片描述

redis6 新特性

ACL

acl list  				权限内容查看;
acl cat					查看具体的操作命令有哪些
acl cat	string			查看具体的操作命令有哪些
acl setuser lucy 		添加用户
acl whoami				查看当前是哪个用户在操作
acl setuser mary on >password ~cached:* +get  on为激活该用户可操作,只能对key开头为cached的操作 password为设置的密码
auth mary password		切换到mary用户

IO多线程

redis命令依然是单线程+多路IO复用
在这里插入图片描述
多线程IO默认也是没开启的,需在配置文件中设置
io-threads-do-reads yes 开启多线程IO
io-threads 4 设置多线程数量

工具支持Cluster,集群环境

猜你喜欢

转载自blog.csdn.net/wflsyf/article/details/116463237