AWS ElasticCache – Redis 101 动手实验

一、 Redis 几种模式和选择建议

1、Cluster Mode Disable 模式 – 单节点

在创建Redis的第一个选项就是是否选择 “Cluster Mode enabled”。如果不选中,这表示 Disable 。这时候,Redis的数据不能处理分片,Redis只能是主备集群。

在创建过程中,如果设置Replcia=0,将关闭Multi-AZ选项,这样将获得一个单节点的Redis。

此时,创建完毕的Redis的Endpoint在控制台上将显示为如下。

Configuration Endpoint: -
Primary Endpoint: single.hzvgog.0001.cnw1.cache.amazonaws.com.cn:6379
Reader Endpoint: -

在这个模式下,Primary对应的Endpoint就是唯一访问入口。

2、Cluster Mode Disable 模式 – 主备多节点且读写分离

在此模式下,因为Cluster没有启用,Redis将不支持分片,但是Redis将提供高可用和读写分离支持。在创建时候,可以输入Replica的数量,设置为1则表示1个写入节点(Primary)和1个只读节点(Reader)。设置为2则表示2个只读节点。

此时,Multi-AZ选项是可以打开或关闭的。如果选中Multi-AZ,那么这个Redis集群将分散在不同AZ。如果关闭Multi-AZ,那么这个集群将都在一个AZ内。

此时,创建完毕的Redis的Endpoint在控制台上将显示为如下。

Configuration Endpoint: -
Primary Endpoint: master.non-cluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
Reader Endpoint: replica.non-cluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379

在这个模式下,Primary对应的Endpoint就是写入的入口,Reader Endpoint对应的是读取的入口。

3、Cluster Mode Enable 模式 – 分片+主备模式

在此模式下,创建Redis第一步就选中Cluster Mode enabled。此时在创建中可指定Shards数量,也就是分片数量。例如将分片配置为4,Replica设置为1,那么总共将获得4个分片,每个分片一个写入节点一个只读节点,总共8个节点。

此时,Multi-AZ选项依然是可以打开或关闭的。如果选中Multi-AZ,那么这个Redis集群将分散在不同AZ。如果关闭Multi-AZ,那么这个集群将都在一个AZ内。

此外,也可以通过创建集群界面上的分布定义功能,手工指定各分片所在的AZ。一般使用默认值不用修改。

此时,创建完毕的Redis的Endpoint在控制台上将显示为如下。

Configuration Endpoint: clustercfg.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
Primary Endpoint: -
Reader Endpoint: -

在这个模式下,所有访问都通过集群节点。访问集群模式需要使用独立的集群SDK,与访问非集群模式的库不一样。集群模式的接口可以自动计算要写入redis的值的CRC16值,并将其自动定位到对应的分片上。由此,使用这个Endpoint,就可以实现自动的定向和访问。

4、几种模式选择建议

数据量比较小时候:

非集群模式:如果数据量很小,那么没必要分片,就选普通主备,replica=1,有1个主节点,1个副本,总计1+1=2节点。安全,不怕单AZ挂,这是最便宜模式。如果只读压力大,可增加只读节点。

数据量中等:

  • 集群模式:最小可以2分片,replica=0,每个分片自有1个主节点,没有副本,总计2节点。但这个没有副本,不安全,一台节点挂了就down机了。因此这种模式不推荐。
  • 集群模式:最小可以2分片,replica=1,每个分片自有1个主节点,1个副本,总计2×2=4节点。安全,不怕单AZ挂。如果只读压力大,可增加replica数量,增加只读节点。
  • 集群模式:如果有3个AZ,可以三分片,replica=1,每个分片自有1个主节点,1个副本,总计3×2=6节点。这样把三个AZ都充分跑起来。如果只读压力大,可增加replica数量,增加只读节点。

