《Redis开发与运维》读书笔记一

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/singgel/article/details/90897393

 之前这本书看了大概二分之一,后面就没有再坚持下去,这次在我球管理redis-manager的机会,重新捡起这本书,深度的阅读,以防止自己记忆碎片,整理文档。Redis开发与运维这本书的内容太多,网上没有找到检索,记录下来自己认为重要的信息片段,供检所使用。

书籍地址:https://github.com/singgel/Study-Floder


目录

redis可以做什么:

redis可执行文件:

redis版本:

redis的API:

慢查询分析:

redis-cli:

redis-benchmark:

pipeline:

事物:

Lua:

Redis如何管理Lua:

Bitmaps:

HyperLogLog:

发布订阅:

GEO:

客户端通信协议:

Jedis:

Python的redis-py:

客户端api:

输入缓冲区:

输出缓冲区:

客户端存活状态:

客户端限制:

客户端常见异常:

持久化触发机制:

RDB文件处理:

AOF使用:


redis可以做什么:

  • 缓存
  • 排行榜系统
  • 计数器应用
  • 社交网络
  • 消息队列系统

redis可执行文件:

  • redis-server
  • redis-cli
  • redis-benchmark #基准测试工具
  • redis-check-aof #aof持久化文件检测和修复工具
  • redis-check-dump #rdb持久化文件检测和修复工具
  • redis-sentinel

redis版本:

  • 2.6 bind多地址 sentinel哨兵 主从复制
  • 3.0 embedded编码 migrate连接缓存
  • 3.2 quicklist编码
  • 4.0 非阻塞del和flush命令 memory命令

redis的API:

  • 全局:keys dbsize exists del expire(好几个时间级别) type rename ttl
  • 数据结构:object encoding 
  • String:set|mset key value [ex second] [px milliseconds] [nx|xx]  (编码:int embstr raw)
  • hash:hset|hmset key field value [field value ...] (编码:ziplist<512个 64kb hashtable)
  • list:rpush key value [value ...]{linsert listkey before key key} (编码:ziplist<512个 64kb linkedlist quicklist)
  • set:sadd key element [element ...](编码:inset<512个  linkedlist quicklist)
  • zset:zadd key score member [score member ...] (编码:ziplist<512个 64kb skiplist)
  • migrate: migrate host port key|"" destination-db timeout [copy] [replace] 
  • sacn:在scan过程中出现键的变化(增加删除修改),会出现新增没有遍历到、出现键的重复
  • config rewrite将配置持久化到本地

慢查询分析:

  • 预设阀值slowlog-log-slower-than<10000微秒(高QPS建议1ms)
  • 慢查询记录showlog-max-len最多纪录多少条(线上可设置大一些,不会占用大量内存)
  • showlog get [n]

redis-cli:

-r(重复次数repeat)

-i(间隔时间interval 单位s)redis-cli -r 100 -i 1 info|grep used_memory_human

-x(标准输入stdin)echo "world" | redis-cli -x set hello

-c(集群模式cluster)

-a(密码auth)

--scan --pattern(扫描指定模式的键)

--slave 把客户端模拟成Redis的从节点

--rdb 生成RDB持久化文件

--pipe 将命令封装发送

--bigkeys 用scan对redis采样,找出大key

--eval 执行指定lua脚本

--latency 检测网络延迟 redis-cli -h {machineB} --latency

--stat 实时获取redis统计信息

--raw 返回原始文本

redis-server:

--test-memory 用来检测但前操作系统能否稳定的分配指定容量内存给redis

redis-benchmark:

-c 代表客户端的并发数量(默认50)

-n 代表客户端请求总数(默认100000)

-q 仅仅显示redis-benchmark的requests per second信息

-r 在一个redis上执行命令会发现只有3个键,想插入更多使用-r(random)

-p 每个请求的pipeline数量 (默认1)

-k 代表客户端是否使用keepalive 1使用 0不使用(默认1)

-t 指定基准测试模式 eg:-t get set

--csv 将结果按照csv格式输出

pipeline:

redis提供了批量操作的命令(mget mset之类)但大部分不支持(例如hgetall)

注意:一次组装pipeline量过大会增加client等待时间,还会造成网络阻塞,分成多个pipeline来完成

事物:

multi和exec之间,multi代表事物开始,exec代表事物结束

停止事物的话使用discard命令

出现语法错误(eg:sett),导致事物无法执行

运行时错误(eg:sadd–zadd),导致执行,结果无法回滚

若要确保事物中的key没有被其他客户端修改:watch

Lua:

boolean、numbers、strings、tables

localhost int sum=0

