Redis 开发与运维(付磊_张益军)学习笔记

Redis 学习笔记

Redis特性

Redis可以做什么

缓存;排行榜系统;计数器应用;社交网络:点赞,喜好,推送;消息队列。

Redis为什么这么快

1.通过内存访问数据
2.采用非阻塞IO,不在网络IO上浪费过多时间
3.单线程避免了线程切换和多线程竞争资源的问题

Redis与Memcahce比较

1.Redis为单线程系统,memcache为多线程
2.Redis支持持久化,memcache不支持
3.Redis天然支持主从复制,memcache需要自己实现
4.Redis内存分配临时申请空间,存在碎片;memcache使用预分配内存池的方法,可以省去内存分配的空间
5.数据量大时redis会通过swap把冷数据读到硬盘中,mencache不会
6.Redis的数据类型比mencache多,因此应用场景更广
终上所诉:追求高可用,项目业务比较复杂时建议用redis,追求读写速度用memcahce

Redis 数据类型与API

redis数据类型与内部编码

Redis 开发与运维(付磊_张益军)学习笔记

字符串

字符串类型的实际值可以是字符串,数字(整数,浮点),二进制图片,但最大值不超过512MB

常用命令

1.设置值:set key value [ex seconds] [px milliseconds] [nx|xx]
ex seconds:设置秒级过期时间(对应快捷键setex)
px milliseconds:设置毫秒级过期时间
nx:key不存在才设置成功(对应快捷键setnx)
xx:key存在才设置成功
2.批量设置值:mset key value [key value …]
3.获取值:get key
4.批量获取值:mget key [key …]
5.计数:incr key
值需要是整数,否则返回错误
每次操作自增+1
Key不存在按照值为0自增,返回1

内部编码

int:8个字节的长整型
embstr:小于等于39个字节的字符串
raw:大于39个字节的字符串

哈希

类似map或者对象的结构,适合存储对象信息

常用命令

1.设置值:hset key field value
2.获取值:hget key field
3.删除field:hdel key field
4.计算filed个数:hlen key
5.批量设置:hmget key field [key field …]
6.批量获取: hmget key field [field …]
7.判断field是否存在:hexists key field
8.获取所有field: hkeys key
9.获取所有value:hvals key
10.获取所有field-value:hgetall key

内部编码

当元素个数小于hash-max-ziplist-entries(默认512个),所有值小于hash-ziplist-value(默认64字节)时,使用ziplist,否则用hashtable;ziplist内存小,hashtable读写速度快

列表

可以用来存储多个字符串,列表最多存储2^32-1个元素;
使用场景:lpush+lpop=栈,lpush+rpop=队列,lpush+ltrim=有限集合,lpush+brpop = 消息队列。

常用命令

1.从右边插入元素:rpush key value [value …]
2.从左边插入元素:lpush key value [value …]
3.向某个元素前面或者后买插入元素:linsert key before|after pivot value
4.查找指定范围的元素: lrange key start end
5.获取指定下标的元素:lindex key index
6.获取列表长度:llen key
7.从左侧删除元素:lpop key
8.从右侧删除元素:rpop key
9.删除指定元素:lrem key count value
count>0从左到右删除count个元素
count<0从右到左删除count个元素
Conut=0删除所有
10.按照索引范围删除:ltrim key start end
11.修改指定下标元素:lset key index newValue
12.阻塞式弹出:blpop|brpop key [key …] timeout
timeout为阻塞时间,单位秒,为0时如果无对应数据会一直阻塞可用于实现消息队列

集合

可以保存多个字符串对象,与列表区别在于集合为无序的不能通过下标查询元素,集合不允许有重复对象;
使用场景:sadd = 标签,spop/srandmember = 生成随机数,sadd+sinter = 社交需求

常用命令