数据量比较大:

  • 集群模式:如果数据量比较大,那么分片就需要多一些,例如可以8个分片,replica=1,每个分片自有1个主节点,1个副本,总计8×2=16节点。这样压力就很分散,一个数据来了,集群会决定按照hash值决定写哪个分片的第几分片。如果只读压力大,可增加replica数量,增加只读节点。

二、创建Redis集群

1、创建安全组

首先进入VPC界面,进入安全规则组(Security Group),创建新的安全规则组。规则如下:

  • 入栈:放行TCP端口6379来自内网172.31.0.0/16的流量(请替换为您的VPC实际网段)
  • 出栈:放行所有流量

请记录下名称,稍后会使用。

2、创建子网组

Redis和RDS一样,需要一个子网组(Subnet Group),才能将Redis集群落地到VPC内。

通过Redis控制台左侧的子网组新建一个,选择当前要使用的VPC,选择所有AZ和对应子网即可。请记录下名称,稍后会使用。

3、创建Redis集群

请分别创建Cluster模式OFF/ON模式各一个,创建时候选择如下参数:

  • 集群模式选中
  • 设置名称、版本、端口等常规选项
  • 选项组位置已经使用了集群参数组,不需要调整
  • Node Type节点类型请选为需要的类型
  • 分片(Number of Shard)设置为4分片(集群模式下有效)
  • 副本(Replicas)设置为1
  • 多AZ(Multi-AZ)选中
  • 子网组(Subnet Group)选择上一步设置的子网
  • 高级设置部分主要是分片和数据分布及可用区设置,默认设置不需要修改
  • 在安全部分,安全规则组(Security Group)中点击编辑按钮,首先取消对Default的选择,然后在选择上一步设置的新的安全规则组。注意一定要取消default的选择,不要同时选中多条。如果安全规则组比较多,需要按翻页键才可以显示
  • 选中Encryption at-rest加密,密钥选择default即可,这个选项是落盘加密,可以理解为存储级别加密
  • 选中Encryption in-transit加密,这个选项是传输过程加密,可以理解为SSL方式连接,此时页面会弹出Redis AUTH选项,选中这个选项,并设置Redis AUTH Token即访问密码,密码需要16位字母和数字,不需要特殊字符即可
  • 其余选项可以不再修改,直接点击右下角创建完成

创建时候需要注意,AWS遵循极高的安全标准,如果要启用Redis Auth身份验证,则必须打开传输加密,二者是强制一起打开的关系。如果关闭了传输加密(SSL),那么也就无法启用Auth认证。

三、准备测试环境

1、获取访问地址

首先从Redis界面上,看到当前集群的Endpoint,这个Endpoint只能在VPC内网访问。可以从VPC内的EC2上Ping过去,也可以从VPC外(例如本地笔记本电脑)Ping过去都可以发现这个endpoint是解析到VPC内网IP的。因此Redis只能在内网访问。在程序中访问,请使用Endpoint域名。

本文第一章节已经描述过不同的Redis集群模式,Endpoint也将显示不同的信息,这里不再赘述。

2、准备EC2环境

在本VPC内创建一个EC2,创建使用较小的规格例如t2.small即可。创建时候使用如下的Userdata脚本进行初始化:

#! /bin/bash
yum update -y
yum install git gcc openssl-devel python3 -y
/bin/python3 -m pip install --upgrade pip
/bin/python3 -m pip install boto3
/bin/python3 -m pip install redis
/bin/python3 -m pip install redis-py-cluster --user
reboot

由此即可准备好环境。

3、Redis-cli安装

Redis-cli在大部分系统中都没有提供预先编译好的RPM包客户端,建议使用从源代码编译安装的方法。用来做测试的客户端建议使用Redis-6.0.6以上版本,这是因为截止5.0.9的Redis客户端cli并没有提供SSL支持,无法连接传输中加密和Auth的服务器。编译Redis-6的客户端,可以向下兼容连接到5版本上。

请使用前文创建的EC2,系统为Amazon Linux 2系统,兼容CentOS 7。在初始化这个EC2后,已经通过userdata安装了gcc和openssl-devel环境,因此接下来直接编译即可。执行如下命令。

