chaoz的杂货铺

生命有息、学无止境、折腾不止

0%

Redis-入门笔记

八个特性

速度快

数据存在内存上
用 C 语言写的
线程模型是单线程

持久化

断电不丢数据
所有数据保存在内存中,对数据的更新将异步地保存到磁盘中

多种数据结构

图一

其他:

BitMaps:位图
HyperLogLog:超小内存唯一数值
GEO:地理信息定位

支持多种编程语言

功能丰富

发布订阅

事务

Lua 脚本

pipeline

简单

只有 23000 行 C 代码:单机的

不依赖外部库

单线程模型

主从复制

高可用、分布式

高可用、分布式

Redis-Sentinel(v2.8)支持高可用

Redis-Cluster(v3.0)支持分布式

应用场景

缓存系统

图二

计数器

图三

消息队列系统

图四

排行榜

社交网络

粉丝数、关注数、共同关注

实时系统

垃圾邮件过滤

redis 安装

安装、可执行文件说明、三种启动方法、简单的客户端连接

redis-server RRedis服务器
redis-cli redis 命令行客户端
redis-benchmark redis 性能测试工具
redis-check-aof AOF文件修复工具
redis-check-dump RDB文件检查工具
redis-sentinel Sentinel服务器(2.8以后)

三种启动方法:

最简启动

动态参数启动
redis-server –port 6380

配置文件启动
redis-server configPath

三种启动方式比较:
生成环境选择配置启动
单机多实例配置文件可以用端口区分开

redis 客户端链接
redis-cli -h 10.10.19.150 -p 6384
10.10.79.150:6384> ping
PONG
10.10.79.150:6384> set hello world
“OK”
10.10.79.150:6384>get hello
“world”

redis 客户端返回值
状态回复
错误回复
整数回复
字符串回复
多行字符串回复

验证是否启动

ps -ef | grep redis
netstat -antpl | grep redis
redis-cli -h ip -p port ping

redis 常用配置:
daemonize:是否守护进程
port:redis 对外端口
logfile:redis 系统日志
dir:redis 工作目录
RDB config
AOF config
slow Log config
maxMemory

通用命令

通用命令

keys

dbsize

exists key

del key [key ….]

expire key seconds :key在secends卖弄之后过期
ttl key :查看key剩余的过期时间
persist key :去掉key的过期时间

返回值 0 -1:代表key存在,并且没有过期时间 -2:代表不存在了

type key :返回 key 的类型
string、hash、list、set、zset、none

incr key:key自增1,如果key不存在,自增后get(key)=1 O(1)
decr key:key自减1,如果key不存在,自减后get(key)=1 O(1)
incrby key k:key自增k,如果key不存在,自增后get(key)=k O(1)
decr key k:key自减k,如果key不存在,自减后get(key)=k O(1)

set key value : 不管 key 是否存在,都设置 O(1)
setnx key value :key 不存在,才设置 O(1)
set key value xx : key存在,才设置 O(1)

mget key1 key2 key3 ….. O(n)
mset key1 value1 key2 value2 key3 value3 O(n)
n 次 get = n 次网络时间 + n 次命令时间;这里用 mget 的话能省去大量的时间

getset key newvalue : set key newvalue 并返回旧的 value O(1)
append key value : 将 value 追加到旧的 value O(1)
strlen key 返回字符串的长度(注意中文) O(1)

incrbyfloat key 3.5 : 增加 key 对应的值3.5
getrange key start end : 获取字符串指定下标所有的值
setrange key index value : 设置指定下标所有对应的值

时间复杂度

图五

数据结构和内部编码

图六

redisObject
图七

单线程

一瞬间只执行一个命令

为什么还是快:
纯内存;非阻塞 IO;避免线程切换和静态消耗

使用单线程时要注意什么:
一次只能用一条命令;
拒绝长命令:在应用中,高可用别这么用,会卡导致超时

字符串键值结构

图八

字符串总结

图九

redis Api 的使用和理解

哈希:

特点
重要 API

hash vs string

查缺补漏

图十
图11

hget key field : 获取 hash key 对应的 file 的 value O(1)
hset key field value :设置 hash key 对应的 value O(1)
hdel key field : 删除 hash key 对应 field 的 value O(1)