1.添加元素:sadd key element [element …]
2.删除元素:srem key element [element …]
3.计算元素个数:scard key
4.判断元素是否在集合中: sismember key element
5.随机返回指定个数元素:srandmember key [count]
默认为1个
6.从集合中随机弹出一个元素:spop key
弹出后集合元素会减少
7.获取所有元素:smembers key
8.求集合交集:sinter key [key …]
9.求集合差集:sdiff key [key …]
10.求集合并集:suinon key [key …]
11.保存交集,差集,并集结果:sinterstore|suionstore|sdiffstore destion key [key …]
其中destion 为新集合的key

内部编码

当元素数量小于set-max-inset-entries(默认512个)时用inset否则用hashtable

有序集合

有序集合与集合类似,区别在于给每个元素增加了一个分数,做为排序的依据。
使用场景:zadd+zincrby = 排行榜系统

常用命令

1.添加成员:zadd key score member [score member]
2.计算成员个数:zcard key
3.计算某个成员的分数:zscore key member
4.计算成员的排名从低到高:zrank key member
5.计算成员的排名从高到低:zrevrank key member
6.删除成员:zrem key member
7.增加成员分数:zincrby key increment member
increment 为增加的分值
8.返回指定排名范围的成员从低到高:zrange key start end [withsorce]
9.返回指定排名范围的成员从高到低:zrevrange key start end [withsorce]
10.返回指定分数范围的成员从低到高:zrangebyscore key min max [withsorce]
min取-inf代表无限小,max 取+inf代表无限大
11.返回指定分数范围的成员从高到低:zrevrangebyscore key min max [withsorce]
12.删除指定排名的升序元素:zremrangebyrank key start end
13.删除指定分数范围的成员:zremrangebyscore key min max
14.交集:zinterstroe destination numkeys key [key …] [weights weight [weight …]] [aggregate sum|min|max]
numkeys:需要做交集的个数
weights weight 每个键的权重
Aggregate sum|min|max 交集后分值汇总方式
15.并集:zuniontroe destination numkeys key [key …] [weights weight [weight …]] [aggregate sum|min|max]

内部编码

当元素个数小于zset-max-ziplist-entries(默认128个),同时zset-max-ziplist-value(默认64)时用ziplist否则用skiplist(跳表)

键管理

1.删除键:del key
2.重命名:rename key newkey
3.随机返回一个键:randomkey
4.设置键在seconds秒后过期: expire key seconds
5.键在秒级时间戳timestamp后过期:expireat key timestamp
6.遍历键:keys pattern
7.渐进式遍历键: scan cursor [match pattern] [count number]
cursor 为上一个游标,从0开始,每次遍历产生新的cursor,遍历完所有键后cursor返回0
match pattern 匹配参数
count number 每次遍历个数
渐进式相比普通遍历,不会造成阻塞,但是在遍历时如果键有变化不保证能遍历所有键
8.清除所在数据库数据所有的键:flushdb
9.清除所有的键:flushall

info 命令详解

server

一般 Redis 服务器信息,包含以下域:
redis_version : Redis 服务器版本
redis_git_sha1 : Git SHA1
redis_git_dirty : Git dirty flag
os : Redis 服务器的宿主操作系统
arch_bits : 架构(32 或 64 位)
multiplexing_api : Redis 所使用的事件处理机制
gcc_version : 编译 Redis 时所使用的 GCC 版本
process_id : 服务器进程的 PID
run_id : Redis 服务器的随机标识符(用于 Sentinel 和集群)
tcp_port : TCP/IP 监听端口
uptime_in_seconds : 自 Redis 服务器启动以来,经过的秒数
uptime_in_days : 自 Redis 服务器启动以来,经过的天数
lru_clock : 以分钟为单位进行自增的时钟,用于 LRU 管理

clients

已连接客户端信息,包含以下域:
connected_clients : 已连接客户端的数量(不包括通过从属服务器连接的客户端)
client_longest_output_list : 当前连接的客户端当中,最长的输出列表
client_longest_input_buf : 当前连接的客户端当中,最大输入缓存
blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量

memory