wget https://s3.cn-north-1.amazonaws.com.cn/lxy-sa-software/redis-6.0.6.tar.gz
tar zxvf redis-6.0.6.tar.gz
cd redis-6.0.6
make BUILD_TLS=yes MALLOC=libc

注意网上很多文档,没有加上TLS支持,因此编译后的redis-cli是无法连接带SSL传输加密和AUTH认证的集群。至此编译完成,在src目录下即可获得客户端redis-cli的可执行文件。

四、测试场景介绍

接下来,我们将针对两个选项,即是否集群/是否SSL加密分别组合出四种模式,分别进行测试。

  • 四、非集群、不启用SSL+无AUTH认证
  • 五、非集群、启用SSL+有AUTH认证
  • 六、集群、不启用SSL+无AUTH认证
  • 七、集群、启用SSL+有AUTH认证

需要注意的是,不同语言使用的是不同的客户端也就是redis库,支持的功能也不完全一样,请通过这里查询:

https://redis.io/clients

五、非集群模式、不启用SSL传输中加密和不启用Auth认证的测试

在前文创建Redis集群时候做过介绍,SSL传输加密和Auth认证功能是互相依存的,当打开了密码认证,就必须启用SSL方式登录。当创建了一个非加密的集群且没有密码认证的集群的时候,建议通过安全规则组互信的方式来限制可访问来源,连接方式可以使用如下方式连接:

1、CLI方式

此模式CLI默认支持。

./redis-cli -h non-ssl.hzvgog.ng.0001.cnw1.cache.amazonaws.com.cn -p 6379

连接后执行set key value命令,如下操作表示连接集群成功。

[root@ip-172-31-43-79 src]# ./redis-cli -h non-ssl.hzvgog.ng.0001.cnw1.cache.amazonaws.com.cn -p 6379
non-ssl.hzvgog.ng.0001.cnw1.cache.amazonaws.com.cn:6379> set name liuxinyou
OK
non-ssl.hzvgog.ng.0001.cnw1.cache.amazonaws.com.cn:6379> get name
"liuxinyou"
non-ssl.hzvgog.ng.0001.cnw1.cache.amazonaws.com.cn:6379> quit
[root@ip-172-31-43-79 src]#

测试完成。

2、Python代码方式(略)

本模式非本文测试重点,略。

六、非集群模式,开启传输中加密和启用Auth认证的测试

1、CLI测试

(1)连接到非Cluster模式的、且开启了SSL和Auth加密的Redis

执行如下命令连接。

~/redis-6.0.6/src/redis-cli -h master.non-cluster-with-ssl.hzvgog.cnw1.cache.amazonaws.com.cn -p 6379 -a 1qazxsw23edcvfr4 --tls

连接后执行set命令设置一个值,并执行get取回,可以看到工作正常。

[ec2-user@ip-172-31-43-79 ~/redis-6.0.6]$ src/redis-cli -h master.non-cluster-with-ssl.hzvgog.cnw1.cache.amazonaws.com.cn -p 6379 -a 1qazxsw23edcvfr4 --tls
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
master.non-cluster-with-ssl.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set name hehe
OK
master.non-cluster-with-ssl.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get name
"hehe"
master.non-cluster-with-ssl.hzvgog.cnw1.cache.amazonaws.com.cn:6379>

由此可以看到在使用Redis-6.0.6的客户端,在编译时候打开了tls支持,即可正常连接启用了传输中加密和Auth身份认证的Redis节点。

2、Python脚本测试

Python程序调用的redis库支持ssl传输中加密,在配置文件中增加ssl=True即可。编辑如下python文件,文件名叫做 noncluster-ssl.py ,保存路径不限。

#!/usr/bin/env python
# -*- coding:utf8 -*-

import redis