for i=1100

do

    sum=sum+1

end

print(sum)

//函数定义

function funName()

    ...

end

contract拼接字符串

function contract(str1,str2)

    return str1 .. str2

end

--"hello world"

print(contract("hello""world"))

eval:eval 脚本内容 key个数 key列表 参数列表

          eg:eval 'return "hello " .. KEYS[1] .. ARGV[1]' 1 redis world  输出:"hello redisworld"

redis-cli --eval执行客户端写好的脚本

evalsha:首先将Lua脚本加载到Redis服务器,得到该脚本的SHA1校验和

              redis-cli script load “$(cat lua_get.lua)” 输出 “SHA1值”

              evalsha 脚本的SHA1值 key个数 key列表 参数列表

redis.call函数 访问Redis

redis.log函数 将Lua脚本日志输出到redis中

Redis如何管理Lua:

  • script load:将Lua脚本加载到内存
  • script exists:判断SHA1是否在
  • script flush:清除已经加载的所有Lua脚本
  • script kill:杀掉正在执行的Lua脚本

Bitmaps:

以位为单位的数组,数组每个单元只能存储0和1

setbit key offset 0|1

getbit key offset

bitcount [start][end]

bitop是一个复合操作 做多个bitmap的交集(and) 并集(or) 非(not) 异或(xor)

bitops key targetBit计算第一个值为targetBit的偏移量

用途:

存储一个网站一天活跃用户

HyperLogLog:

用途:

存储IP、Email、ID等,存在误差0.81%

pfadd key element [element ...] 添加

pfcount key [key ...]计算独立用户数

pfmerge destkey sourcekey [sourcekey ...]合并,求并集

发布订阅:

publish channel message发布消息

subscribe channel [channnel ...]订阅消息

新订阅的客户端无法接受到消息,因为redis不持久化消息

unsubscribe [channel [channnel ...]]取消订阅

psubscribe pattern [pattern ...]批量订阅

punsubscribe [pattern [pattern ...]]批量取消订阅

pubsub channels [pattern]查看活跃的频道

pubsub numsub [channel ...]查看频道订阅数

pubsub numpat查看订阅数

用途:

聊天室、公告牌、服务之间的消息解耦

GEO:

geoadd key longitude latitude member [longitude latitude member ...]

geopos key member [member ...]

geolist key member1 member2 [unit]获取两地之间的位置信息

获取指定范围内的地理信息georadius georadiusbymember

geohash key member [member ...]获取geohash,GEO的数据类型为ZSET

geohash编码和经纬度是可以相互转换的

zrem key member 删除地理位置信息

客户端通信协议:

一:TCP协议之上

二:RESP序列化协议

想要看到RESP的真是结果,可以使用nc、telnet、socket程序

Jedis:

太简单,算了。。。

对了pipeline值得讲一下

eg:批量删除

public void mdel(List<String> keys){

    Jedis jedis = new Jedis("127.0.0.1");

    Pipeline pipeline = jedis.pipelined();

    for(String key : keys){

       pipeline.del(key);

    }

    pipeline.sync();

}

pipeline.syncAndReturnAll()获取返回结果

lua脚本也得来一下:

eg:scriptLoad发送脚本的形式

String key = "hello";

String script = "return redis.call('get',KEYS[1])";

Object result = jedis.eval(script, 1, key);

System.out.println(result);

eg:evalsha服务端宿主的形式

String key = "hello";

Object result = jedis.evalsha(scriptSha, 1, key);

System.out.println(result);

Python的redis-py:

算了吧,这个我不用。。。

套路和jedis差不多

客户端api:

client list能够列出与Redis服务端相连的所有客户端信息

id:客户端连接的唯一标识,id随着redis自增,重启后置为0

addr:客户端的ip和端口

fd:socket的文件描述符,fd=-1代表客户端不是外部客户端,是Redis内部的伪装客户端

name:客户端的名字

输入缓冲区:

Redis为每一个客户端分配了输入缓冲区,动态规划的,最大为1G,超过后客户端将被关闭

qbuf:代表客户端缓冲区的总容量

qbuf-free:代表了客户端的剩余容量

输入缓冲区不收maxmemory控制

解释:

假设一个Redis实例设置了maxmemory为4G,已经存储了2G数据

如果此时输入缓冲区使用了3G,可能会造成数据丢失、键值淘汰、OOM的情况

原因:

Redis的处理速度跟不上输入缓冲区的输入速度,并且每次输入缓冲区的命令包含了大量的bigkey

Redis发生阻塞,短期内不能处理命令,造成客户端命令积压在输入缓冲区,造成缓冲区过大