hexists key field : 判断 hash key 是否有 field O(1)
hlen key : 获取 hash key field 的数量 O(1)

hmget key field1 field2 … fieldN : 批量获取 hash key 的一批 field 对应的值 O(n)
hmset key field1 value1 field2 value2 … fieldN valueN O(n)

实战

hincrby user:1:info pageview count

hgetall key : 返回 hash key 对应所有的 field 和 value O(n)
hvals key :返回 hash key 对应所有 field 的 value O(n)
hkeys key : 返回 hash key 对应所有 field O(n)

小心使用 hgetall ,牢记单线程,会比较慢

如何更新用户属性?
string 实现2种,hash

图十二

列表结构:
有序、可以重复、数据结构一样左右两边插入弹出

rpush key value1 value2 … valueN : 从列表右端插入 O(1~n)
lpush key value1 value2 … valueN : 从列表左端插入 O(1~n)

linsert key before|after value newvalue : 在 list 指定的值前|后插入newvalue O(n)

lpop key : 从列表左侧弹出一个item O(1)
rpop key : 从列表右侧弹出一个item O(1)

lrem key count value : 根据 count 值,从列表中删除所有value相等的项 O(n)
(1)count>0,从左到右,删除最多count个value相等的项
(2)count<0,从右到左,删除最多Math.abs(count)个value相等的项
(3)count=0,删除所有value相等的项

ltrim key start end : 按照索引范围修剪列表 O(n)
lrange key start end (包含end) : 获取列表指定索引范围所有item O(n)
lindex key index : 获取列表指定索引的item O(n)
llen key : 获取列表长度
lset lset key index newvalue : 设置列表指定索引值为 newvalue O(n)

blpop key timeout : lpop 阻塞版本,timeout 时阻塞超时时间,timout=0为永远不阻塞。 O(1)
brpop key timeout : rpop 阻塞版本,timeout 时阻塞超时时间,timout=0为永远不阻塞。 O(1)

TIPS
1、LRUSH + LPOP = Stack
2、LPUSH + RPOP =Queue
3、LPUSH + LTRIM =Capped Collection
4、LPUSH + BRPOP = Message Queue

sadd key element : 向集合 key 添加 element (如果 element 已经存在,添加失败)
srem key element : 将集合key中的element移除掉

scard user:1:follow = 4 :计算集合大小
sismember user:1follow it = 1 : 判断it是否在集合中
srandmember user:1:follow count = his :从集合中随机挑 count 个元素 不改变
spop user:1:follow = sports :从集合中随机弹出一个元素 改变原来的
smember user:1:follow = music his sports it :获取集合所有元素 无序的,小心使用

集合间 API

sdiff user:1:follow user:2:follow = music his : 差集
sinter user:1:follow user:2:follow = it sports : 交集
sunion user:1:follow user:2:follow = it music his sports news ent : 并集
sdiff|sinter|suion + store destkey .. 将差集、交集、并集结果保存在destkey中

有序集合:
无重复元素、有序
api 都是以 z 开头
zadd key score element(可以是多对) : 添加score和element O(logN)
zrem key element(可以是多个) : 删除元素 O(1)
zscore key element : 返回元素的分数

zincrby key increScore element : 增加或者减少元素分数 O(1)
zcard key : 返回元素总个数 O(1)

zrange key start end [WITHSCORES] : 返回指定索引范围内的升序元素[分值] o(log(n)+m)
zrangebyscore key minScore maxScore [WITHSCORES] : 返回指定分数范围内的升序元素[分值] o(log(n)+m)
zcount key minScore maxScore ;返回有序集合内在指定分数范围内的个数 o(log(n)+m)

zremrangebyrank key start end : 删除指定排名内的升序元素 o(log(n)+m)

zrevrank
zrevrange
zrevrangebyscore
zinterstore
zunionstore

有序集合总结图十三

redis 客户端

java 客户端 :Jedis

直连:

连接池:

问题:池子里有多少个连接合适呢

两种方案对比:

图十四

python 客户端 :redis-py

瑞士军刀 redis

慢查询

生命周期

图十五

注:慢查询发生在第三阶段;客户端超时不一定慢查询,但慢查询是客户端超时的一个可能因素。

两个配置

slowlog-max-len

1、先进先出队列
2、固定长度
3、保存在内存中