r = redis.Redis(
        host='master.redis-02.hzvgog.cnw1.cache.amazonaws.com.cn',
        port=6379,
        password='1qazxsw23edcvfr4',
        ssl=True,
        ssl_cert_reqs=None
        )
r.set('name','liuxinyou-redis-with-auth')

print(r.get('name').decode('utf8'))

请替换其中的信息为实际环境的Endpoint和密码。其中注意声明ssl启用的True是区分大小写的。

执行命令。执行时候注意使用Python3,因为Userdata准备环境时候是使用Python3环境安装的依存库。

python3 noncluster-ssl.py

返回结果就是在代码中设置的name的值,这表示成功,例如结果如下。

[ec2-user@ip-172-31-43-79 ~]$ python3 noncluster-ssl.py
liuxinyou-redis-with-auth
[ec2-user@ip-172-31-43-79 ~]$

由此测试非集群模式下的SSL支持完毕。

七、集群模式、但不启用SSL传输中加密和不启用Auth认证的测试

1、Redis-CLI命令行测试

此模式CLI默认支持。使用如下命令连接。

./redis-cli -h cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn -p 6379 -c

在集群模式下,与上一个步骤的区别是,增加了一个 -c 参数,表示集群模式。执行如下 cluster slots 可显示本集群的分片。返回结果如下。

cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> cluster slots
1) 1) (integer) 12288
   2) (integer) 16383
   3) 1) "172.31.42.163"
      2) (integer) 6379
      3) "ea92f2c730c604e2bd14131b7a35e4c8079e7acc"
   4) 1) "172.31.29.206"
      2) (integer) 6379
      3) "11868c727fe7970c6a8fd8c0ff168cf716aa1e2c"
2) 1) (integer) 8192
   2) (integer) 12287
   3) 1) "172.31.1.74"
      2) (integer) 6379
      3) "635ec827b4101b25f583b4520c75525fc837078f"
   4) 1) "172.31.28.71"
      2) (integer) 6379
      3) "c2239edbd9cfecaa0b96600a31228cf91d3ac001"
3) 1) (integer) 0
   2) (integer) 4095
   3) 1) "172.31.22.206"
      2) (integer) 6379
      3) "9415d33656edf7a523ec3ea349abce93fd3dec9b"
   4) 1) "172.31.41.149"
      2) (integer) 6379
      3) "e051f4c848adde3a3159726b3ffa12425211852f"
4) 1) (integer) 4096
   2) (integer) 8191
   3) 1) "172.31.36.166"
      2) (integer) 6379
      3) "df1489f0614baaadfc06d8e7a8e9dd167af8ae2f"
   4) 1) "172.31.6.253"
      2) (integer) 6379
      3) "6146446d8e07679cc4300cb3371ee92a1de776d5"
cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379>

接下来测试下如果写入的key名称是zhangsan,会写入哪一个分片。

cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> cluster keyslot zhangsan
(integer) 12767
cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379>

由此可看到,redis计算CRC16后,确认分片slot是12767,根据上文显示的cluster集群信息,12767在8192和12287自建,因此将写入第2个分片。由于使用Redis-cli时候增加了-c参数,是专门支持集群模式的,因此在接下来写入数据时候,是不需要介意分片规则的,Redis集群会自动跳转和写入到对应分片。

尝试写入数据。使用set命令加字符串写入集群,可以看到cluster模式下的CLI自动完成了集群到不同分片的跳转。

cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> set zhangsan myname
OK
cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> get zhangsan
"myname"
cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> set lisi myname
OK
cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn:6379> set wangwu myname
-> Redirected to slot [9439] located at 172.31.1.74:6379
OK
172.31.1.74:6379> set ba myname
-> Redirected to slot [4559] located at 172.31.36.166:6379
OK
172.31.36.166:6379>

至此CLI测试完成。

2、Python脚本测试

此步骤中,调用的库不再是前文的Redis库,而是改为了RedisCluster库以支持集群模式。编辑如下python文件,文件名可以叫做 cluster-nossl.py ,保存路径不限。