解决:

定期执行client list命令,手机qbuf和qbuf-free记录

通过info clients找出最大输入缓冲区,可以将client_biggest_input_buf设置超过10M就报警

Redis为每个客户端分配了输出缓冲区,保证执行结果返回给客户端

输出缓冲区:

输出缓冲区的容量可以通过参数client-output-buffer-limit进行设置

普通客户端、发布订阅客户端、slave客户端

client-out-buffer-limit <class> <hard limit> <soft limit> <soft seconds>

<class>:客户端类型:normal普通客户端、slave客户端、pubsub发布订阅客户端

<hard limit>:缓冲区大小,>该值客户端立即关闭

<soft limit> <soft seconds>:如果客户端使用的缓冲区超过soft limit并持续soft limit秒,客户端立即关闭

跟输入缓冲区一样,使用不当将会造成数据丢失、键值淘汰、OOM的

组成:

由固定缓冲区和动态缓冲区组成

固定缓冲区村较小的执行结果(使用字节数组)

动态缓冲区存较大的结果,较大的字符串、hgetall、smembres(使用列表)

obl:固定缓冲区长度

oll:动态缓冲区长度

omem:使用的字节数

解决:

监控、设置阀值

限制客户端缓冲区的大小

适当增大slave的缓冲区

限制容易让输出缓冲区增大的命令

及时监控内存,发现内存抖动频繁,有可能是输出缓冲区过大造成

客户端存活状态:

age:已经连接的时间

idle:最近一次空闲的时间

客户端限制:

maxclients:限制最大客户端连接数(默认10000)

timeout:连接最大空闲时间

client setname|getname设置名字

client kill ip:port杀掉

client pause timeout暂停,对于slave无效

monitor监听服务端执行的命令

tcp-keepalive进行活性检测,防止大量死连接占用系统资源(默认0)

tcp-backlog TCP握手后的连接队列(默认511)

客户端常见异常:

无法从连接池获取到连接:

blockWhenExhausted=flase不等待、存在慢查询阻塞了连接池

客户端读写超时:

读写超时间设置过短、命令本身慢、网络不正常、Redis自身阻塞

客户端连接超时:

连接超时设置过短、Redis阻塞、网络不正常

客户端缓冲区异常:

输出缓冲区慢、长时间时间限制连接被主动断开、不正常并发读写

Lua脚本正在执行:

Busy Redis is busy running a script

Redis正在持久化文件:

Loading Redis is loading the dataset in memory

Redis内存超过maxmemory设置:

OOM command not allowed when use memory

客户端连接数过大:

ERR max number of clients reached

主从内存不一致:

缓冲区的大小占用了大量内存空间

客户端周期性超时:

运维层面架空慢查询、开发层面加强对Redis理解

持久化触发机制:

save:阻塞Redis服务器,对于内存较大的实例会造成长时间的阻塞(已经废弃)

bgsave:Redis进程执行fork操作创建子进程,阻塞只发生在fork阶段

触发:

save m n表示m秒内数据存在n次修改触发bgsave

从节点执行全量复制操作,主节点生成RDB文件发送给从节点

debug reload命令重新加载Redis时

默认情况下执行shutdown命令时,如果没有开启AOF持久化功能自动执行bgsave

执行流程:

info stats:

latest_fork_usec可以获取最近一个fork操作的耗时(微秒)

rdb_last_save_time最后一次生成RDB的时间

RDB文件处理:

config set dir {newDir}遇见磁盘写满时,切换完路径执行bgsave切换

config set dbfilename {newFileName}下次运行的时候RDB会保存到新的位置

config set rdbcompression {yes|no}采用LZF算法生成RDB压缩

优点:

RDB是紧凑型的二进制文件,用作灾难恢复

RDB恢复速度快于AOF

缺点:

没有办法做到实时/秒级,针对这个问题可以使用AOF来解决

RDB的版本演进,导致无法兼容新的RDB格式

AOF使用:

问题:

1.AOF为什么采用文本?

文本具有很好的兼容性、直接采用协议格式避免二次处理开销、文本具有可读性

2.AOF为什么不直接将命令追加到aof_buf?

性能取决于当前硬盘的负载、另一个好处多缓冲区同步

appendfsync控制同步策略

write、fsync、alway(SATA)、no、everysec(默认)

重写压缩数据:bgrewriteaof手动触发、auto-aof-rewrite-min-size、auto-aof-rewrite-percentage

进程内超时的数据不再写入

进程内整个流程无效的数据不再写入

多条命令合为一条

猜你喜欢

转载自blog.csdn.net/singgel/article/details/90897393