阿里云服务配置情况
服务器A:Nginx,用于所有接口的代理,并且在Nginx上集成了WAF
服务器B:应用服务器,运行了N个Java进程,并使用TCP长链接和服务商保持通信,数据有去有回
Redis缓存:使用的是阿里云的Redis社区主从版,如果是集群版,可以降级成主从版,方便同步数据至本地
数据库:使用的阿里云的RDS
2. 迁移方案
迁移准备按照下图的方式去执行,后面会详细叙述。
2.1. 本地完成环境部署
2.1.1. Nginx服务器安装
安装CentOS 8操作系统
配置nginx yum源
安装最新的nginx
执行nginx waf编译安装
使用rsync命令同步nginx部署文件、配置文件
nginx建立阿里云内网Redis,MysqlTCP代理,准备用于redis-shake的数据同步、Navicat的数据同步
2.1.2. 应用服务安装
本次将Mysql,Redis都安装在应用服务器上。
安装CentOS 8 操作系统
安装openjdk,为了避免应用程序大改动,仍然用几年一年的1.8版本
安装redis,并切换module流,从默认的5版本更新到6版本,修改redis.conf配置
安装mysql8.0,注意提前在/etc/my.cnf.d/mysql-server.cnf中添加lower_case_table_names=1参数,mysql8.0一旦数据库中已经有数据,就不允许再在配置文件中添加该参数。初始化账号信息和数据库
CREATE USER 'username'@'%' IDENTIFIED BY 'password';
create database if not exists dbname DEFAULT CHARACTER SET = 'UTF8';
GRANT ALL ON dbname.* TO 'username'@'%';
flush privileges;
使用rsync命令同步所有Java应用文件以及配置
2.2. 同步Redis和Mysql
执行redis-shake同步,具体参考https://help.aliyun.com/document_detail/111066.html,这是aliyun开源出来的一个redis同步工具,默认使用psync模式,全量同步之后,增量更新。
redis-shake同步完了之后,可以通过RedisInsight查看同步的情况,由于Redis过期Key不会立即删除,也不会得到同步,所以同步之后对比源和目标库的时候会发现目标库比源库Key数量少很多,这是正常的。说明:RedisInsight是一个Redis官方开源的Redis客户端。可以从这里下载安装包,开源仓库没有安装包,只有源码。
使用Navicat试用版执行数据库同步,第一次可以全量,之后可以只选择业务会更新的表作增量同步,降低单次同步的时间。
2.3. 修改所有应用的配置
修改redis连接地址
修改Mysql连接地址
由于数据库名、账号、密码都保持了和阿里云的一致,所以修改连接地址就行了
参考命令:
sed -i s/rm-xxxxxxxxxxxxx.mysql.rds.aliyuncs.com/192.168.0.0/g *
2.4. 测试应用程序能否正常启动。
由于数据库版本从阿里云RDS自带的mysql5.6升级到了自己安装的8.0。所以Java应用程序需要更新mysql驱动程序,并重新编译发布,中间也更新了一下有安全漏洞的各个组件。安全漏洞报告使用vscode
也因为是内网应用,没有在Mysql上使用SSL,所以在jdbc连接串上需要设置useSSL=false参数
2.5. 切换流量至新的服务器
修改DNS解析规则,指向新服务器。DNS完全生效需要10~30分钟,甚至更久,所以执行下一步。
通过nginx设置tcp upstream代理,将dns规则还未生效的老服务器流量直接指向新的服务器。
断开老应用服务器与服务商的连接
启动新应用服务器,建立与服务商的连接
确认老服务器环境所有数据进入redis、Mysql之后
停止redis-shake的同步
最后一次同步Mysql,这次同步由于新服务器也有写入数据,注意只做追加和更新,不要做删除
2.6. 观察新服务器运行情况
2.7. 释放阿里云资源
3. 踩过的坑
3.1. Redis数据突然丢失
由于Redis配置了maxmemory,并且设置了maxmemory-policy,因为所有key都是同一时间从源服务器同步过来的,时间是一样的,而maxmemory我设置错误,GB计算成了MB,导致触发了maxmemory限制,执行了maxmemory-policy策略,清空了所有key。导致我一度怀疑自己在2.4.步骤中更新应用出现了问题,或者是redis-shake有Bug,没有办法和我的应用同时写入Redis,后面证实这种情况不存在,实际是我的maxmemory算错了。
关于maxmemory,官方解释是这样的:
设置一个内存使用限制到指定的字节数。
当达到内存限制时,Redis将尝试根据所选的驱逐策略(见maxmemory-policy)来移除键。
如果Redis不能根据策略删除键,或者策略被设置为 "noeviction",Redis将开始对会使用更多内存的命令做出错误回复,如SET、LPUSH等,并将继续对GET等只读命令做出回复。
这个选项通常在使用Redis作为LRU或LFU缓存时很有用,或者为一个实例设置一个硬的内存限制(使用'noeviction'策略)。
至于maxmemory-policy,我选择的是allkeys-lru,根据业务情况,也可以选择volatile-lru,只对过期key执行lru策略。
4. 总结
阿里云的Redis,RDS都提供了很完善的备份策略,甚至在应用服务器这块,也提供了很完善的监控策略,能够监控到进程、流程、CPU、内存等等。但这一切都是建立在长期付费的基础上的,出于成本考虑,目前迁移回了本地私有云环境,监控就需要自己上手段了。