slowlog-log-slower-than

1、慢查询阈值(单位:微秒)
2、slowlog-log-slower-than = 0,记录所有命令
3、slowlog-log-slower-than < 0,不记录任何命令

配置方法:

1、默认值:
config get slowlog-max-len = 128
config get slowlog-log-slower-then = 10000

2、修改配置文件重启

3、动态配置

config set slower-max-len 1000
config set slowlog-log-slower-than 1000

三个命令

1、slowlog get [n]:获取慢查询队列 n 条
2、slowlog len : 获取慢查询队列长度
3、slowlog reset : 清空慢查询队列

运维经验

1、slowlog-max-len 不要设置太大,默认10ms,通常设置1ms
2、slowlog-log-slower-than不要设置过小,通常设置1000左右
3、理解命令生命周期
4、定期持续化慢查询

pipeline

什么是流水线

将一批命令进行打包并进行计算,然后将结果返回。类似 m*** 操作

与原生操作对比

一个是原子命令,一个是非原子的命令进行拆分。

客户端实现

使用建议

1、注意每次 pipeline 携带数据量
2、pipeline 每次只能作用在一个redis节点上
3、M操作与pipeline区别

发布订阅

角色

  • 发布者

  • 频道

  • 订阅者

模型

图十六

API

  • publish 发布命令

publish channel message

  • subscribe

subscribe [channel] : 一个或者多个

  • unsubscribe

unsubscribe [channel] : 取消订阅 一个或者多个

  • 其他

1、psubscribe [pattern …] 订阅模式
2、punsubscribe [pattern …] 退订指定模式
3、pubsub channels 列出至少有一个订阅者的频道
4、pubsub numsub [channel …] 列出给定频道的订阅者数量
5、pubsub numpat 列出被订阅模式的数量

消息队列

图十七

发布订阅总结

1、发布订阅模式中的角色
2、重要的API
3、消息队列和发布订阅

Bitmap

位图

图十八

相关命令

setbit key offset value :给位图指定索引设置值

没看明白

getbit key offset : 获取位图指定索引的值

bitcount key [start end] : 获取位图指定范围(start到end,单位为字节,如果不指定就是获取全部)位置为1的个数。

bitop op destkey key [key …]
做多个 Bitmap 的and(交集)、or(并集)、not(非)、xor(异或)操作并将结果保存在destkey中。

bitpos key targetBit [start][end]
计算位图指定范围(start到end,单位为字节,如果不指定就是获取全部)第一个偏移量对应的值等于targetBit的位置

独立用户统计

图十九

没看懂

使用经验

1、type = string 最大512M
2、注意setbit时的偏移量,可能有较大耗时
3、位图不是绝对好

HyperlogLog

新的数据结构?

算法:极小的空间来完成独立数量统计

内存消耗

图二十

三个命令

1、pfadd key element [element …] : 向HyperlogLog添加元素
2、pfcount key [key …] : 计算 HyperlogLog 的独立总数
3、prmerge destkey sourcekey [sourcekey …] : 合并多个HyperlogLog

使用经验

1、是否能容忍错误?(错误率 : 0.81%)

2、是否需要单条数据

GEO

是什么?

地理信息定位: 存储经纬度、计算两地距离、范围计算等

相关命令

geo key longitude latitude member [longitude latitude member …] 增加地理位置信息

geopos key member [member …] : 获取地理位置信息

geodist key member1 member2 [unit] : 获取两个地理位置的距离 m米、km、mi英里、ft尺

georadius图二十

相关说明

1、since 3.2
2、type geoKey = zset

持久化的取舍和选择

持续化作用

什么是持久化

redis 数据保存在内存中,同时将数据的更新异步的保存到磁盘上

持久化的实现方式

快照:mysql dump ; redis rdb

写日志 : mysql binlog ; hbase hlog ;redis aof

RDB

什么是 RDB

RDB 文件 是一个二进制文件,存储在硬盘中,内存写入磁盘,重启从磁盘载入恢复,以及主从方式的媒介。

触发机制-主要三种方式

同步、异步、自动。

save 命令

bgsave 命令 : 子进程用来生成RDB文件,不会出现阻塞

自动生成 : 满足一定条件,就去写一个RDB文件

配置:

