- [1. 统计活跃用户](#1-统计活跃用户) - [2. 搭建高可用redis集群](#2-搭建高可用redis集群) - [1. 常见redis集群](#1-常见redis集群) - [2. 单机版redis集群](#2-单机版redis集群) - [2.1 修改redis配置文件](#21-修改redis配置文件) - [2.2 重新打包redis镜像](#22-重新打包redis镜像) - [2.3 编辑docker-compose.yml文件](#23-编辑docker-composeyml文件) - [2.4 创建redis集群](#24-创建redis集群) - [2.5 创建带有密码的redis集群](#25-创建带有密码的redis集群) - [2.6 创建集群中遇到的问题](#26-创建集群中遇到的问题) # 1. 统计活跃用户 场景: 1亿个用户,用户登陆,标记为今天活跃,否则记为不活跃,记录最活跃用户。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 思路
每个用户在数据库都有一个id,用第id个位的0和1来表示是否登录,例如:
login0721: '011001...............0'
......
login0726: '011001...............0'
login0727: '0110000.............1'

# 实现过程
(1) 记录用户登陆,每天按日期生成一个位图,用户登陆后,把user_id位上的bit值置为1
首先把所有用户的位置位0
redis 127.0.0.1:6379> setbit login0721 100000000 0
(integer) 0
redis 127.0.0.1:6379> setbit login0721 3 1
(integer) 0
redis 127.0.0.1:6379> setbit login0721 5 1
(integer) 0
redis 127.0.0.1:6379> setbit login0721 7 1
(integer) 0
......
redis 127.0.0.1:6379> setbit login0722 100000000 0
(integer) 0
redis 127.0.0.1:6379> setbit login0722 3 1
(integer) 0
redis 127.0.0.1:6379> setbit login0722 5 1
(integer) 0
redis 127.0.0.1:6379> setbit login0722 8 1
(integer) 0
......
redis 127.0.0.1:6379> setbit login0723 100000000 0
(integer) 0
redis 127.0.0.1:6379> setbit login0723 3 1
(integer) 0
redis 127.0.0.1:6379> setbit login0723 4 1
(integer) 0
redis 127.0.0.1:6379> setbit login0723 6 1
(integer) 0
......
(2)把1周/月的位图用and计算, 位为1的是连续登陆的用户。
redis 127.0.0.1:6379> bitop and login0721 login0722 login0723......
(integer) 12500001

# 优点
(1) 节约空间,用1亿bit表示1亿人每天的登陆情况,1亿bit约为10M。
(2) 计算方便,计算速度非常快
# 2. 搭建高可用redis集群 ## 1. 常见redis集群 常见redis集群有RedisCluster、Codis、Twemproxy,其中Codis、Twemproxy是有中心节点的,而RedisCluster是没中心节点,而且是redis内置的集群方案,推荐使用redisCluster集群。 redisCluster特点: - 无中心节点,客户端与 redis节点直连,不需要中间代理层。 - 数据可以被分片存储,集群数据加起来就是全量数据。 - 可以通过任意一个节点,读写不属于本节点的数据。 - 管理方便,后续可自行增加或删除节点。 由于RedisCluster是分片存储,当集群中一个节点故障时,会损失该节点数据,为了实现高可用,需要对每个节点各添加一个从节点,形成主从同步,当主redis(集群节点)出现故障时,从节点替换故障的主节点。 - Redist集群中的数据库复制是通过主从同步来实现的。 - 主节点( Master)把数据分发给从节点(Slave)。 - 主从同步的好处在于高可用, Redis节点有冗余设计。 - 集群节点个数最好是奇数并且3个以上, 奇数个的好处是,有一个节点出现故障了,集群数量过半数,集群可以继续正常使用,数量少于半数则认为集群瘫痪了。 ![](https://gitee.com/krislin_zhao/IMGcloud/raw/master/img/20200601094320.png) 如果客户端本身带有负载均衡功能,可以省去使用haproxy搭建负载均衡,也可以在程序简单的实现负载均衡功能。 ## 2. 单机版redis集群 在单机上搭建3个节点的集群,3个主节点分别有各自的从节点,如图所示: ![](https://gitee.com/krislin_zhao/IMGcloud/raw/master/img/20200601094436.png) ### 2.1 修改redis配置文件 因为官方镜像中没有redis配置,也没有启动redis,需要去官方下载对应版本的redis源码获取redis.conf和redis-trib.rb文件,下载官方源码地址:http://download.redis.io/releases/
1
2
3
4
5
6
7
8
9
10
11
mkdir redis-cluster
cd redis-cluster
wget http://download.redis.io/releases/redis-4.0.11.tar.gz
tar zxvf redis-4.0.11.tar.gz

# 从源码中复制redis.conf和redis-trib.rb文件到当前目录
cp redis-4.0.11/redis.conf .
cp redis-4.0.11/src/redis-trib.rb .

# 删除redis源码文件
rm -rf redis-4.0.11 redis-4.0.11.tar.gz
因为redis默认没有开启集群功能,需要修改redis配置文件redis.conf,主要修改下面几个参数
1
2
3
4
5
bind 0.0.0.0 # 允许外部登录
cluster-enabled yes # 开启集群
cluster-config-file nodes-6379.conf # 集群配置文件
cluster-node-timeout 15000 # 超时时间
appendonly yes # 并开启AOF模式
### 2.2 重新打包redis镜像 下载指定版本redis官方镜像 > docker pull redis:4.0.11 因为官方redis镜像不能满足搭建redis集群要求,需要在官方镜像基础上添加ruby和启动redis命令功能,在当前目录创建Dockerfile文件,文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
FROM redis

# 安装ruby
RUN apt-get -y update
RUN apt-get -y install ruby
RUN apt-get -y install rubygems
# ruby 安装redis接口
RUN gem install redis
# 安装vim
RUN apt-get -y install vim

# 启动redis
CMD redis-server /usr/local/etc/redis/redis.conf
### 2.3 编辑docker-compose.yml文件 在当前目录创建docker-compose.yml文件来管理容器,共6个容器,文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
version: "3"

services:

redis-node1:
build:
context: .
dockerfile: Dockerfile
ports:
- 20001:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
# 创建集群的配置文件,只需创建一次,其他节点不需要映射此文件
- ./redis-trib.rb:/usr/local/etc/redis/redis-trib.rb
networks:
- redis-net

redis-node2:
build:
context: .
dockerfile: Dockerfile
ports:
- 20002:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-net

redis-node3:
build:
context: .
dockerfile: Dockerfile
ports:
- 20003:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-net

redis-node4:
build:
context: .
dockerfile: Dockerfile
ports:
- 20004:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-net

redis-node5:
build:
context: .
dockerfile: Dockerfile
ports:
- 20005:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-net

redis-node6:
build:
context: .
dockerfile: Dockerfile
ports:
- 20006:6379
volumes:
- ./redis.conf:/usr/local/etc/redis/redis.conf
networks:
- redis-net

networks:
redis-net:
driver: bridge
### 2.4 创建redis集群 当前目录下完整文件列表如下所示:
1
2
3
4
5
.
├── docker-compose.yml
├── Dockerfile
├── redis.conf
└── redis-trib.rb
准备好文件后,开始创建redis集群:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 先打包好新的redis镜像
docker-compose build

# 启动容器
docker-compose up -d

# 获取所有启动redis容器ip地址,获取ip地址是用来创建集群准备
docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq) | grep redis

