天天看点

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

目录

前言

1. 二进制位数组

1.1 位数组的表示

1.2 GETBIT 命令的实现

1.3 SETBIT 命令的实现

1.4 BITECOUNT 命令的实现

1.5 BITOP 命令的实现

2. 慢查询日志

2.1 慢查询记录的保存

2.2 慢查询日志的阅览与删除

2.3 添加新日志

3. 监视器

最后

参考资料:《Redis设计与实现 第二版》;

第三部分为独立功能的实现,主要由以下模块组成:发布订阅、事务、Lua 脚本、排序、二进制位数组、慢查询日志、监视器;

本篇将介绍 Redis 的二进制位数组、慢查询日志和监视器。Redis 提供了一些命令操作二进制位数组;通过 SLOWLOG 相关命令可以对慢查询日志进行操作;通过 MONITOR 命令可以进入监视器模式;

与本章相关的 Redis 命令总结在下篇文章,欢迎点击收藏,本篇将不再重复:

《Redis常用命令及示例总结(API)》:https://www.cnblogs.com/dlhjw/p/15639773.html

Redis 使用字符串对象来表示位数组,因为字符串对象使用的 SDS 是二进制安全的;

使用逆序保存位数组,下图实际为:1111 0000 1100 0011 1010 0101;

使用逆序保存位数组,可以直接在新扩展的二进制位中完成,不必改动位数组原来已有的二进制位;

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

<code>GETBIT key offset</code> 命令;

1)计算 byte=offset / 8;<code>byte</code> 值表示位数组的哪个字节;

2)计算 bit=(offset mod 8)+1;<code>bit</code> 值表示在 <code>byte</code> 下标字节的第几个二进制位;

3)根据 byte 和 bit 的值定位 <code>offfset</code> 偏移量指定的二进制位;

4)向客户端返回二进制位的值;

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

<code>SETBIT key offset value</code> 命令;

1)计算 len=offset/8+1;<code>len</code> 值表示 <code>offset</code> 指定的二进制位至少需要多少字节;

2)根据 len 值进行扩展新空间,如果原位数组长度够则不扩展;

3)计算 byte=offset/8;<code>byte</code> 值表示位数组的哪个字节;

4)计算 bit=(offset mod 8)+1;<code>bit</code> 值表示在 <code>byte</code> 下标字节的第几个二进制位;

5)根据 byte 和 bit 的值定位 offfset 偏移量指定的二进制位 <code>oldvalue</code>,并修改;

6)向客户端返回二进制位 <code>oldvalue</code> 的值;

无扩展操作的 SETBIT 命令示例如下:

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

带扩展操作的 SETBIT 命令示例如下:

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

遍历算法:

遍历位数组中的每个二进制位,遇到 1 时将计数器值赠 1;

实现简单,效率低;

查表法:

对于长度有限的位数组而言,能表示的二进制位有限,而每种排列顺序的 1 的个数是确定的;

查表法是典型的空间换时间策略,节约时间越多,花费内存越大

受 CPU 缓存限制:创建表越大,能加载进缓存的内容越少,缓存不命中的情况越高,缓存的换入换出操作就越频繁,最终影响实际效率;

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

variable-precision SWAR 算法:

又称:计算汉明重量法;

一个处理 32 位长度位数的算法示例:

一个示例如下:

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》
Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

Redis 的实现:

BITCOUNT 命令使用查表法和 variable-precision SWAR 法两种;

查表法:使用键长为 8 位的表,记录 0000 0000 到 1111 1111 在内的二进制位的汉明重量;

variable-precision SWAR 法:每次循环中载入 128 个二进制位,调用 4 次 32 位的variable-precision SWAR 法计算 128 位二进制位的汉明重量;

程序根据未处理的二进制位的数量决定使用哪种算法:

未处理二进制位大于等于 128 位:variable-precision SWAR 法;

未处理二进制位小于 128 位:查表法;

算法的时间复杂度为:O(n),n 为输入二进制位的数量;

BITOP 命令的所有操作都是使用 C 语言内置的位操作来实现的;

BITOP 命令

C语言操作

说明

BITOP AND

&amp;

逻辑与

BITOP OR

|

逻辑或

BITOP XOR

^

逻辑异或

BITOP NOT

~

逻辑非

Redis 的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的例子来监视和优化查询速度;

服务器配置有两个和慢查询日志相关的选项:

<code>slowlog-log-slower-than</code> 选项:指定执行时间超过多少毫秒的命令请求会被记录到日志上;

<code>slowlog-max-len</code> 选项:指定服务器最多保存多少条慢查询日志。采用先进先出的方式;

使用 SLOWLOG 相关命令可以操作慢查询日志;

服务器状态中包含与慢查询日志功能相关的属性:

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

<code>slowlog</code> 链表结构如下:

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

<code>SLOWLOG GET [number]</code>;打印所有 slow log ,最大长度取决于 slowlog-max-len 选项的值;

<code>SLOWLOG LEN</code>;查看当前日志的数量。其值为 slowlog 链表的长度;

<code>SLOWLOG RESET</code>;清除所有慢查询日志;

每次执行命令的之前和之后,程序会记录微秒格式的当前 UNIX 时间戳,两个时间戳之间的差值就是服务器执行命令所消耗的时长;

新的慢查询日志会被添加到 slowlog 链表的表头,如果日志的数量超过 <code>slowlog-max-len</code> 选项的值,那么多出来的日志会被删除;

执行 MONITOR 命令,客户端可以将自己变为一个监视器,实时打印服务器当前处理的命令请求相关信息;

当一个客户端从普通客户端变为监视器时,该客户端的 <code>REDIS_MONITOR</code> 标识会被打开,该客户端会被添加到 <code>monitors</code> 链表的表尾;

所有监视器都记录在 <code>monitors</code> 链表里;

每次处理命令请求时,服务器会遍历 <code>monitors</code> 链表,将相关信息发送给监视器;

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

新人制作,如有错误,欢迎指出,感激不尽!

欢迎关注公众号,会分享一些更日常的东西!

如需转载,请标注出处!

Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》