dbfilename dump-${port}.rdb
dir /bigdiskpath
stop-write-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

触发机制-不容忽视方式

1、全量复制

2、debug reload 不清内存的重启

3、shutdown

RDB 总结

1、RDB 是 Redis 内存到硬盘的快照,用于持久化
2、sava通常会阻塞Redis
3、bgsave 不会阻塞Redis,但是会fork新进程
4、save 自动配置满足人亦就会被执行
5、有些触发机制不容忽视

redis 配置文件说明

AOF

RDB 现存的问题

耗时、耗性能:O(n)数据,耗时;fork 消耗内存,copy-on-write 策略;Disk I/O

什么是 AOF

AOF 文件 就像是日志,宕机能够恢复。

AOF 三种策略

always :写命令刷新到缓冲区,然后每天命令都会写道AOF文件中
everysec : 每秒进行刷新,每秒写道缓冲区再到AOF文件,可能存在宕机丢失1s的命令;高写入量可保护磁盘。
no : 根据操作系统来,不可控,不用管

AOF 重写

作用:

减少磁盘占用量;
加速恢复速度;

两种方式:

bgrewriteaof 命令:

AOF 重写配置:

auto-aof-rewrite-min-size : AOF 文件重写需要的尺寸
auto-aof-rewrite-percentage : AOF 文件增长率

aof_current_size : AOF 当前尺寸(单位:字节)
aof_base_size : AOF 上次启动和重写的尺寸(单位:字节)

AOF 重写流程 图 21

配置说明:

RDB 和 AOF 的抉择

图 22

开发运维常见问题

fork 操作

同步操作

与内存量息息相关:内存越大,耗时越长(与机器类型有关)

info:latest_fork_usec : 查持久化的时间

改善 fork :

1、优先使用物理机或者高效支持fork操作的虚拟化技术
2、控制redis实例最大可用内存:maxmemory
3、合理配置Linux内存分配策略:vm.overcommit_memery=1
4、降低fork频率:例如放宽AOF重写自动触发时机,不必要的全量复制

进程外开销

1、CPU

  • 开销:RDB和AOF文件生成,属于CPU密集型
  • 优化:不做CPU绑定,不和CPU密集型部署

2、内存

  • 开销:fork内存开销,copy-on-write
  • 优化: echo never > /sys/kernel/mem/transparent_hugepage/enabled

3、硬盘

  • 开销:AOF和RDB文件写入,可以结合iostst,iotop分析

硬盘优化:
1、不要和高硬盘负载服务部署一起:存储服务、消息队列服务
2、no-appendfsync-on-rewrite = yes
3、根据写入量决定磁盘类型:例如ssd

AOF 追加阻塞

AOF 阻塞定位:

Redis 复制的原理与 优化

什么是主从复制

单机有什么问题:机器故障~容量瓶颈,QPS瓶颈

主从复制作用:数据副本,拓展性能。

一个master可以有多个slave
一个slave只能有一个master

复制的配置

命令实现:slaveof ip port
取消主从命令:slaveof no one

可以子啊配置中修改添加

slaveof ip port
slave-read-only yes : 只读操作

命令方式:无需重启,不便于管理
配置方式:统一配置,需要重启

全量复制和部分复制

全量复制 图 23

全量复制开销:
1、bgsave时间
2、RDB文件网络传输时间
3、从节点清空数据时间
4、从节点加载RDB的时间
5、可能的AOF重写时间

部分复制 图 24

故障处理

slave 故障

master 故障

开发运维常见问题

1、读写分离

把都流量分给 从节点

问题:复制数据的延迟;读到过期的数据,从节点故障

2、主从配置不一致

问题:例如 maxmemory 不一致:丢失数据;例如数据结构优化参数(例如hash-max-ziplist-entries):内存不一致

3、规避全量复制

问题:第一次全量复制,第一次不可避免,小主节点、低峰;节点运行id不匹配,主节点重启,运行id会变化,导致来一次全量复制,故障转移,例如哨兵或者集群;复制积压缓冲区不足:网络中断,部分复制无法满足,增大复制缓冲区配置rel_backlog_size,网络”增强”。

4、规避复制风暴

问题:单节点复制风暴,主节点重启,多从节点复制:解决:更换复制拓扑结构,如树形结构等;单节点复制风暴:机器宕机后,大量全量复制:解决:主节点分散多机器,或者一个高可用的架构。

