(1)Redis基本特性

Redis 基本特性

Remote Dictionary Service

内存存储,NoSQL。基于内存来存储数据。无需IO,效率高。提供高可用方案。哨兵模式,分布式数据存储。

关系型数据与非关系型数据库对比

SQL

1、行存储,二维

2、结构化,Schema

3、表与表之间关联,Relationship

4、SQL语法,Structure Query Lanagurage

5、ACID Atomic consistency isolation constancy

  1. 基于磁盘存储,扩容困难。增加硬件、或者使用其他的技术(分库分表)。

  2. 数据结构固定(存储数据格式受限)。

  3. 并发量大情况下读写压力大(IO)。

NOSQL

1、非结构化数据

2、数据没有关联

3、遵循BASE最终一致性

4、支持海量数据存储,高效数据读写

5、支持分布式分片存储。

BASE介绍

Basically Available(基本可用)

Soft-State(软状态)

Eventually Consistent(最终一致性)

NOSQL类型

KV存储(Redis)

文档存储(MongoDB)

列存储HBase

图存储Graph

对象存储

XML存储

......

Redis客户端

基于TCP通讯,有固定的通讯格式(序列化协议

*3\r\n3\r\nSET\r\n9\r\nfishbones$4\r\nhaha\r\n

SET fishbones haha

*3表示一共几个参数 set (1) fishbones(2) haha(3)

\r\n 回车换行,可理解为表示空格

$3 第一个参数的(SET)长度

$9第二个参数的(fishbones)长度

......

目前常用的(官方推荐)客户端有

  1. Jedis 小巧轻量的客户端。

  2. lettuce (SpringBoot)高级客户端。线程安全支持同步异步、哨兵、分片、管道......

  3. Redisson

Jedis

Redis高级特性基本都支持。但是在多线程使用同一个Jedis连接时会出现数据干扰问题。要解决这一问题需要用到连接池,为每个线程创建一个专属的连接(Apache commonPool)。

lettuce

线程安全的客户端。使用Netty实现,多个线程可以共用一个实例,无需考虑并发问题。SpringBoot 2.0 后默认客户端,2.0前 是Jedis。

Redisson

(有中文文档)区别于传统的客户端,主要是基础Redis提供一些分布式、可扩展的Java数据结构(SET,LIST,MAP,QUEUE)。

Redis 数据类型

String

介绍

默认数据类型。包含int/float。

常用命令

set key value 设置值

get key 获取值

set key value NX 值不存在才会成功

set key value EX 设置过期时间

mset mget 批量设置 获取

strlen key 获取值的长度

append key value 追加字符(末尾)

getrange key start end 截取字符 (0开始 -1表示最后 -2 表示倒数第一个字符)

incr key 增加1 (int值可用 默认1)

incrby key value 增加value

decr , decrby value, 减少

set key 2.6 可以设置浮点数

incrbyfloat key value 增加浮点值

位相关操作(字符在Redis中以8位二进制存储)

setbit key index value 将key对应的value值的第index位修改为value。

getbit key index 获取key对应位的值

bitcount key 获取二进制存储 一共有多少个1

bitpos key 0/1 返回二进制存储 第一个0或者1的下标位置。

bitop and resultKey key1 key2 ...... 对一个或多个key求逻辑与,结果保存到resultKey中。(只有相对位结果都是1 才是 1)

bitiop or ...... 逻辑或 (对应位有一个1 就是1)

bitop xor ...... 逻辑异或 (对应值不同的时候才是1,相同就是0)

bitop not resultKey key 对制定Key进行逻辑非操作,保存到resultKey中。 (1就是0,0就是1)

String类型应用

  1. 缓存
  1. 分布式Session。Spring-session-data-redis
  1. set key value NX EX 分布式锁。(del key)
  1. incr 全局ID、计数器、限流
  1. 位操作 统计(每天有没有访问)

Hash

介绍

主要为了解决String类型,存储对象数据不方便问题。Hash不支持嵌套Hash。

优点:

  1. 节省空间。

  2. 减少Key冲突。

  3. 减少资源消耗(一次就能获取到资源,共享一个Key。利用:这种需要访问很多KEY)。

缺点:

  1. 过期时间无法针对某个字段单独设置

  2. 没有位操作

  3. 分片根据Key来进行存储分片。如果对象过大无法做到平衡。

RedisKey支持使用":"分级。通过这种方式可以做到存储一张表的内容,(Table:ID:Field)但是这种方式会消耗大量内存。

命令

hset key field value 设置 key下某个字段的值

hmset key filed1 value1 field2 value2 ...... 批量设置

hget、hmset 获取、批量获取值

hincby key field value 自增 通String incby

hexists key field 判断是否存在(1 是 0 否)

hdel key field 删除某个字段

hlen key 返回元素个数

应用场景

购物车等需要对象

List

介绍

有序的数据结构。存储的是字符串,元素允许重复,L表示左,R表示右。

基础命令

lpush key v1 v2...... 向List队列左侧增加一个或多个元素

rpush key value1 value2 ...... 向队列右侧增加一个或多个元素

lpop key 从队列左侧弹出第一个元素

blpop key timeout 阻塞弹出(没有元素则一直等待,超过timeout时间后不再阻塞等待)

lindex key 0 获取队列左侧开始某个下标的元素

lrange key 0 -1 获取队列左侧开始到队尾全部元素

应用

  1. 简单的消息队列。rpush + lpop (blpop)
  1. 时间线操作。
  1. 抢红包存储红包、秒杀存储库存

Set

介绍

String类型的无序集合,集合中元素不可重复。

基础命令

sadd key v1 v2 v3 v4 ...... 像一个Set集合添加 一个或多个元素。

smembers key 返回Set集合所有元素

scard key 返回集合元素个数

srandmember key v1 从Set集合中返回v1个随机元素(默认1)

spop key 返回并删除元素

srem key v1 v2 v3...... 移除元素

sismember key v1 判断v1是否是Set集合中的元素

sdiff key1 key2 取差集(第一个集合有,第二个没有)

sinter key1 key2 取交集

sunion key1 key2 取并集(合并后去重)

场景

  1. spop 抽奖。(随机且移除,相对公平)

  2. 微博点赞、关注、签到、打卡等。

    • 用like:WeiboId作为Key作为一个用户点赞Set集合列表。
    • 点赞后使用: sadd like:WeiboId user1
    • 去掉点赞: srem like:WeiboId user1
    • 是否点赞:sismember like:WeiboId user1
    • 点赞的所有用户: smembers like:WeiboId
    • 点赞数:scard like:WeiboId
  3. 维护商品所有标签。(标签检索商品,商品显示标签)

  1. 相互关注、共同关注、可能认识......

ZSet

介绍

有序的集合。利用key和分值排序(优先使用分值)。

基础命令

zadd key score1 v1 score2 v2 ...... 向集合中增加元素并设置元素分值,默认分值小的排在前边

zrange key 0 -1 withscores 返回集合中元素同时返回分值

zrevrange key 0 -1 withscores 返回集合中元素同时返回分值(rev翻转 分值大的排在前边)

zrangebyscore key score1 score2 获取集合中某分值区间的元素

zrem key v1 v2 删除集合中指定元素

zcard key 返回集合中元素个数

zincrby key score v1 为集合中指定元素增加指定分值

zrank key v1 获取指定元素在集合中的下标位置

zscore key v1 获取集合中指定元素的分值

应用场景

点击排行榜。

Geo

介绍

保存地理信息的数据类型,提供了地理信息的基础操作。

基础命令

geoadd key log1 lat1 v1 log2 lon2 v2 向集合中增加两个元素及其对应的经纬度坐标

geopos key v1 获取集合中指定元素的经纬度坐标

getdist key v1 v2 km 获取集合中指定两个元素的距离,用km表示。

georadius key log1 lat1 r1 km 返回集合中在指定经纬度周边r1km距离内的元素。

georadiusbymember key v1 r1 km 返回集合中在指定元素v1周边r1 km距离的元素。

HyperLogLogs

介绍

基于基数的统计方法。可以用很少的内存计算很大的基数。缺点是有误差。

命令

pfadd key v1 v2 v3 ...... 向集合中添加多个元素

pfcount key 返回元素数量

pfmerge result key1 key2...... 合并多个集合返回result

应用

可以用来统计访问量等,不需要太精确的信息。

Redis发布订阅

简介

实现消息的订阅发布,保证消息的实时性,减少性能消耗(相对lpop),支持模糊匹配、广播。

订阅发布模式中,发送者和订阅者是没有任何关系的(解耦)。发布者发送的消息是不会被持久化的,所以订阅者只能接收到从订阅频道开始之后的消息。

基础命令

subscribe key1 key2 订阅多个频道

publish key msg 向一个频道发送消息(返回结果是改频道订阅者数量)

psbuscribe news.* tweet.* 订阅一个或者多个符合给定模式的频道

unsubscribe key1 key2 取消订阅

punsbcribe new.* weather.* 去掉订阅符合给定模式的频道

pubsub channels 返回活跃的频道数量(至少有一个订阅者的频道)

Redis事务

介绍

保证多个命令之间的原子性(无法彻底保证)。

  1. Redis会按照顺序执行命令。

  2. 在事务执行过程中,不会受到其他客户端的干扰。

基础命令

multi 开启事务

exec 执行事务

discard 取消事务

watch 乐观锁实现

unwatch 取消监视

watch 提供了乐观锁行为,如果有多个线程更新同一个值时,会跟开启事务之前的值进行对比,如果不一致则取消事务。(事务开启前 使用watch监控一个或多个key。如果不使用会影响最终结果)

<pre class="md-fences md-end-block md-fences-with-lineno ty-contain-cm modeLoaded" spellcheck="false" lang="xml" cid="n261" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"> 127.0.0.1:6379> INCR int
(integer) 5
127.0.0.1:6379> multi
OK
127.0.0.1:6379> INCR int
QUEUED
127.0.0.1:6379> exec

  1. (integer) 106</pre>

在执行事务之前出现的错误会导致事务取消。

比如 事务执行中 输入 hset key fishbone (执行检查不通过)

在执行事务之后出现的错误不会导致事务取消。出错的命令不会执行,但是不会影响其他命令的执行(不满足原子性)。

Redis Lua 脚本

介绍

是一种轻量级的编程语言,基于C语言编写,与数据库存储过程类似。

  1. 能够批量执行命令

  2. Redis 会把Lua脚本当做一个整体来执行。彻底保证执行的原子性。

  3. 复杂操作的组合命令可以复用(提取公共方法让其他系统执行)。

基础命令

eval lua-script key-num [key1 key2 key3......] [value1 value2 value3]

lua-script 表示脚本内容

key-num 表示参数中有多少个key, 注意 从1 开始。如果没有则写0。

[key1 key2 key3 ......] 参数的key

[value1 value2 value3 ......] 参数的value

redis.call(command,key [param1,param2......])

commond 是命令 get、set

eval "redis.call( 'set' , keys[1] , argv[1] )" 1 user fishbone

127.0.0.1:6379> eval "redis.call( 'set' ,  KEYS[1]  ,  ARGV[1]  )"   1 user fishbone 
(nil)
127.0.0.1:6379> get user
"fishbone"
127.0.0.1:6379> 

编写、执行Lua脚本文件

创建fishbone.lua文件,并写入如下内容

redis.call('set','fishbone','666666')
return redis.call('get','fishbone')

执行命令

[root@localhost  src]#  ./redis-cli --eval  fishbone.lua  0  "666666"
[root@localhost  src]#

脚本示例

local count = redis.call('incr',KEYS[1])
 if  tonumber(count) == 1  then
  redis.call('expire',KEYS[1],ARGV[1])
  return 1
 elseif tonumber(count) > tonumber(ARGV[2]) then
  return 0
 else
  return 1
 end

 # 执行命令
 ./redis.cli --eval "ip_limit.lua"  ip:limit:127.0.0.1 , 6 10</pre>

脚本缓存

为什么要缓存 . (lua 脚本内容过多)

如何缓存 在Redise客户端执行 script load "脚本内容" 命令生成摘要。 使用evalsha 摘要编号 来执行

执行超时怎么办(死循环) 如果没有设置值的操作,可以使用 Script Kill 命令。

如果有使用 shuntdown nosave 强行停止Redis服务。

Redis 数据淘汰与内存回收

Redis 内存满了怎么办?

在某些情况下需要对Redis内存进行回收,回收分为两类。

  1. Key过期

  2. maxmemory 达到设置内存上限

Key过期淘汰策略

  1. 定时过期:到了key的过期时间,立即删除。(创建监视器)

  2. 惰性过期:在key被访问到的时候才判断是否过期,过期删除。

  3. 定期过期:每隔一段时间,清楚一定数量的过期Key。

如果Key没有设置过期时间,则按照淘汰策略来进行数据清理。

Redis 默认不淘汰数据 noevication

LRU Lest Recently Used 最近最少使用

LFU Lest Frequently Used 最少用到(一定时间内的使用频率)

volatile 设置了过期时间的Key

allKeys 全部数据

volatile-lru

allkeys-lru

volatile-lfu

allkeys-lfu

volatile-random (随机清理)

allkeys-random

volatile-ttl (清除掉快过期的数据)

noevication

LRU 算法

随机采样,找到热度最低的key。

maxmemory-samples 5

Key中包含LRU字段,LRU属性字段包含时间戳的值(取全局时钟的值做更新)。

Servercron 会定时更新全局时钟。

LFU

1、Key最后被访问的时间

2、Key访问的频次

lfu-log-factor 10 配置递增参数

lfu-decay-time 1 频次衰减 几分钟没有访问就递减

Redis 持久化

RDB: Redis DataBase

AOF: Append Only File

RDB

默认持久化方案,自动存储到RDB文件,存储到磁盘。

触发方案

  1. 配置规则自动触发/shutdown触发/flushall触发

  2. 手动触发: save /bgsave

配置规则

 save 900 1  900秒内 有1个Key被修改
 save 300 10  300秒内 
 save 60 10000 60秒内
 
 rdbcompression  yes  开启会使用LZF算法做压缩 节省空间 消耗性能 
 rdbchecksum  yes 开启后自动做 完整性校验
 dbfilename  dump.rdb   db文件名称
 dir ./   表示存储在哪里  ./表示根目录

RDB存储特点

  1. 内容紧凑。保存了某一时间节点全部的数据

  2. 不影响主进程。保存数据时 不会影响主进程的工作

  3. 恢复大数据集时速度快

  4. 同步频率问题(同步时间是不确定的,无法做到秒级的持久化)

AOF

默认不开启,解决RDB存储频率问题。

用日志的形式记录操作命令,写入日志文件。每次执行修改、写入命令都会被写入日志。

开启AOF后重启服务会优先使用AOF文件做数据恢复。(注意:首次开启AOF后文件为null,重启前需要先手动做一个备份)

配置规则

appendonly no 默认不开启
appendfilename "appendonly.aof" 文件名称
auto-aof-rewrite-percentage 100 达到上次执行的百分百后 自动执行
auto-aof-rewrite-min-size 64mb 到达aof的最小空间大小(到达64mb会触发重写。如果到达百分之百但是 没有达到64mb不会重写)

 appendfsync always 每一次 写入 修改Key都会同步
 appendfsync everysec  每一秒钟执行一次 存储   默认使用
 appendfsync no  都不会同步
 开启后需要重启

AOF文件体积问题

Redis提供了一种重写机制,当大小超过阈值后,会自动进行一次压缩。

在客户端执行 bgrewriteaof 会手动重写。

AOF特点

  1. 同步频率快

  2. 文件较大

  3. 性能消耗较高(高并发下AOF要好于Redis)

备注:

AOF与RDB可以同时开启。

Redis Pipeline

批量执行,效率高。没有连接、释放耗时操作。

通过队列将命令缓存起来,一次性的在一个连接中发送给服务器执行。

因为会缓存命令,所以不要设置太大。

Jedis限值缓存命令大小为8192字节(受TCP包的大小限制不一定能达到),到达后会自动发送,收到返回后会存储在客户端的接收缓冲区,客户端缓冲区满之后,会放在服务器的输出缓冲区。

Redis 主从复制配置

主从配置原因。

  1. 性能

  2. 扩展 水平扩容

  3. 可用性 防止单点故障

通过配置文件来配置

slaveof IP PORT 在子节点配置文件 配置主节点 (主节点无需配置)
replicaof IP PORT (哨兵末日切换主从会自动修改为 replicaof )

通过客户端指令来配置

./redis-server --slaveof ip port

slaveof no one 取消主从配置

info replication 查看节点详情

特点

主节点才能执行修改,写入命令。从节点只能执行读取。

原理

链接阶段

子节点会自动保存主节点的IP端口,有定时任务去查看有没有新的主节点需要链接,有的话会建立Socket网络链接。连接成功后,会创建文件事件处理器,来执行数据同步。

数据同步阶段(初始化同步)

主节点会通过bgsave 命令生成RDB快照文件,并将文件发送给子节点做数据同步。

  1. 如果链接主节点前,Slave节点有数据,会自动清空。

  2. 如果Redis主节点数据量比较大,生成RDB文件时间较长,在这个过程中有其他命令执行。主节点会将生成RDB文件期间产生的数据命令缓存起来,等子节点保存完RDB文件数据后再传给子节点。

命令传播阶段

如果因为网络导致子节点与主节点断开一段时间,这段时间的数据如何处理?

Redis提供了偏移量来记录、确定数据同步的阶段,重新连接后把相差阶段

总结

主从复制可以解决性能,和数据备份以及高可用问题。但是还有一定的不足。

  1. 当主节点数据量很大时,同步比较耗时

  2. 无法自动切换主从节点,当主节点挂掉后,因为从节点无法写入,修改数据,会影响到服务使用(只能通过手动切换)。

Redis Sentinel

运行一个监控程序(哨兵节点),监控Redis主从节点状态。

客户端先连接Sentinel拿到master的ip,端口再进行数据操作。

1607431899787.png

配置解析

daemonize yes
port 26379
protected-mode no
dir "/usr/local/soft/redis-6.0.9/sentinel-tmp"
sentinel monitor redis-master 192.168.44.186 6379 2
sentinel down-after-milliseconds redis-master 30000
同一个master两次failover 的时间间隔
sentinel failover-timeout redis-master 180000

sentinel parallel-syncs redis-master 1
down-after-milliseconds 超过多久没有收到回复 则判定为主观下线
发生故障转移时同时有几个slave 同时对master进行同步

如何知道服务下限

判断方式分为两种,主观下限与客观下限

每一秒钟ping一下客户端,如果超过 一定时间未回复就判定为主观下线。如果一个master节点被标记为主观下线,会发起一个询问。如果超过一半的哨兵节点认为下线,则判定为客观下线。启动故障转移。

下限处理

Sentinel 选举出Leader(Raft算法,先到先得,少数服从多数)执行故障转移。

如何选取从节点成为主节点受几个因素影响。

  1. 端口连接的时长(如果某节点与哨兵节点断开的时长较长则失去资格)

  2. 优先级(可以在redis.conf进行配置 replica-priority 100)

  3. offset(偏移量) 从主节点复制数据的完整性

  4. 进程id最小的

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容