# 执行命令的结果如下:
# /redis-cluster_redis-node2_1 - 172.20.0.6
# /redis-cluster_redis-node4_1 - 172.20.0.7
# /redis-cluster_redis-node6_1 - 172.20.0.4
# /redis-cluster_redis-node1_1 - 172.20.0.5
# /redis-cluster_redis-node5_1 - 172.20.0.3
# /redis-cluster_redis-node3_1 - 172.20.0.2

# 进入redis-node1容器,因为只有redis-node1容器映射了redis-trib.rb文件
docker-compose exec redis-node1 bash

# 创建集群
/usr/local/etc/redis/redis-trib.rb create --replicas 1 172.20.0.2:6379 172.20.0.3:6379 172.20.0.4:6379 172.20.0.5:6379 172.20.0.6:6379 172.20.0.7:6379

# 其中参数--replicas 1表示每个主节点有一个从节点。
# 在创建集群过程会提示Can I set the above configuration? 在终端输入yes即可,如果不出现错误,很快就完成集群的创建。

# 创建完集群后,在任意一个redis节点都可以进入redis集群,-c表示连接的是集群
redis-cli -c

# 查看集群节点
127.0.0.1:6379> cluster nodes

# afb979236e96b6e9aac972af7508e4cd9505676d 172.20.0.6:6379@16379 slave 9715f836310b872961a7defc64bdb4a319f9848d 0 1537636386000 5 connected
# 1ffa00413a5f75465e1bb5aaef551c38fb3db1f3 172.20.0.5:6379@16379 myself,master - 0 1537636387000 7 connected 10923-16383
# 9715f836310b872961a7defc64bdb4a319f9848d 172.20.0.2:6379@16379 master - 0 1537636387811 1 connected 0-5460
# d59a0ad710f35fe349f62eda4279e02972983fd3 172.20.0.3:6379@16379 master - 0 1537636386000 2 connected 5461-10922
# c9371c4936d12b9f764e5bf5a7257928aa36cbc2 172.20.0.7:6379@16379 slave d59a0ad710f35fe349f62eda4279e02972983fd3 0 1537636385000 6 connected
# b39a684ad281f03c1befcd90048c503d95526645 172.20.0.4:6379@16379 slave 1ffa00413a5f75465e1bb5aaef551c38fb3db1f3 0 1537636386807 7 connected