#!/usr/bin/env python
# -*- coding:utf8 -*-

from rediscluster import RedisCluster

startup_nodes = [{
    "host": "cluster-wo-ssl.hzvgog.clustercfg.cnw1.cache.amazonaws.com.cn",
    "port": "6379" }]

rc = RedisCluster(
        startup_nodes=startup_nodes,
        decode_responses=True,
        skip_full_coverage_check=True)

print("")
print("# Show Cluster slot information")
print(rc.cluster('slots'))

print("")
print("# Show zhangsan key-slot mapping")
print(rc.cluster('keyslot', 'zhangsan'))

print("")
print("# Write zhangsan into cluster")
rc.set("zhangsan", "Zhangsan's message is xxxxx")
print("Done")

print("")
print("# Read from cluster")
print(rc.get("zhangsan"))

运行后反馈结果如下表示Cluster组件工作正常。

[ec2-user@ip-172-31-43-79 ~]$ python3 cluster-nossl.py

# Show Cluster slot information
{(12288, 16383): {'master': ('172.31.42.163', 6379), 'slaves': [('172.31.29.206', 6379)]}, (0, 4095): {'master': ('172.31.22.206', 6379), 'slaves': [('172.31.41.149', 6379)]}, (8192, 12287): {'master': ('172.31.1.74', 6379), 'slaves': [('172.31.28.71', 6379)]}, (4096, 8191): {'master': ('172.31.36.166', 6379), 'slaves': [('172.31.6.253', 6379)]}}

# Show zhangsan key-slot mapping
12767

# Write zhangsan into cluster
Done

# Read from cluster
Zhangsan's message is xxxxx
[ec2-user@ip-172-31-43-79 ~]$

由此表示Python通过RedisCluster库可以很好的支持集群模式。

八、集群模式、并且启用SSL传输中加密和启用Auth认证的测试

1、CLI测试

使用前文编译时候启用了TLS=yes的客户端,连接集群Endpoint地址。

./redis-cli -h clustercfg.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn -p 6379 -c --tls -a 1qazxsw23edcvfr4

连接成功后,实测写入,可以正常写入,Redis-cli会自动将数据定向到对应的分片上。

lustercfg.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set zhangsan 123
-> Redirected to slot [12767] located at mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
OK
mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set lisi 123
OK
mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set wangwu 123
-> Redirected to slot [9439] located at mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
OK
mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set aa 123
-> Redirected to slot [1180] located at mycluster-0001-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
OK
mycluster-0001-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> set bb 123
-> Redirected to slot [8620] located at mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
OK
mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379>

再测试读取。如下信息可看到从对应的分片上读取过程也正常。

mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get zhangsan
-> Redirected to slot [12767] located at mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
"123"
mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get lisi
"123"
mycluster-0004-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get wangwu
-> Redirected to slot [9439] located at mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
"123"
mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get aa
-> Redirected to slot [1180] located at mycluster-0001-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
"123"
mycluster-0001-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379> get bb
-> Redirected to slot [8620] located at mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379
"123"
mycluster-0003-001.mycluster.hzvgog.cnw1.cache.amazonaws.com.cn:6379>

至此CLI的测试完成。

2、Python测试

推荐使用Python插件redis-py-cluster。具体Demo脚本待补充。

https://github.com/Grokzen/redis-py-cluster

九、参考文档

Redis的几种类型

https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/Clusters.html

访问集群模式的Redis

https://aws.amazon.com/cn/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/

访问集群模式的Redis

https://aws.amazon.com/cn/blogs/china/how-to-work-with-cluster-mode-on-amazon-elasticache-for-redis-files/

Redis传输加密

https://aws.amazon.com/cn/premiumsupport/knowledge-center/elasticache-connect-redis-node/

https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#connect-tls

Redis身份验证

https://docs.aws.amazon.com/zh_cn/AmazonElastiCache/latest/red-ug/auth.html