使用docker建立redis集群提供系统缓存

最近做了系统的权限以及动态权限sql和配置库, 为了提升性能, 都做到了缓存里面, 缓存方法是, 当更新内容时同步写入锁清空缓存, 读取数据时使用可升级读取锁来读取缓存, 如果缓存为空时候升级写入锁读取数据库并写入缓存. 这样在单服务器上是比较好的读写策略了, 但是在多台服务器上却不能这样使用, 而需要使用其他的服务器来提供订阅更新等机制. 目前使用了redis.

docker

为了redis的高可用, 需要创建redis集群, 这里选择建立在多个docker环境中. 首先安装docker.

1
2
3
sudo apt-get install curl //安装curl
curl -sSL https://get.docker.com/ | sh //获取最近版本docker
docker run hello-world //安装完成以后测试是否成功

Dockerfile

创建Dockerfile文件.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// /usr/local/docker-files/Dockerfile
FROM redis:4.0.1
MAINTAINER zhoucong

ENV REDIS_HOME /usr/local

RUN mkdir $REDIS_HOME/conf
WORKDIR $REDIS_HOME/conf

## 创建一个redis.conf文件,打开集群相关配置,默认端口不写的话为6379
RUN echo "cluster-enabled yes" > redis.conf
RUN echo "cluster-config-file redis-nodes.conf" >> redis.conf

## 初始化容器时启动redis实例
CMD ["redis-server","/usr/local/conf/redis.conf"]

redis-container

根据Dockerfile创建容器.

1
docker build -t zhoucong/redis-test .

下载完成以后, 在/usr/local/redis/conf/下分别建立6501-65066 个文件夹, 因为redis集群至少需要 3 台主从机. 在每个文件夹下建立配置文件.

1
2
3
cluster-enabled yes
cluster-config-file redis-nodes.conf
port 6501 //port(n)

start docker

启动这些 redis 节点

1
2
3
4
5
6
docker run -d --name redis-m-01 -v /usr/local/redis/conf/6501/:/usr/local/conf -p 6501:6501 -p 16501:16501 zhoucong/redis-test
docker run -d --name redis-m-02 -v /usr/local/redis/conf/6502/:/usr/local/conf -p 6502:6502 -p 16502:16502 zhoucong/redis-test
docker run -d --name redis-m-03 -v /usr/local/redis/conf/6503/:/usr/local/conf -p 6503:6503 -p 16503:16503 zhoucong/redis-test
docker run -d --name redis-c-04 -v /usr/local/redis/conf/6504/:/usr/local/conf -p 6504:6504 -p 16504:16504 zhoucong/redis-test
docker run -d --name redis-c-05 -v /usr/local/redis/conf/6505/:/usr/local/conf -p 6505:6505 -p 16505:16505 zhoucong/redis-test
docker run -d --name redis-c-06 -v /usr/local/redis/conf/6506/:/usr/local/conf -p 6506:6506 -p 16506:16506 zhoucong/redis-test

在主机中安装好redis后, 进入/redis/src/, 执行命令

redis

make redis-cluster

1
2
3
4
5
6
7
8
9
sudo gem install redis //安装ruby的redis模块

//创建集群
ruby redis-trib.rb create --replicas 1 \
10.200.200.227:6501 10.200.200.227:6502 10.200.200.227:6503 \
10.200.200.227:6504 10.200.200.227:6505 10.200.200.227:6506

//如果一直出现Waiting for the cluster to join.需要手动设置防火墙
sudo ufw allow 6501-6506 16501-16506

connect redis-cluster

本机连接docker里的redis

1
2
3
4
5
6
7
//如果不使用-c, 会因为插槽不对报错
/redis/src/redis-cli -c -h 10.200.200.227 -p 6501

> set test demo
// -> Redirected to slot [6918] located at 172.17.0.1:6502 ok 成功

> get test // -> demo

redis-lock

到这里就成功了, 在后台使用相关库连接到redis, 然后就可以直接使用了. 缓存做法则改成在服务器中使用一级缓存, 全局使用redis来提供二级缓存, redis里不存在数据时去数据库获取数据并更新到redis中, 当更新数据时候先保存到数据库, 然后清空一级和二级缓存, 同时发布一个事件到redis中, 其他的服务器在订阅事件处理中清空一级缓存. 利用redisSETNXGETSET命令来锁住缓存对象, 防止并发时数据错误覆盖和死锁. 当然, 这只是一个简单的redis锁的实现, 而且不够强壮, 但是对于我们系统的使用已经足够, 而且系统也额外提供了清空和重新读取缓存的功能. 如果想要比较强壮的redis分布式锁, 可以参考这篇文章: 基于 Redis 的分布式锁到底安全吗(上), 基于 Redis 的分布式锁到底安全吗(下).

1
2
3
4
5
6
7
8
9
10
11
//redis防止并发覆盖
while(SETNX(cacheLock,now + 30s) == 0)//设置30s超时
{
if(now > GET(cacheLock) && now > GETSET(cacheLock,now + 30s)){
break;//成功拿到锁, 并给锁设置新值
}else{
Thread.sleep(500);
}
}
//dosth
DEL(cacheLock)

使用docker建立redis集群提供系统缓存

https://mosby-zhou.github.io/2017/05-22-docker-redis/

作者

Mosby

发布于

2017-05-22

许可协议

评论