Redis(二)

慢查询

慢查询日志

慢查询日志帮助开发和运维人员定位系统存在的慢操作。慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(慢查询ID,发生时间戳,耗时,命令的详细信息)记录下来。

Redis客户端一条命令分为如下四部分执行:

慢查询日志只是统计步骤3,执行命令的时间。

配置参数

1.慢查询的预设阀值 slowlog-log-slower-than

slowlog-log-slower-than参数就是预设阀值,单位是微秒,默认值是1000,如果一条命令的执行时间超过10000微妙,那么它将被记录在慢查询日志中。

如果slowlog-log-slower-than的值是0,则会记录所有命令。

如果slowlog-log-slower-than的值小于0,则任何命令都不会记录日志。

2.慢查询日志的长度slowlog-max-len

slowlog-max-len只是说明了慢查询日志最多存储多少条。Redis使用一个列表来存储慢查询日志,showlog-max-len就是列表的最大长度。当慢查询日志已经到达列表的最大长度时,又有慢查询日志要进入列表,则最早插入列表的日志将会被移出列表,新日志被插入列表的末尾。

慢查询日志的组成

慢查询日志由以下四个属性组成:标识ID,发生时间戳,命令耗时,执行命令和参数

慢查询日志的访问和管理

1.获取慢查询日志slowlog get [n]

命令:slowlog get [N]

选型:N,可选,代表获取的日志条数

2.获取慢查询日志列表的当前长度slowlog len

命令:slowlog len

返回:慢日志列表的当前长度

3.慢查询日志重置slowlog reset

慢查询日志重置实际是对列表做清理操作。

pipline

将命令和结果打包,节省很多网络时间。Redis命令是非常快的,微秒级的,网络却很慢,所以pipeline要做到的就是控制网络时间

发布订阅

  • publish channel message:发布消息到某个频道
  • subscribe channel(可以多个):订阅某频道
  • unsubscribe channel(可以多个):取消订阅
  • psubscribe [pattern]
  • punsubscribe [pattern]

bitmap(位图)

操作String数据结构的key所存储的字符串指定偏移量上的位,返回原位置的值

  • setbit key offset value:设置或修改key上的偏移量(offset)的位(value)的值
  • getbit key offset:查询key所存储的字符串值,获取偏移量上的位
  • bitcount key [start] [end]:计算给定key的字符串值中被设置为1的位bit的数量
  • bitop and destkey key [key...],对一个或多个key逻辑并,结果保存到destkey
  • bitop or destkey key [key...],对一个或多个key逻辑或,结果保存到destkey。
  • bitop xor destkey key [key...],对一个或多个key逻辑异或,结果保存到destkey。
  • bitop xor destkey key,对一个或多个key逻辑非,结果保存到destkey。

hyperloglog

  • pfadd key element(可以多个)
  • pfcount key:计算独立总数
  • pfmerge destkey sourcekey1 sourcekey2 ...:合并多个hyperloglog为一个

geo

  • geoadd key longitude latitude member [longitude latitude member...]:将给定的空间元素(纬度、经度、名字)添加到指定的键里面
    如:
    geoadd cities:locations 116.28 39.55 beijing
  • geopos key member [member...]:从键里面返回所有给定位置元素的位置(经度和纬度)
  • geodist key member1 member2 [unit]:计算两个位置的距离
  • georadius key longitude latitude radius m|km|ft|mi [withcoord][withdist][withhash][asc|desc][count count]:以给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素。
  • georadiusbymember key member radius m|km|ft|mi [withcoord][withdist][withhash][asc|desc][count count]:这个命令和georadius命令一样,都可以找出位于指定范围内的元素,但是georadiusbymember的中心点是由给定的位置元素决定的
  • geohash key member [member...]:Redis使用geohash将二维经纬度转换为一维字符串,字符串越长表示位置更精确,两个字符串越相似表示距离越近。
  • zrem:GEO没有提供删除成员的命令,但是因为GEO的底层实现是zset,所以可以借用zrem命令实现对地理位置信息的删除.如:zrem cities:locations tianjin

