Redis高性能集群理论以及实践

452 阅读8分钟

一 redis高可用分布式方案

  • 项目采用的是predixy + redis-cluster 的组合,predixy充当代理,集群三组三从总共六个节点。
  • 有三台Linux专门用来部署redis,每台有两个节点,每个节点的内存是23G。每台都有一个代理predixy,其中predixy代理六个节点。
  • 硬负载配置三台predixy代理进行轮询,服务端配置硬负载地址。这块具体是保密的,我们没接触到。只知道大概架构。

二 为什么要选择Redis Cluster集群?

Redis如果要扩展的话有纵向扩展、横向扩展。

纵向扩展

  • 好处 实施起来简单、直接

  • 缺点 随着数据量增加,需要的内存也会增加,主线程fork子进程时就可能会阻塞;受到硬件和成本的限制

横向扩展

  • 只需增加Redis实例个数就行,面向百万、千万级别的用户规模横向扩展的Redis切片集群会使一个非常好的选择。

Redis Cluster集群

步骤:

  • 首先根据键值对的key,按照CRC16算法计算一个16bit的值。

  • 用这个16bit值对16384取模,得到0~16383范围内的模数,每个模数代表一个相应编号的哈希槽

Redis实例会把⾃⼰的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。

客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

在集群中,实例有新增或删除,Redis需要重新分配哈希槽;为了负载均衡,Redis需要把哈希槽在所有实例上重新分布⼀遍。

集群的实例增减,或者是为了实现负载均衡⽽进⾏的数据重新分布,会导致哈希槽和实例的映射关系发⽣变化,客户端发送请求时,会收到命令执⾏报错信息。

三 MOVED & ASK

当客户端把⼀个键值对的操作请求发给⼀个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下⾯的MOVED命令响应结果,这个结果中就包含了新实例的访问地址。

GET hello:key(error) MOVED 13320 172.16.19.5:6379

MOVED命令表⽰,客户端请求的键值对所在的哈希槽13320,实际是在172.16.19.5这个实例上。通过返回的MOVED命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。这样⼀来,客户端就可以直接和172.16.19.5连接,并发送操作请求了。

客户端向实例2发送请求,但此时,Slot 2中的数据只有⼀部分迁移到了实例3,还有部分数据没有迁移。会出现一下错误:

GET hello:key(error) ASK 13320 172.16.19.5:6379

ASK命令表⽰两层含义:第⼀,表明Slot数据还在迁移中;第⼆,ASK命令把客户端所请求数据的最新实例地址返回给客户端,此时,客户端需要给实例3发送ASKING命令,然后再发送操作命令。

四 本地部署 predixy + redis-cluster

主要思路:

1. 首先我们要去官网下载 redis-6.2.6.tar.gz包到本地并解压

2. 进入目录编译 make,之后进入目录创建redis-cluster文件夹,在该文件夹下创建文件夹7001、7002、7003、7004、7005、7006 以及redis-data、run的文件夹

3. 在7001文件夹下创建redis-7001.conf配置文件,之后复制到其他文件夹下

这是redis-7001.conf的内容

# 配置实例端口
port 7001
# 配置rdb文件名
dbfilename 7001-dump.rdb
# 配置cluster生成节点数据的文件名,注意如果要重启服务,重新组成cluster集群需要删除所有的这个文件。
cluster-config-file nodes-7001.conf
# 配置pid文件名和存储目录
pidfile /Users/APPLE/Documents/software/redis-cluster-predixy/redis-6.2.6/redis-cluster/run/redis_7001.pid
dir /Users/APPLE/Documents/software/redis-cluster-predixy/redis-6.2.6/redis-cluster/redis-data
 # 生成的文件存储目录(包括rdb文件和node的conf文件)
# 作为守护线程运行
daemonize yes
# 不绑定ip
bind 0.0.0.0
logfile ""
# 关闭保护模式
protected-mode no
# 密码 (全部实例设置成同一个)
# requirepass 123456
# 从节点访问主节点的密码(和上面的密码一样并且,全部实例设置成同一个)
# masterauth 123456
# 超时时间
cluster-node-timeout 12000
#开启cluster
cluster-enabled yes

## 其余配置比如aof什么的视情况自己改就好了
loadmodule /Users/APPLE/Documents/software/redis-cluster/redisbloom.so

4. 配置完后我们就可以指定配置文件启动redis,进到src文件夹下启动。

5. cluster的通信组装

./redis-cli -a sjwkk123456 --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1

6. 完成以上步骤就可以使用redis-cli命令查看集群状态

7. 安装predixy

官网 github.com/joyieldInc/…

编译、安装好后,配置【predixy.conf】和【cluster.conf】以及【auth.conf】这3个文件,因为这个redis我也有安装插件布隆过滤器,所以【command.conf】也有配置。

################################### GENERAL ####################################
## Predixy configuration file example

## Specify a name for this predixy service
## redis command INFO can get this
Name Predixy7617

## Specify listen address, support IPV4, IPV6, Unix socket
## Examples:
# Bind 127.0.0.1:7617
# Bind 0.0.0.0:7617
# Bind /tmp/predixy

## Default is 0.0.0.0:7617
Bind 0.0.0.0:7617

## Worker threads
WorkerThreads 1

## Memory limit, 0 means unlimited

## Examples:
# MaxMemory 100M
# MaxMemory 1G
# MaxMemory 0

## MaxMemory can change online by CONFIG SET MaxMemory xxx
## Default is 0
# MaxMemory 0

## Close the connection after a client is idle for N seconds (0 to disable)
## ClientTimeout can change online by CONFIG SET ClientTimeout N
## Default is 0
ClientTimeout 300


