# 全量检查-Redis

## 鹰眼

* [1 项目概述](#1-项目概述)
  * [1.1 背景介绍及目标](#11-背景介绍及目标)
  * [1.2 名词说明](#12-名词说明)
    * [1.2.1 数据一致率](#121-数据一致率)
  * [1.3 Roadmap](#13-roadmap)
* [2 需求分析](#2-需求分析)
  * [2.1 功能需求](#21-功能需求)
    * [2.1.1 不一致类型](#211-不一致类型)
    * [2.1.2 key 不一致](#212-key-不一致)
    * [2.1.3 对比模式](#213-对比模式)
  * [2.2 非功能需求](#22-非功能需求)
  * [2.3 调研](#23-调研)
    * [2.3.1 vipshop/redis-migrate-tool](#231-vipshopredis-migrate-tool)
    * [2.3.2 alibaba/RedisFullCheck](#232-alibabaredisfullcheck)
* [3 总体设计](#3-总体设计)
  * [3.1 系统架构](#31-系统架构)
  * [3.2 模块简介](#32-模块简介)
  * [3.3 设计与折衷](#33-设计与折衷)
  * [3.4 潜在风险](#34-潜在风险)
* [4 详细设计](#4-详细设计)
  * [4.1 分发任务](#41-分发任务)
    * [4.1.1 交互流程](#411-交互流程)
    * [4.1.2 数据库设计](#412-数据库设计)
    * [4.1.3 接口形式](#413-接口形式)
    * [4.1.4 Redis key](#414-redis-key)
* [5 数据统计](#5-数据统计)
  * [5.1 scan 耗时](#51-scan-耗时)
  * [5.2 scan 并发送任务耗时](#52-scan-并发送任务耗时)

## 1 项目概述

### 1.1 背景介绍及目标

> * Redis 集群间数据检查

### 1.2 名词说明

#### 1.2.1 数据一致率

> * 一致率 = (key\_sum\_num - key\_diff\_num)/key\_sum\_num \* 100%

### 1.3 Roadmap

## 2 需求分析

> 需求分析重点是需求

### 2.1 功能需求

#### 2.1.1 不一致类型

不一致的方式主要分为 2 类：key 不一致和 value 不一致。

#### 2.1.2 key 不一致

key 不一致主要分为以下几种情况：

> * lack\_target : key 存在于源库，但不存在于目的库。
> * type: key 存在于源库和目的库，但是类型不一致。
> * length: value 长度不一致
> * value: key 存在于源库和目的库，且类型一致，但是 value 不一致。
>   * string: value 不同。
>   * hash: 存在 field，满足下面 3 个条件之一：
>     * field 存在于源端，但不存在与目的端。
>     * field 存在于目的端，但不存在与源端。
>     * field 同时存在于源和目的端，但是 value 不同。
>   * set/zset：与 hash 类似。
>   * list: 与 hash 类似。
> * other: 其他异常

field 冲突类型有以下几种情况（只存在于 hash，set，zset，list 类型 key 中）：

> * lack\_source: field 存在于源端 key，field 不存在与目的端 key。
> * lack\_target: field 不存在与源端 key，field 存在于目的端 key。
> * value: field 存在于源端 key 和目的端 key，但是 field 对应的 value 不同。

#### 2.1.3 对比模式

check\_method

> * length: 对比 value 值的长度是否相等。
> * content: 对比 value 长度、value 值是否相等。
>   * 对于 hash，set，zset，list 大 key 处理采用以下方式：
>     * len <= 1000，直接取全量 field、value 进行比较，使用如下命令：hgetall，smembers，zrange 0 -1 withscores，lrange 0 -1。
>     * len > 1000, 仅打印日志，不校验数据

### 2.2 非功能需求

### 2.3 调研

#### 2.3.1 vipshop/redis-migrate-tool

<https://github.com/vipshop/redis-migrate-tool>

```
$src/redis-migrate-tool -c rmt.conf -o log -C redis_check
Check job is running...

Checked keys: 1000
Inconsistent value keys: 0
Inconsistent expire keys : 0
Other check error keys: 0
Checked OK keys: 1000

All keys checked OK!
Check job finished, used 1.041s
```

> 如果想检查更多的 key，可以使用下面命令：

```
$src/redis-migrate-tool -c rmt.conf -o log -C "redis_check 200000"
Check job is running...

Checked keys: 200000
Inconsistent value keys: 0
Inconsistent expire keys : 0
Other check error keys: 0
Checked OK keys: 200000

All keys checked OK!
Check job finished, used 11.962s
```

> 插入一些测试 key （redis\_testinsert）

```
$src/redis-migrate-tool -c rmt.conf -o log -C "redis_testinsert"
Test insert job is running...

Insert string keys: 200
Insert list keys  : 200
Insert set keys   : 200
Insert zset keys  : 200
Insert hash keys  : 200
Insert total keys : 1000

Correct inserted keys: 1000
Test insert job finished, used 0.525s

$ 插入更多的 key
$src/redis-migrate-tool -c rmt.conf -o log -C "redis_testinsert 30000"
```

#### 2.3.2 alibaba/RedisFullCheck

<https://github.com/alibaba/RedisFullCheck>

## 3 总体设计

> 总体设计重点是设计与折衷

### 3.1 系统架构

> 一般来说会有个简单的架构图，并配以文字对架构进行简要说明；

```
    +------------------------------------------------+
    | +--------------------------+ +---------------+ |
    | |       Source Redis       | | Target  Redis | |
    | + ------------^--------^-^-+ +-------------^-+ |
    +---------------|----------\-\---------------|---+
                    | redis       \ \ twemproxy  |
                    1(scan)    (type)2 3         3(length + content)
                    |                   \ \      |
                    |                      \ \   |
    +---------------|-------------------------+-\+---+
    |               |                            |   |
    | +yingyan------------------+  +yingyan_agent--+ |
    | |+----------+ +----------+|  | +-----------+ | |
    | ||scan_group| |scan_shard||  | | key_check | | |
    | |+--+-------+ +--+----+--+|  | +-----+-----+ | |
    | +---|------------|----|---+  +-------|-------+ |
    +-----|------------|----|--------------|---------+
          |            |    |              |
   (1)push|     (2)pull|    |(2)push       |(3)pull
          |            |    |              |
          |            |    |              |
          |            |    |              |
    +MQ---V------------V----V--------------V---------+
    |             +---------+                        |
    |             |Twemproxy| \                      |
    |             +--+---+--+  +----------+          |
    |                |   |     |Metaserver|          |
    |             +--V---V--+  +----------+          |
    |             |  Redis  | /                      |
    |             +---------+                        |
    +------------------------------------------------+

(1) scan_group(src_group, dst_group)
    获取源集群 redis shard 从库 ip port
(2) scan_shard(src_group, dst_group, src_ip, src_port)
    对从库进行 scan 获取 key，每 1000 个 key 进行打包发到队列（同时包含 src_ip, src_port, dst_ip, dst_port)
(3) key_check(src_ip, src_port, dst_ip, dst_port, key_list)
    从源集群获取集群 type
    根据 type 对集群的 key 的 value 进行检查长度，
        若长度不一则进行记录
            目标 value 长度为 0: 则记录为 lack_target
            目标 value 长度为其他 length： 则记录为 length
            目标 value 中含 "WRONGTYPE": 则记录为 type
            目标 value 异常：则记录为 "other"
        长度一致
            若检查内容，则对比内容的 md5 值
            
```

### 3.2 模块简介

> 架构图中如果有很多模块，需要对各个模块的功能进行简要介绍；

### 3.3 设计与折衷

> 设计与折衷是总体设计中最重要的部分；

### 3.4 潜在风险

## 4 详细设计

> 详细设计重点在“详细”

### 4.1 分发任务

> （有了数据库 + 接口 + 流程，别的同学拿到详设文档，基本也能够搞定了）

#### 4.1.1 交互流程

> 简要的交互可用文字说明，复杂的交互建议使用流程图，交互图或其他图形进行说明

#### 4.1.2 数据库设计

#### 4.1.3 接口形式

#### 4.1.4 Redis key

python 中 repr 和 eval 可以用来在数据结构和字符串间互转 在这个功能上，repr 和 str 的作用一样，把一个数据结构转换成字符串，例如：

```
>>> repr([1,2,3,4])
'[1, 2, 3, 4]'

eval 是把字符串转换成数据结构，例如：
>>> eval('[1,2,3,4]')
[1, 2, 3, 4]
```

Redis 中很多 key name 是使用的中文，可以先通过 repr(key) 转为字符串，塞入队列，然后处理 worker 获取到时先 eval(key\_str) 进行转换为原数据

## 5 数据统计

### 5.1 scan 耗时

> * 10G 数据，不限速

```
scan_count:256
cost:66s
counts:43676
key_num:8746171(874w)

avg_qps:661
cpu: 上涨 30%
```

> * 10G 数据（每次 scan 后，等待 10ms)

```
scan_count:256
cost:519s
counts:43752
key_num:8761618

avg_qps:84
cpu: 上涨 6%
```

### 5.2 scan 并发送任务耗时

> * 10G 数据 (900w key)

```
生产者：
    发送耗时：154s(3 分钟）
    开始时间：2021-09-01 12:23:29
    结束时间：2021-09-01 12:26:03

消费者：
    处理耗时：17 分钟
    开始时间：2021-09-01 12:23:30
    结束时间：2021-09-01 12:40:34

目标集群 CPU:
    上涨 5-10% 左右
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://meetbill.gitbook.io/butterfly-project-doc/project-handlers/chunfeng/butterfly-bianque/butterfly-yingyan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