内存信息,包含以下域:
used_memory : 由 Redis 分配器分配的内存总量,以字节(byte)为单位
used_memory_human : 以人类可读的格式返回 Redis 分配的内存总量
used_memory_rss : 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
used_memory_peak : Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human : 以人类可读的格式返回 Redis 的内存消耗峰值
used_memory_lua : Lua 引擎所使用的内存大小(以字节为单位)
mem_fragmentation_ratio : used_memory_rss 和 used_memory 之间的比率
mem_allocator : 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。
在理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿。
当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。
内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出。
当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。
Because Redis does not have control over how its allocations are mapped to memory pages, high used_memory_rss is often the result of a spike in memory usage.
当 Redis 释放内存时,分配器可能会,也可能不会,将内存返还给操作系统。
如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致。
查看 used_memory_peak 的值可以验证这种情况是否发生。

其他信息

persistence :RDB 和 AOF 的相关信息
stats : 一般统计信息
replication : 主/从复制信息persistence
cpu : CPU 计算量统计信息
commandstats : Redis 命令统计信息
cluster : Redis 集群信息
keyspace : 数据库相关的统计信息
除上面给出的这些值以外,参数还可以是下面这两个:
all : 返回所有信息
default : 返回默认选择的信息

Redis 超级对象

Bitmaps(位图)

Redis 开发与运维(付磊_张益军)学习笔记

使用场景:取日期为key,可以做日活分析。用户数量很大(活跃用户比重较大时适合做)
Redis 开发与运维(付磊_张益军)学习笔记

常用命令

1.设置值:setbit key offset value
offset 为位置取整数
value 为值取0或者1

2.获取值: getbit key offset
3.获取某个key元素的个数: bitcount key [start] [end]
4.bitop op destkey key [key …]
op 取 and(交集)|or(并集)|not(非)|xor(异或)
destkey 为新key名称
5 . 计算第一个值为targetbit的偏移量:bitops key targetBit [start] [end]

HyperLogLog

可以用极小的内存空间完成独立总数的统计。但是存在一定误差率,误差率约为0.81%。
使用场景:计算独立用户数,百万用户相比时,内存空间要比set小几千倍。

常用命令
1.添加元素:pfadd key element [element …]
2.计算元素数目:pfcount key [key …]
3.合并: pfmerge destkey sourcekey [sourcekey]
destkey 为新key名称
Sourcekey为被合并的key
合并后相同元素算一个元素

GEO

实现地理信息定位的功能。
使用场景:附近的位置,摇一摇

常用命令
1.增加地理信息:geoadd key longitude latitude member [ longitude latitude member …]
longitude latitude member分别为经度,纬度,成员
2.获取地理信息geopos key member [key member …]
3.获取两个地理位置的距离:geodist key member1 member2 [m|km|mi|ft]
4.根据某经纬度为中心指定范围内的地理信息位置集合:georadius key longitude latitude radius m|km|ft|mi [withcoord] [withdist] [withhash] [asc|desc] [store key] [storedist key]
withdist:在返回位置元素的同时,将位置元素与中心之间的距离也一并返回.距离的单位和用户给定的范围单位保持一致。
withcoord:将位置元素的经度和纬度也一并返回。
withhash:以52位有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中的作用不大。
命令默认返回未排序的位置元素。通过以下两个参数,用户可以指定被返回位置元素的排序方式:
asc:根据中心的位置,按照从近到远的方式返回位置元素
desc:根据中心的位置,按照从远到近的方式返回位置元素。
store key: 将返回结果保存在指定键
storedist key:将距离中心的距离保存到指定键
5.根据某成员为中心指定范围内的地理信息位置集合:georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [asc|desc] [store key] [storedist key]
操作同georadius
6.获取geohash(地理位置对应的hash字符串):geohash key member
GEO数据类型为zset,地理位置以geohash保存在zset中。
字符串越长代表位置越精确。
两个字符串越相似,代表地理位置月近。
Geohash可以与经纬度互相转换。

Redis 常用功能

Pipeline

可以将一组redis命令组装,一次性传给redis进行处理,从而减少反复交付的次数。Pipeline使用要避免数据量过大,否则会增加客户端等待时间,造成网络阻塞

Lua