## IO buffer size
## Default is 4096
# BufSize 4096

################################### LOG ########################################
## Log file path
## Unspecify will log to stdout
## Default is Unspecified
# Log ./predixy.log

## LogRotate support

## 1d rotate log every day
## nh rotate log every n hours   1 <= n <= 24
## nm rotate log every n minutes 1 <= n <= 1440
## nG rotate log evenry nG bytes
## nM rotate log evenry nM bytes
## time rotate and size rotate can combine eg 1h 2G, means 1h or 2G roate a time

## Examples:
# LogRotate 1d 2G
# LogRotate 1d

## Default is disable LogRotate


## In multi-threads, worker thread log need lock,
## AllowMissLog can reduce lock time for improve performance
## AllowMissLog can change online by CONFIG SET AllowMissLog true|false
## Default is true
# AllowMissLog false

## LogLevelSample, output a log every N
## all level sample can change online by CONFIG SET LogXXXSample N
LogVerbSample 0
LogDebugSample 0
LogInfoSample 10000
LogNoticeSample 1
LogWarnSample 1
LogErrorSample 1


################################### AUTHORITY ##################################
Include auth.conf

################################### SERVERS ####################################
Include cluster.conf
# Include sentinel.conf
# Include try.conf


################################### DATACENTER #################################
## LocalDC specify current machine dc
# LocalDC bj

## see dc.conf
# Include dc.conf


################################### COMMAND ####################################
## Custom command define, see command.conf
Include command.conf

################################### LATENCY ####################################
## Latency monitor define, see latency.conf
#Include latency.conf

ClusterServerPool {
    MasterReadPriority 100  #这个是主节点访问权重,如果是只把备节点用作备份不去做读写分离,直接将这个配置成100只去读主节点就好了。
    Password sjwkk123456 # redis实例的访问密码
    StaticSlaveReadPriority 0  # 读写分离功能,从静态redis slave节点执行读请求的优先级,所谓静态节点,是指在本配置文件中显示列出的redis节点,不指定的话为0
    DynamicSlaveReadPriority 0 # 功能见上,所谓动态节点是指在本配置文件中没有列出,但是通过redis sentinel动态发现的节点,不指定的话为0
    RefreshInterval 1 # predixy会周期性的请求redis sentinel以获取最新的集群信息,该参数以秒为单位指定刷新周期,不指定的话为1秒
    ServerTimeout 1 # 请求在predixy中最长的处理/等待时间,如果超过该时间redis还没有响应的话,那么predixy会关闭同redis的连接,并给客户端一个错误响应,对于blpop这种阻塞式命令,该选项不起作用,为0则禁止此功能,即如果redis不返回就一直等待,不指定的话为0
    ServerFailureLimit 10 # 一个redis实例出现多少次才错误以后将其标记为失效,不指定的话为10
    ServerRetryTimeout 1 # 一个redis实例失效后多久后去检查其是否恢复正常,不指定的话为1秒
    KeepAlive 120 #predixy与redis的连接tcp keepalive时间,为0则禁止此功能,不指定的话为0
    Servers {
    ## 配置所有节点地址就好了
        + 127.0.0.1:7001
        + 127.0.0.1:7002
        + 127.0.0.1:7003
        + 127.0.0.1:7004
        + 127.0.0.1:7005
        + 127.0.0.1:7006
    }
}

Authority {
    Auth "123456" {
        Mode admin
    }
}

CustomCommand {
   bf.reserve {
       Mode write
       MinArgs 4
       MaxArgs 7
   }

   bf.add {
       Mode write
       MinArgs 3
       MaxArgs 3
   }

   bf.madd {
       Mode write
       MinArgs 3
       MaxArgs 9999
   }

   bf.insert {
       Mode write
       MinArgs 4
       MaxArgs 9999
   }

   bf.exists {
       Mode read
       MinArgs 3
       MaxArgs 3
   }

   bf.mexists {
       Mode read
       MinArgs 3
       MaxArgs 9999
   }

   bf.scandump {
       Mode admin
       MinArgs 3
       MaxArgs 3
   }

   bf.loadchunk {
       Mode admin
       MinArgs 4
       MaxArgs 4
   }

   bf.info {
       Mode read
   }

   cf.reserve {
          Mode write
          MinArgs 3
          MaxArgs 9
      }

      cf.add {
          Mode write
          MinArgs 3
          MaxArgs 3
      }

      cf.addnx {
          Mode write
          MinArgs 3
          MaxArgs 3
      }

      cf.insert {
          Mode write
          MinArgs 4
          MaxArgs 9999
      }

      cf.insertnx {
          Mode write
          MinArgs 4
          MaxArgs 9999
      }

      cf.exists {
          Mode read
          MinArgs 3
          MaxArgs 3
      }

      cf.del {
          Mode read
          MinArgs 3
          MaxArgs 3
      }

      cf.count {
          Mode read
          MinArgs 3
          MaxArgs 3
      }

      cf.scandump {
          Mode admin
          MinArgs 3
          MaxArgs 3
      }

      cf.loadchunk {
          Mode admin
          MinArgs 4
          MaxArgs 4
      }

      cf.info {
          Mode read
      }

}

8. ok 启动 ./src/predixy ./conf/predixy.conf

五 总结

predixy + redis-cluster 就是我们项目实际用的redis高可用模式,实际上还有一层就是硬负载对三个predixy进行轮询请求,这块我们是接触不到的。

安装教程参考

juejin.cn/post/686370…

blog.csdn.net/qq_34944535…