持久化

RDB(快照)持久化:保存某个时间点的全量数据快照

  • 手动触发

    • SAVE:阻塞Redis的服务器进程,知道RDB文件被创建完毕
    • BGSAVE:Fork出一个子进程来创建RDB文件,不阻塞服务器进程 lastsave 指令可以查看最近的备份时间
  • 自动触发

    • 根据redis.conf配置里的save m n定时触发(用的是BGSAVE)
    • 主从复制时,主节点自动触发
    • 执行Debug Relaod
    • 执行Shutdown且没有开启AOF持久化

RDB配置

# 时间策略
save 900 1
save 300 10
save 60 10000

# 文件名称
dbfilename dump.rdb

# 文件保存路径
dir /home/work/app/redis/data/

# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes

# 是否压缩
rdbcompression yes

# 导入时是否检查
rdbchecksum yes
  • save 900 1 表示900s内如果有1条是写入命令,就触发产生一次快照,可以理解为就进行一次备份
  • save 300 10 表示300s内有10条写入,就产生快照
  • stop-writes-on-bgsave-error yes 当备份进程出错时,主进程就停止接受新的写入操作,是为了保护持久化的数据一致性问题
  • rdbcompression yes ,建议没有必要开启,毕竟Redis本身就属于CPU密集型服务器,再开启压缩会带来更多的CPU消耗,相比硬盘成本,CPU更值钱

当然如果你想要禁用RDB配置,也是非常容易的,只需要在save的最后一行写上:save ""

AOF(Append-Only-File)持久化:保存写状态(日志)

  • 记录除了查询以外的所有变更数据库状态的指令

  • 以append的形式追加保存到AOF文件中(增量)

  • 日志重写解决AOF文件不断增大的问题,原理如下

    • 调用fork,创建一个子进程
    • 子进程把新的AOF写到一个临时文件里,不依赖原来的AOF文件
    • 主进程持续将新的变动同时写到内存和原来的AOF里
    • 主进程获取子进程重写AOF完成信号,往新AOF同步增量变动
    • 使用新的AOF文件替换掉旧的AOF文件

AOF配置

# 是否开启aof
appendonly yes

# 文件名称
appendfilename "appendonly.aof"

# 同步方式
appendfsync everysec

# aof重写期间是否同步
no-appendfsync-on-rewrite no

# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加载aof时如果有错如何处理
aof-load-truncated yes

# 文件重写策略
aof-rewrite-incremental-fsync yes
  • appendfsync everysec 它其实有三种模式:

    • always:把每个写命令都立即同步到aof,很慢,但是很安全
    • everysec:每秒同步一次,是折中方案
    • no:redis不处理交给OS来处理,非常快,但是也最不安全

    一般情况下都采用 everysec 配置,这样可以兼顾速度与安全,最多损失1s的数据。

  • aof-load-truncated yes 如果该配置启用,在加载时发现aof尾部不正确是,会向客户端写入一个log,但是会继续执行,如果设置为 no ,发现错误就会停止,必须修复后才能重新加载。

缓存

缓存更新策略

  • LRU/LFU/FIFO算法剔除
  • 超时剔除
  • 主动更新

缓存穿透

如果数据库和缓存中本身就不存在要查询的数据,那么每次查询就都会查询到数据库。

解决方法:

  • 缓存空对象
  • 布隆过滤器拦截

无底洞问题

批量操作(mget)有时会因为节点的增加导致查询速度反而变慢,因为节点越多就需要向更多的节点发起查询。

热点key+较长重建时间

当一个线程访问到热点key,且该key不在缓存中,就需要查询数据库并重建缓存,在重建未完成时,会有很多其他并发线程也访问该key,同样就需要访问数据库并重建缓存。

解决方法:

  • 互斥锁:在第一个线程访问时,加一把互斥锁,其他线程访问时阻塞,待第一个线程重建缓存后再释放锁
  • 永不过期:在缓存中设置热点key永不过期,即一直存在于缓存中(无法保证一致性)
原文地址:https://www.cnblogs.com/cky-2907183182/p/13237867.html