Redis Sentinel

主从复制高可用

备份、分流;出现问题,故障转移~

手动故障转移:

写能力和存储能力的限制:

架构说明

Redis Sentinel 架构

图23

故障转移 图24

安装配置

1、配置开启主从节点
2、配置开启sentinel监控主节点。(sentinel是特殊的redis)
3、实际应该多机器
4、详细配置节点

主从节点、sentinel的配置说明

客户端链接

实现原理

三个定时任务:
1、每10s每个sentinel对master和slave执行info:发现slave节点,确认主从节点。
2、每2s每个sentinel通过master节点的channel交换信息(pub/sub):通过sentinel:hello 频道交互,交互对节点的“看法”和自身信息。
3、每1s每个sentinel对其他sentinel和redis执行ping。心跳检测

主观下线和客观下线

图25

领导者选举

图26

故障转移(sentinel 领导者节点完成)
图27

选择合适的slave节点

图28

常见开发运维问题

节点运维:

节点下线:
机器下线:过保问题,机器性能问题,节点自身问题

sentinel failover

从节点:临时下线还是永久下线,读写分离等情况考虑。

节点上线:
主节点:sentinel failover 进行替换
从节点:slaveof即可,sentinel节点可以感知
sentinel节点:参考其他sentinel节点启动即可

高可用读写分离

从节点作用:
副本:高可用基础
拓展:读能力

三个“消息”

  • switch-master: 切换主节点(从节点晋升主节点)
  • convert-to-slave : 切换从节点(原主节点降为从节点)
  • sdown : 主管下线

Redis Cluster

呼唤集群

为什么呼唤:1.并发量;2。数据量

配置更强悍的机器

分布式:简单的认为加机器。

集群:规模化需求,并发量:OPS 数据量:“大数据”

数据分布

顺序分区:

哈希分区:(例如节点取模、一次性哈希分区、虚拟槽分区)

节点取余:hash(key)%nodes PS:容量变化,会造成数据进行偏移
客户端分片:哈希+取余
节点伸缩:数据节点关系变化,导致数据迁移
迁移数量和添加节点数量有关:建议翻倍扩容

一致性hash: PS:扩容的话影响很低
客户端分片:哈希+顺时针(优化取余)
节点伸缩:只影响临近节点,但是还是有数据迁移
翻倍伸缩:保证最小迁移数据和负载均衡

虚拟槽分区:
预设虚拟槽:每个槽映射一个数据子集,一版比节点数大
良好的哈希函数:例如CRC16
服务端管理节点、槽数据:例如 Redis Cluster

对比:

图29

搭建集群

Redis Cluster 架构:节点、meet、指派槽、复制

所有节点共享消息

特性:复制、高可用、分片

Redis Cluster 安装:原生命令安装、官方工具安装
配置:
开启节点: 配置里 cluster-enabled yes ;cluster-config-file nodes-${port}.conf
Redis-server redis-7000.conf
meet (节点之际去哪通信):cluster meet ip port
配置槽 : cluster addslots slot [slot …]
主从配置 : cluster replicate node-id

集群伸缩

伸缩原理

集群伸缩=槽和数据在节点之间的移动

扩容集群:准备新节点、加入集群、迁移槽和数据

准备新节点:
集群模式;配置和其他节点统一;启动后是孤儿节点;

加入集群:
作用:为它迁移槽和数据实现扩容;作为从节点负责故障转移
redis-trib.rb : 使用 rb 能够避免新节点已经加入了其他集群,造成故障。
rb 的工作原理、过程:

迁移槽和数据:

  • 槽迁移计划:
  • 迁移数据:
  • 添加从节点:

迁移数据:

30

31

收缩集群

下线迁移槽;
忘记节点;cluster forget {id}
关闭节点。

客户端路由

moved 从定向

图31

图32

图33

ask 重定向

图34

图35

moved 和 ask 区别:两者都是客户单重定向;moved:槽已确定迁移;ask:槽还在迁移中。

smart 客户端

实现原理:追求性能。
1、从集群中选一个可运行节点,使用cluster slots 初始化槽和节点映射
2、将cluster slots 的结果映射到本地,为每一个节点创建JedisPool
3、准备执行命令