通过multi命令开启任务,discard暂停任务,exec执行任务。执行完任务后才完成事物。如果在执行任务时,事物中的key有被修改。任务将不执行。可在multi前执行watch key命令,防止key被修改。

Redis 持久化

RDB

把当前数据生成快照保存到硬盘。

触发机制

1.手动触发:执行save或者bgsave命令
2.自动触发:
使用配置save m n 在m秒n次修改时触发save
从节点全量复制主节点时执行bgsave
执行debug reload 时触发save
执行shutdown时触发save

save与bgsave

save 命令会阻塞当前Redis服务器,bgsave是对save阻塞问题做的优化,bgsave流程:
1.执行bgsave命令
2.fork开启子进程
3.子进程生成RDB文件
4.告知父进程已完成,父进程更新统计信息

AOF

以日志形式实现数据的实时持久化,是现在持久化的主流方式

工作流程

1.Redis所有写入命令会追加到aof_buf(缓冲区)
2.根据文件同步策略同步数据到aof文件
3.当文件太大时对aof文件进行重写
4.Redis重启时加载aof文件恢复数据

文件同步

1.always:每次命令写入都同步
2.everysec:每秒执行一次
3.no:同步操作交给操作系统负责,通常同步周期最长为30秒

AOF文件重写触发机制

手动触发:执行bgrewriteaof命令
自动触发:在aof文件大小超过auto-aof-rewrite-min-size,且文件大小-上次重写时文件大小
/上次重新时文件大小>auto-aof-rewrite-percentage 时触发

AOF文件重写流程

Redis 开发与运维(付磊_张益军)学习笔记
1.执行aof重写请求
2.Fork子进程
3-1 完成fork后有新的写入继续写入aof_buf缓冲区
3-2 为了防止fork后的数据丢失,fork后的数据写入aof_rewrite_buf 重写缓冲区
4. 子进程根据内存快照,按照合并规则写入到新aof文件
5-1 通知父进程,记录info persistence信息
5-2 把重写缓冲区的数据写入新aof文件
5-3 用新aof文件替换旧aof文件

重启加载机制

如果开启aof,加载aof文件;
如果未开启aof或者aof文件不存在则使用rdb,加载rdb文件
如果rdb文件不存在,就不加载任何文件直接重启

RDB与AOF比较

1.RDB比AOF文件小
2.Redis恢复数据时加载RDB比AOF快很多
3.RDB没有办法实时持久化
4.RDB版本用二进制文件保存版本兼容没AOF好

问题定位与优化

fork操作

问题原因:fork操作是重量级操作,会复制父进程的空间内表页(理论上需要复制与父进程同样的内存,但是linux有写时复制机制,父子进程贡献相同的物理内存页,实际会小很多,10G大概只需要20MB)
问题定位: 通过info stats 统计排查 lastest fork查看最近一次的fork的耗时
优化方法:
1.Xen虚拟机对fork操作支持不好,因避免使用
2.控制Redis实列最大内存,线上建议10GB以内
3.合理配置linux内存?
4.降低fork频率,适当放宽aof触发时机

子进程

问题原因:子进程负责重写操作,需要消耗cpu,内存和硬盘的资源
问题定位:
info persistence 查看当多个Redis实例部署在一台服务器时的重写状态
查看重写时的cpu消耗
查看重写时的redis 日志输出观察内存消耗状态
优化方法:

cpu:

1.把内存数据写入文件会消耗大量cpu,因此尽量不要用单核cpu;
2.一台机器如果多个实例,尽量保证不同时重写

内存:

1.同cpu尽量保证多个实列不同时重写
2.设置no-appendfsync-on-rewrite yes避免在大量写入时重写
硬盘:
1.将文件写入硬盘时,会造成比较多的硬盘压力,因此不要和其他高硬盘操作放在一起。如:存储服务,消息队列
2.设置no-appendfsync-on-rewrite yes避免在大量写入时重写
3.开启aof功能时且流量高时,尽量不要用普通机械盘
4.单机开启多个实例,可以把文件分盘存储

AOF追加阻塞

