最近做了系统的权限以及动态权限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-6506
6 个文件夹, 因为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
中, 其他的服务器在订阅事件处理中清空一级缓存. 利用redis
的SETNX
和GETSET
命令来锁住缓存对象, 防止并发时数据错误覆盖和死锁. 当然, 这只是一个简单的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)
|