图36

使用方法:对应的一个 java 客户端

简单案例、整合到spring、多节点命令实现、如何实现批量操作

批量操作如何让实现:

1、串行mget : for 循环遍历所有key
2、串行IO :在客户端对key进行内聚,根据节点分组,通过pipeline执行。
3、并行IO: 同上,但是是并行的执行多个pipeline
4、hash_tag : 对key进行包装,mget(hash_key)

对比:

图37

故障转移

故障发现
1、通过ping/pong消息实现故障发现:不需要sentinel
2、主观下线和客观下线

主观下线:

图38

客观下线:

图39

尝试客观下线:

图40

故障恢复

资格检查:

每个从节点检查与故障主节点的断线时间;超过cluster-node-timeout * cluster-slave-validity-factor 取消资格;cluster-slave-validity-factor : 默认是10

准备选举时间:

图41

选举投票:

图42

替换主节点:

图43

故障转移演练

Redis Cluster 开发运维常见问题

集群完整性

  • cluster-require-full-coverage 默认是 yes

    • 集群中16384个槽全部可用:保证集群完整性
    • 节点故障或者正在故障转移:(error)CLUSTERDOWN the cluster is down
  • 大多数业务无法容忍,cluster-require-full-coverage 建议设置为no

宽带消耗

官方建议:不超过1000个节点
ping/pong信息
不容忽视的宽带消耗

三个方面:
消息发送频率:节点发现与与其他节点最后通信时间超过cluster-node-timeout/2时会直接发送ping消息
消息数据量:slots 槽数组(2KB空间)和整个集群1/10的状态数据(10个节点状态数据约1KB)
节点部署的机器规模:集群分布的机器越多且每台机器划分的节点数越均匀,则集群内整体的可用宽带越高

一个例子:

  • 规模:200个节点、20台物理机(每台10个节点)
  • cluster-node-timeout = 15000 ,ping/pong 宽带为25Mb
  • cluster-node-timeout=20000,ping/pong宽带低于15Mb

优化:

避免“大”集群:避免多业务使用一个集群,大业务可以多集群。
cluster-node-timeout: 宽带和故障转移速度的均衡
尽量均匀分配到多机器上:保证高可用和宽带

pub/sub 广播

问题:publish 在集群每个节点广播:加重宽带
解决:单独“走”一套Redis Sentinel

数据倾斜

  • 数据倾斜:内存不均匀

1、节点和槽分配不均匀
redis-trib.rb info ip:port 查看节点、槽、键值分布
redis-trib.rb rebalance ip:port 进行均衡(谨慎使用)

2、不同槽对应键值数量差异较大
CRC16正常情况下比较均匀
可能存在hash_tag
cluster countkeysinslot {slot}获取槽对应键值个数

3、包含bigkey
bigkey:例如大的字符串、几百万的元素的hash、set等
从节点:redis-cli –bigkeys
优化:优化数据结构

4、内存相关配置不一致
hash-max-ziplist-value、set-max-inset-entries等
优化:定期“检查”配置一致性

  • 请求倾斜:热点

1、热点 key:重要的 key 或者 bigkey
优化:
避免 bigkey
热键不要用 hash__tag
当一致性不高时,可以用本地缓存 + MQ

读写分离

1、只读链接:集群模式的从节点不接受任何读写请求

重定向到负责槽的主节点
readonly命令可以读:连接级别命令

2、读写分离:更佳复杂
同样的问题:复制延迟、读取过期数据、从节点故障
修改客户端:cluster slaver {nodeId}

数据迁移

1、官方迁移工具:redis-trib.rb import
只能从单机迁移到集群
不支持在线迁移:source需要停写
不支持断点续传
单线程迁移:影响速度

2、在线迁移
唯品会:redis-migrate-tool
豌豆荚:redis-port

集群 VS 单机

1、集群限制:key 批量操作支持有限:例如mget、mset必须在一个slot
2、Key事务和Lua支持有限:操作的key必须在一个节点上
3、key是数据分区的最小粒度:不支持bigkey分区
4、不支持多个数据库:集群模式下只有一个db 0
5、复制只支持一层:不支持树形复制结构