问题原因:常用的同步策略为everysec,此时当Redis有大量写入时,会导致fsync和重写同时发生,此时对比上次fsync时间有可能大于2秒,如果超过2秒主线程将堵塞,直到同步完成。
问题定位:每次阻塞 aof_delayed_fsync指标会累加,通过info persistence 查看 aof_delayed_fsync指标
优化方法:同子进程硬盘优化

相关配置与命令

1.指定RDB保存文件名:dbfilename
2.动态更改RDB文件名:执行config set dbfilename {newfilename}
3.动态更改RDB保存目录:config set dir {newDir}
4.是否采用LZF压缩RDB文件:config set rdbcompression {yes|no},默认开启,建议开启,方便传输和保存到硬盘
5.开启AOF持久化:appendonly yes
6.设置AOF文件名:appendfilename 默认为appendonly.aof
7.设置AOF文件同步方式:appendfsync 默认everysec
8.重新AOF文件:执行bgrewriteaof
9.AOF文件重写体积:auto-aof-rewrite-min-size 默认64MB
10.AOF文件重写子进程根据内存快照每次批量写入新AOF文件的数据大小:aof-rewirte-incremental-fsync 默认大小为32MB
11.在AOF重写期间是否执行fysnc(把缓存信息写入aof文件):no-appendfsync-on-rewrite

Redis主从复制

为Redis配置副本,实现故障的恢复和负载均衡

建立复制

一共有三种方式建立复制:
1.从节点配置文件 中加入slaveof {masterHost} {masterPort}
2.在redis-server 启动命令后加入 –slaveof {masterHost} {masterPort}
3.执行slaveof {masterHost} {masterPort}

断开复制

在从节点上执行slaveof no one,从节点与主节点断开链接,并保留断开前的数据

切换主节点

对断开复制的节点,重新执行建立复制,实现切换主节点的操作,此时:
从节点会清空数据,然后复制新主节点的数据

拓扑

一主一从

主要用于故障转移,可只打开从节点的AOF功能,以提高主节点性能,但此时重启时从节点要断开与主节点的复制关系,以免清空数据。

一主多从

主要用于读占比比较大的场景,用从节点分摊主节点的读写压力

树状结构

Redis 开发与运维(付磊_张益军)学习笔记

通过引入中间层,降低主节点负载

数据同步

复制偏移量

每次写入命令主从节点都会增加复制偏移量

复制积压缓存区

当主节点响应写命令时,不但把命令发送给从节点,页把命令写入复制积压缓存区

全量复制流程

1.一般在第一次建立链接和重启主节点导致主节点运行id发生变化后引起,如果是debug reload,运行id不会发生变化
2.第一次建立链接后,因为从节点没有复制偏移量和主节点的运行id,会进行全量复制,并保存主节点此时的运行id和复制偏移量
3.主节点执行bgsave保存rdb文件到本地,并将rdb文件发送给从节点,需要注意传输的总时间不能超过 repl-timeout(默认 60秒),否则从节点清空rdb文件,复制失败。
4.在从节点接受rdb文件期间,主节点会将此时的写命令写入复制积压缓冲区,并累积偏移量
5.从节点清空自身数据,加载RDB文件,加载完成后,如果开启AOF就马上重写

部分复制流程

1.一般在主从节点网络断开时间超过repl-timeout(默认60秒)时发生
2.断开后主节点依然把数据写入复制积压缓存区(默认大小为1MB)
3.重新链接后把复制积压缓存区的信息传输给从节点

心跳

1.主节点默认每隔repl-ping-slave-period (默认10)秒发送ping命令检验从节点是否链接正常
2.从节点每隔一秒发送replconf ack {offset}命令,主动上报主节点自己的复制偏移量,检查数据是否丢失,如果丢失就从主节点的复制积压缓存区中拉取数据

异步复制流程

1.主节点接受处理命令
2.命令结束后返回结果
3.异步发送命令给从节点,从节点执行复制的命令

问题定位与优化

主从配置不一致

1.从节点内存溢出,数据丢失:maxmemory与比主节点配置小造成,应该配置一致。

全量复制

