笔者目前所在公司存在多套 Redis 集群:

  • A 集群 主 + 从 共 60 个分片,部署在 3 + 3 台物理机上,每台机器各承载 10 个端口
  • 主库 30 个端口在广州,从库 30 个端口在中山
  • B 集群共 72 个端口,部署架构一模一样

上云后,均为广东的某个云厂商的 2 个可用区,不再使用 IDC 数据中心,部署架构一致。

有人提出了一个很耐人寻味的问题:

这个架构有问题,如果两地之间网络故障,必定会出现脑裂!

真的会出现脑裂吗?

不至于吧!网络分区后,理论上广州机房是可用的,中山因为没有主(访问从库将槽位重定向回主库),所以中山机房不可用。所以只有一个机房可写,不会脑裂。

猜想终究是猜想,实践出真知!现在 docker 太方便了,搭一个集群模拟一下就 OK 了~

准备环境:

  • 2 台测试机器,模拟双机房环境
  • 每台机器启动 6 个端口,通过 redis-trib 搭建集群

建立以下文件夹,并准备 docker-compose.yml:

mkdir -p ./data/redis/8001/data && \
mkdir -p ./data/redis/8002/data && \
mkdir -p ./data/redis/8003/data && \
mkdir -p ./data/redis/8004/data && \
mkdir -p ./data/redis/8005/data && \
mkdir -p ./data/redis/8006/data && \
mkdir -p ./data/redis/9001/data && \
mkdir -p ./data/redis/9002/data && \
mkdir -p ./data/redis/9003/data && \
mkdir -p ./data/redis/9004/data && \
mkdir -p ./data/redis/9005/data && \
mkdir -p ./data/redis/9006/data

广州机房 6 个端口:

version: '3'

services:
 redis_gz_1:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8001/data:/data
  environment:
   - REDIS_PORT=8001

 redis_gz_2:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8002/data:/data
  environment:
   - REDIS_PORT=8002

 redis_gz_3:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8003/data:/data
  environment:
   - REDIS_PORT=8003

 redis_gz_4:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8004/data:/data
  environment:
   - REDIS_PORT=8004

 redis_gz_5:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8005/data:/data
  environment:
   - REDIS_PORT=8005

 redis_gz_6:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/8006/data:/data
  environment:
   - REDIS_PORT=8006

中山机房 6 个端口:

version: '3'

services:
 redis_zs_1:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9001/data:/data
  environment:
   - REDIS_PORT=9001

 redis_zs_2:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9002/data:/data
  environment:
   - REDIS_PORT=9002

 redis_zs_3:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9003/data:/data
  environment:
   - REDIS_PORT=9003

 redis_zs_4:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9004/data:/data
  environment:
   - REDIS_PORT=9004

 redis_zs_5:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9005/data:/data
  environment:
   - REDIS_PORT=9005

 redis_zs_6:
  image: publicisworldwide/redis-cluster
  network_mode: host
  volumes:
   - ./data/redis/9006/data:/data
  environment:
   - REDIS_PORT=9006

docker-compose up 启动后,使用以下命令搭建集群:

docker run --rm -it inem0o/redis-trib create --replicas 1 \
10.43.2.6:8001 \
10.43.2.6:8002 \
10.43.2.6:8003 \
10.43.2.6:8004 \
10.43.3.7:9004 \
10.43.2.6:8005 \
10.43.3.7:9005 \
10.43.2.6:8006 \
10.43.3.7:9006 \
10.43.3.7:9001 \
10.43.3.7:9002 \
10.43.3.7:9003

你会发现集群搭起来了!有以下提示信息:

...master:
10.43.2.6:8001
10.43.3.7:9004
10.43.2.6:8002
10.43.3.7:9005
10.43.2.6:8003
10.43.3.7:9006
...
Adding replica 10.43.3.7:9001 to 10.43.2.6:8001
Adding replica 10.43.2.6:8004 to 10.43.3.7:9004
Adding replica 10.43.3.7:9002 to 10.43.2.6:8002
Adding replica 10.43.2.6:8005 to 10.43.3.7:9005
Adding replica 10.43.3.7:9003 to 10.43.2.6:8003
Adding replica 10.43.2.6:8006 to 10.43.3.7:9006
...

此时,集群是 广州、中山 各 3 个 master,不符合我们的场景,需要手工切换一下主从:

# 分别在从库 3 个端口做主从切换 10.43.2.6:9004-9006
redis-cli -h 10.43.2.6 -p 8004 CLUSTER FAILOVER
OK
redis-cli -h 10.43.2.6 -p 8005 CLUSTER FAILOVER
OK
redis-cli -h 10.43.2.6 -p 8006 CLUSTER FAILOVER
OK

3 个端口提主成功,10.43.2.6 此时运行 6 个 master,而 10.43.3.7 运行 6 个 slave 示例。

如何断网?很简单,iptables 无敌!

我们在广州(10.43.2.6)丢掉中山(10.43.3.7)的包就好了:

iptables -I INPUT -s 10.43.3.7 -pudp --dport 18001:18006 -j DROP && \
iptables -I INPUT -s 10.43.3.7 -ptcp --dport 18001:18006 -j DROP && \
iptables -I INPUT -s 10.43.3.7 -ptcp --dport 8001:8006 -j DROP && \
iptables -I INPUT -s 10.43.3.7 -pudp --dport 8001:8006 -j DROP

执行后,中山一直打印重连主库失败的日志,主库也探测到从库断开了,通过 CLUSTER NODES 命令可以获取各个节点状态。

结论一:A [6Master/0Slave] + B [0Master/6Slave],A 机房可读可写,B 机房不可读不可写(CLUSTERDOWN)

报错信息如下:

10.43.3.7:9006> set a12 2
(error) CLUSTERDOWN The cluster is down

另外,我还测试了主库分布在双机房的情况:

结论二:A [4Master/2Slave] + B [2Master/4Slave],A 机房可读可写,B 机房不可读不可写(CLUSTERDOWN)

结论三:A [3Master/3Slave] + B [3Master/3Slave],AB 机房均不可读不可写(CLUSTERDOWN)

为什么不可读?

因为请求从库它会自动转发(MOVED)到主库,而主库不可用(达不到半数以上节点),所以彻底凉了!

解决办法是不使用偶数节点,极端情况下(master 均等分布两地)会导致整个集群不可用。

实验完,不要忘了删掉规则,恢复网络:

iptables -D INPUT -s 10.43.3.7 -pudp --dport 18001:18006 -j DROP && \
iptables -D INPUT -s 10.43.3.7 -ptcp --dport 18001:18006 -j DROP && \
iptables -D INPUT -s 10.43.3.7 -ptcp --dport 8001:8006 -j DROP && \
iptables -D INPUT -s 10.43.3.7 -pudp --dport 8001:8006 -j DROP

(完)

最近在开发一个常驻进程、定时任务统一调度系统,以应对开发在进程管理方面遇到的各种复杂问题。

组里开发项目,一般来说是一个人承包整个项目,包括调度器设计,还有后台系统。我还有一部分工作,是队列相关的信息,这个由监控同学负责,到时候我后台聚合他的数据一并展示。

然后我就遇到问题了:

我以前刚入职公司的时候,使用一个开源的后台模板 vue-admin-template 二次开发了一个框架,两三年过去了,因为 nodejs 版本太老有些包下不来,自己升级了 nodejs 后算是解决了问题。

不过呢,我回到家之后想写代码,发现家里电脑和公司电脑环境不一样。因为我新后台系统升级了,旧后台系统咋办?不可能全部都升级 nodejs 的,后台太多了。

这个时候,切换 nodejs 版本显然就很重要了!后来我找到一个包,只需全局安装,就可以自由切换版本,非常好用!

npm install -g n

如果安装不了提示权限问题,可以 sudo 执行。

切换就很方便啦!执行以下命令即可切换到 v16.14.0 版本。

sudo n 16.14.0

一个优秀的产品,真的是简洁为美,用起来是那么的自然。而且,它包名就只有一个字母。

还有其他的用法,就不详细介绍了(好像也用不到),有兴趣可以去官网看看。

题外话:

笔者就职于某上市游戏发行公司,主导整个发行业务线从双 IDC 到腾讯云的搬迁。在此过程中踩了不少坑,便以文章的形式记录下来。

如有错漏之处,敬请指正。

我先简单介绍下我自己:

我是业务开发出身,负责渠道登录/支付业务,熟悉前端,研究后台开发框架后,逐步往运维方向摸索。

业务除了登录/支付业务,也做过风控系统、聊天监控系统,主要是一些防刷保护、敏感词判别、垃圾信息过滤等等。

本系列篇幅较长,共有 7 篇文章,本文是第 7 篇。文章列表:

某上市游戏公司从 IDC 上腾讯云的落地经验(1)——上云必要性与方案设计
某上市游戏公司从 IDC 上腾讯云的落地经验(2)——方案实施之接入层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(3)——方案实施之应用层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(4)——方案实施之缓存层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(5)——方案实施之数据层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(6)——方案实施之中间件上云
某上市游戏公司从 IDC 上腾讯云的落地经验(7)——总结与回顾

总结与回顾

前面的文章写了非常多,最终感觉还是有一篇总结性的文章好一些。

文章的整体脉络围绕为什么上云和如何上云两大模块,并详细展开方案实施整个模块。


阅读全文

题外话:

笔者就职于某上市游戏发行公司,主导整个发行业务线从双 IDC 到腾讯云的搬迁。在此过程中踩了不少坑,便以文章的形式记录下来。

如有错漏之处,敬请指正。

我先简单介绍下我自己:

我是业务开发出身,负责渠道登录/支付业务,熟悉前端,研究后台开发框架后,逐步往运维方向摸索。

业务除了登录/支付业务,也做过风控系统、聊天监控系统,主要是一些防刷保护、敏感词判别、垃圾信息过滤等等。

本系列篇幅较长,共有 7 篇文章,本文是第 6 篇。文章列表:

某上市游戏公司从 IDC 上腾讯云的落地经验(1)——上云必要性与方案设计
某上市游戏公司从 IDC 上腾讯云的落地经验(2)——方案实施之接入层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(3)——方案实施之应用层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(4)——方案实施之缓存层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(5)——方案实施之数据层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(6)——方案实施之中间件上云
某上市游戏公司从 IDC 上腾讯云的落地经验(7)——总结与回顾

中间件上云

中间件这块,我们的 Kafka 没有搬迁,属于大数据业务,目前依然在 IDC 机房。

Elasticsearch 是其他同事跟进,应该也是有同步工具并做 DNS 切换,业务无损。

而 RabbitMQ 这块是我负责上云的。我对它真的是又爱又恨——

  • 爱:RabbitMQ 非常稳定,几乎不需要运维,跑了很久基本不出问题,PHP / Go 都非常友好,用起来比较方便;具备完善的 API 接口和管理界面,方便自己编写脚本实现某些操作的自动化
  • 恨:性能堪忧,腾讯云的 CVM 自建 32 核 64 G内存 HDD * 2 台实例 + 4 层负载均衡,队列开启持久化吞吐量大概在 3 万消息每秒(主备模式);镜像模式下,单队列没有水平扩展的能力,即使关闭持久化,依然存在硬件上的性能瓶颈。

众所周知,RabbitMQ 支持主备模式、镜像队列两种主流的用法。

image-主备模式与镜像模式对比

这两种模式的优缺点如下:

主备模式:架构简单,但节点故障时非常难受,需要手工切换灾备节点(队列元数据需要声明才行,不然会丢数据),一般业务会开启持久化,不做切换时取决于节点何时恢复,不具备高可用的能力。

镜像模式:队列双副本 + 关闭持久化,同样配置吞吐量在 6 万消息每秒,但不具备水平扩展的能力,理论上换 SSD 磁盘会更快,但确实没办法再快了,和 Kafka 没法比。


阅读全文

题外话:

笔者就职于某上市游戏发行公司,主导整个发行业务线从双 IDC 到腾讯云的搬迁。在此过程中踩了不少坑,便以文章的形式记录下来。

如有错漏之处,敬请指正。

我先简单介绍下我自己:

我是业务开发出身,负责渠道登录/支付业务,熟悉前端,研究后台开发框架后,逐步往运维方向摸索。

业务除了登录/支付业务,也做过风控系统、聊天监控系统,主要是一些防刷保护、敏感词判别、垃圾信息过滤等等。

本系列篇幅较长,共有 7 篇文章,本文是第 5 篇。文章列表:

某上市游戏公司从 IDC 上腾讯云的落地经验(1)——上云必要性与方案设计
某上市游戏公司从 IDC 上腾讯云的落地经验(2)——方案实施之接入层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(3)——方案实施之应用层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(4)——方案实施之缓存层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(5)——方案实施之数据层上云
某上市游戏公司从 IDC 上腾讯云的落地经验(6)——方案实施之中间件上云
某上市游戏公司从 IDC 上腾讯云的落地经验(7)——总结与回顾

数据层上云

由于缓存层上云时在 /etc/hosts 文件踩过小坑,后面我们把生产环境上所有绑定 hosts 的业务都整理了一次。

数据层主要是 Redis、MySQL 这两个组件。


阅读全文