思考:redis分布式不一定是好的
1、redis cluster :满足容量和性能的拓展性,很多业务“不需要”。
大多数时客户端性能会“降低”
命令无法跨节点使用:mget、keys、scan、flush、sinter等
lua和事务无法跨节点使用
客户端维护更复杂:SDK和应用本身消耗(例如更多的连接池)

2、很多场景redis sentinel 已经足够好

集群总结

图44

图45

缓存

缓存的使用与设计

缓存的受益与成本

受益:
1、加速读写
2、降低后端负载

成本
1、数据不一致性
2、代码维护成本:多了一层缓存逻辑
3、运维成本

使用场景
1、降低后端负载
2、加速请求响应 :优化IO响应时间
3、大量写合并为批量写 :计数器先Redis累加再批量写DB

缓存更新策略

1、LRU/LFU/FIFO算法剔除:例如maxmemory-policy 一致性最差,维护成本低
2、超时剔除:例如expire 一致性较差,维护成本低
3、主动更新:开发控制生命周期 一致性强,维护成本高

建议:
1、低一致性:最大内存和淘汰策略
2、高一致性:超时剔除和主动更新结合,最大内存和淘汰策略兜底。

缓存粒度控制

图46

控制的三个角度:
1、通用性:全量属性最好
2、占用空间:部分属性更好
3、代码维护、表面上全量属性更好

缓存透彻优化

问题:大量请求不命中

原因:
1、业务代码自身问题
2、恶意攻击、爬虫等等

如何发现:

1、业务的相应时间
2、业务本身问题
3、相关指标:总调用数

解决方法:
1、缓存空对象 ????

  • 需要更多的键
  • 缓存层和存储层数据“短期”不一致

2、布隆过滤器拦截 ????

无底洞问题优化

问题:加机器性能没能提升反而下降了。(量太大)

问题关键点:
更多的机器不等于更高的性能
批量接口需求
数据增长和水平拓展需求

优化IO方法:
1、命令本身优化:慢查询、hgetall bigkey
2、减少网络通信次数
3、降低接口成本:例如客户端长连接/连接池、NIO等。

4种批量优化的方法:
1、串行mget
2、串行IO
3、并行IO
4、hash_tag

缓存雪崩问题

热点key重建优化

问题描述:热点key + 较长的重建时间

图47

三个目标和两个解决:
1、三个目标
减少重缓存的次数
数据尽可能一致
减少潜在危险

2、两个解决
互斥锁
图48
永远不过期
缓存层面:没有设置过期时间(没有用expire)
功能层面:为每一个value添加逻辑过期时间,单发现超过逻辑过期时间后,会使用单独的线程去构建缓存。
图49

图50

总结

图51
图52

Redis 云平台 Cachcloud

Redis 规模化运维

遇到的问题:
发布构建繁琐,私搭乱盖
节点&机器等运维成本
监控报警初级

使用场景:
1、全量视频缓存(视频播放API):跨机房高可用
2、消息队列同步(RedisMQ中间件)
3、分布式布隆过滤器(百万QPS)
4、技术系统:计数(播放值)
5、其他:排行榜、社交(直播、实时计算(反作弊)等)

CacheCloud

1、一键开启 Redis
2、机器、应用、实例监控和报警
3、客户端:透明使用、性能上报
4、可视化运维:配置、扩容、Failover、机器/应用/实例上下线
5、已经存在redis直接接入和数据迁移

快速构建

机器部署

应用接入

用户功能

运维功能

总结

1、Redis 初识:单机安装部署(版本选择),边界(使用场景)
2、API理解和使用:单线程、5种数据结构使用和选择
3、Redis客户端使用:jedis、redis-py等,客户端很“简单”。
4、瑞士军刀Redis:慢查询、pipeline、发布订阅、bitmap等
5、Redis 持久化:RDB和AOF的优缺点和最佳实践
6、Redis复制:配置方法、全量和部分复制、常见运维
7、Redis Sentinel : 高可用、架构、“新”的客户端、基本原理
8、Redis Cluster : 数据分布、架构、安装部署、扩容、客户端、常见问题
9、缓存设计与优化:粒度、更新策略、无底洞问题、穿透、雪崩、热点key
10、CacheCloud : 平台化Redis开发运维工具

喜欢这篇文章?打赏一下作者吧!

欢迎关注我的其它发布渠道