# 测试集群的主从复制
127.0.0.1:6379> set testkey 100
# -> Redirected to slot [4757] located at 172.20.0.2:6379
# OK

# 根据172.20.0.2查到对应节点为redis-node3,暂停该容器
docker-compose pause redis-node3

# 然后再次读看是否能够读取到数据
172.20.0.2:6379> get testkey
# "100"

# 此时可以查看到集群节点状态,显示172.20.0.2和集群连接失败状态
127.0.0.1:6379> cluster nodes
### 2.5 创建带有密码的redis集群 实际使用中一般连接redis是需要密码授权的,添加密码很简单,创建集群前修改redis.conf配置和gems的redis客户端client.rb配置。 删除没有密码的集群容器,重新建一个集群,然后在原来基础上修改配置文件。 > docker-compose down 修改redis.conf配置
1
2
masterauth 123456
requirepass 123456
进入redis-node1容器,修改redis客户端client.rb配置
1
2
3
4
5
6
7
8
9
10
11
# 找出client.rb配置文件位置
find / -name client.rb

# 在配置中添加密码
# 把 :password => nil 改为 :password => 123456

# 创建集群
/usr/local/etc/redis/redis-trib.rb create --replicas 1 172.20.0.2:6379 172.20.0.3:6379 172.20.0.4:6379 172.20.0.5:6379 172.20.0.6:6379 172.20.0.7:6379

# 带密码登录集群
redis-cli -a 123456 -c
### 2.6 创建集群中遇到的问题 > redis-trib.rb create –replicas 1 redis-node1:6379 redis-node2:6379 redis-node3:6379 redis-node4:6379 redis-node5:6379 redis-node6:6379 问题1:使用容器名创建去创建集群报错:”ERR Invalid node address specified” > 答:redis-trib.rb 不支持域名或主机名,必须使用ip:port的方式 问题2:创建集群时报错:err slot 0 is already busy (redis::commanderror) > 答:由于第一次创建集群没有成功,但还在待创建状态,需要将nodes.conf和dir里面的文件全部删除,如果是在docker创建的话,删除容器重新创建。