1.全量复制消耗大,尽量在低峰时进行
2.节点运行ID不匹配:主节点故障重启造成,可以升级从节点为主节点,防止从节点以为链接了新的节点而造成的全量复制
3.复制积压缓冲区不足时,偏移量会不在主节点的复制积压缓冲区内,而造成全量复制,可以适当加大repl_backlog_size(默认1MB)

单主节点复制风暴

由大量从节点对同一主节点发起全量复制造成:会同时向多个从节点发送rdb文件,网络消耗太大,建议改为原拓扑结构为树状结构

单机器复制风暴

由一台机器部署很多个主节点故障造成:建议每台机器部署的主节点数目尽量少,提供主节点故障转移方案:哨兵,集群等。

相关配置与命令

1.设置复制:slaveof {masterHost} {masterPort}
2.复制命令:slaveof {masterHost} {masterPort}
3.断开复制:slaveof no one
4.设置redis链接密码:requirepass
5.设置节点为只读:slave-read-only 从节点默认为yes
6.传输延迟机制:rep-disable-tcp-nodelay
关闭时,无论产生的命令数据大小都会传给从节点
开启时,会合并较小的tcp数据包从而节省宽带,网络环境差时推荐开启
7.从节点心跳超时时间:repl-timeout默认60秒
8.心跳检验间隔时间:repl-ping-slave-period 默认10秒
9.执行复制:psync {offset} {runId}
10.配置最大内存:maxmemory
11.复制积压缓冲区大小:repl_backlog_size(默认1MB)

Redis 阻塞问题

如何发现问题

1.客户端报JedisConnectionExpection异常
2.使用CacheCloud进行管理

内在原因

API或者数据结构使用不合理解决方案

1.通过慢查询日志slowlog get {n} 查询不合理的命令,改为低算法度的命令代替
2.执行 redis-cli -h {ip} -p {port} –bigkeys 查看大对象,尽量用更合理的数据类型代替

CPU饱和

1.每秒请求次数过多:通过redis -cli –stat 观察requests数量,如果一个redis实例每秒有好几万次请求,建议做水平扩展优化
2.使用了耗时高的命令:通过info commandstats 查看user_per查看命令平均耗时,找出耗时高的命令,把耗时高的命令换成低的命令,或者放宽zipList条件

持久化阻塞

解决方案见 Redis 持久化-问题定位与优化

外在原因

CPU竞争

1.Redis是CPU高密集应用,建议不要和其他CPU密集应用部署在同一台服务器
2.对与开启了持久化或参与复制的主节点,建议不要绑定CPU,让其可以充分利用多核CPU

内存交换

即防止把内存数据换出到硬盘
问题定位:
1.查询Redis进程号:info server | grep process_id
2.根据进程号查询内存交换信息:cat /proc/{process_id}/smaps | grep Swap
问题优化:
1.保证机器内存充足
2.设置正确的redis最大内存maxmemory
3.降低系统使用swap优先级

网络问题

1.网络闪断:尽量避免,异地机房调用
2.Redis链接拒绝:适当增加maxclients最大连接数,尽量采用连接池方式
3.连接溢出too many open files:通过unlimit -n {连接数量},适当增加连接数量
4.backlog队列溢出:适当增加redis backlog的长度(默认511)
5.网络延迟:增加宽带,减少大对象传输
相关配置与命令
查看慢查询日志:执行slowlog get {n} n为查询最近日志的条数
查看大对象:执行 redis-cli -h {ip} -p {port} –bigkeys

Redis 内存详解

内存使用统计

1.利用info memory 查看详见Redis 数据类型与API-info命令详情
2.重点

区块链毕设网(www.qklbishe.com)全网最靠谱的原创区块链毕设代做网站
部分资料来自网络,侵权联系删除!
资源收费仅为搬运整理打赏费用,用户自愿支付 !
qklbishe.com区块链毕设代做网专注|以太坊fabric-计算机|java|毕业设计|代做平台 » Redis 开发与运维(付磊_张益军)学习笔记

提供最优质的资源集合

立即查看 了解详情