Shardingsphere-Proxy 5.5.0数据迁移实战:从单机到集群的平滑过渡
1. 为什么需要从单机迁移到集群?
很多开发者第一次接触Shardingsphere-Proxy时,往往会选择单机模式快速上手。这确实是个明智的选择——单机部署简单,配置直观,特别适合开发测试环境。但当数据量逐渐增大,单机模式的瓶颈就开始显现了。我去年就遇到过这样一个案例:某电商平台的订单表已经超过5000万条,单机Proxy在高并发查询时经常出现响应延迟,更麻烦的是每次服务重启都会导致几分钟的服务不可用。
集群模式的核心价值在于高可用和弹性扩展。通过Zookeeper等注册中心,多个Proxy实例可以共享配置和状态信息。当某个节点宕机时,请求会自动转移到其他健康节点。根据我的实测,配置得当的集群可以实现秒级故障转移,这对线上业务至关重要。另外,当查询压力增大时,你只需要水平扩展Proxy实例即可,不需要停服。
2. 集群环境准备
2.1 Zookeeper部署要点
虽然官方文档说可以用任何Zookeeper版本,但我强烈建议使用3.6.x以上版本。去年我在3.4.14版本上踩过一个坑:当网络波动时,Proxy节点会出现假死状态。安装过程很简单:
# 下载解压 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz # 配置基础环境 cd apache-zookeeper-3.7.1-bin/conf cp zoo_sample.cfg zoo.cfg # 关键配置项(根据实际情况调整) echo "tickTime=2000 dataDir=/var/lib/zookeeper clientPort=2181 maxClientCnxns=60 admin.enableServer=false" > zoo.cfg # 启动服务 ./bin/zkServer.sh start特别注意:生产环境至少要部署3个节点组成集群,单节点Zookeeper存在单点故障风险。我曾经为了省事在测试环境用单节点,结果一次机房断电导致配置全部丢失。
2.2 Proxy配置改造
原单机模式的global.yaml需要增加集群配置段。这里有个细节容易被忽略:namespace的命名要有唯一性。我建议采用"项目名_环境"的格式,比如:
mode: type: Cluster repository: type: ZooKeeper props: namespace: payment_prod server-lists: "zk1:2181,zk2:2181,zk3:2181" retryIntervalMilliseconds: 500 timeToLiveSeconds: 60 maxRetries: 3遇到过的一个典型问题:当网络延迟较高时,适当增大retryIntervalMilliseconds和timeToLiveSeconds可以避免频繁超时。有一次我们的跨机房部署就因为这个配置不当,导致Proxy不断重连Zookeeper。
3. 数据迁移全流程
3.1 存储单元注册的坑
注册目标库时,很多人习惯用localhost,这在集群环境下会出大问题。正确的做法是:
-- 错误示范(集群其他节点无法访问) REGISTER STORAGE UNIT target_db_0 ( URL="jdbc:mysql://localhost:3306/db_0", USER="root", PASSWORD="123456" ); -- 正确做法(使用统一域名或IP) REGISTER STORAGE UNIT target_db_0 ( URL="jdbc:mysql://mysql-master:3306/db_0?useSSL=false", USER="sharding_user", PASSWORD="Complex@Pass123", PROPERTIES("maxPoolSize"="20") );我建议专门为ShardingSphere创建数据库用户,而不是直接用root。有一次迁移失败就是因为root账号的host限制导致。另外,SSL连接在生产环境是必须的,但测试时可以暂时关闭。
3.2 分片规则设计实战
设计分片规则时,要考虑未来3-5年的数据增长。比如日期分片的表:
CREATE SHARDING TABLE RULE orders ( DATANODES("ds_${0..15}.orders_${2022..2030}${1..12}"), DATABASE_STRATEGY( TYPE="standard", SHARDING_COLUMN=user_id, SHARDING_ALGORITHM( TYPE(NAME="inline",PROPERTIES("algorithm-expression"="ds_${user_id % 16}")) ) ), TABLE_STRATEGY( TYPE="standard", SHARDING_COLUMN=create_time, SHARDING_ALGORITHM( TYPE(NAME="inline",PROPERTIES("algorithm-expression"="orders_${create_time.toLocalDate().format(DateTimeFormatter.ofPattern('yyyyMM'))}")) ) ) );这个例子中,我们按用户ID分16个库,按月分表。特别注意Java时间类型的处理方式,和MySQL的DATE类型转换不同。曾经有团队因为格式不匹配导致数据全部分到默认表。
4. 迁移过程优化技巧
4.1 性能调优参数
默认的迁移参数对小表没问题,但对千万级大表就需要调整:
ALTER MIGRATION RULE ( READ( WORKER_THREAD=40, BATCH_SIZE=5000, SHARDING_SIZE=5000000, RATE_LIMITER( TYPE(NAME="QPS",PROPERTIES("qps"="300")) ) ), WRITE( WORKER_THREAD=40, BATCH_SIZE=2000, RATE_LIMITER( TYPE(NAME="TPS",PROPERTIES("tps"="1000")) ) ), STREAM_CHANNEL( TYPE(NAME="MEMORY",PROPERTIES("block-queue-size"="20000")) ) );根据我的压力测试,在32核服务器上:
- WORKER_THREAD建议设为CPU核数的1.5倍
- BATCH_SIZE太大容易OOM,太小则效率低
- 合理的QPS限流可以避免源库压力过大
4.2 一致性校验方案
数据迁移后必须做校验,推荐组合方案:
-- 快速校验(适合95%场景) CHECK MIGRATION 'j0102p00004fbcfe6b4dc23af37e3cdb06a4c634ed' BY TYPE (NAME='CRC32_MATCH'); -- 详细校验(关键业务数据) CHECK MIGRATION 'j0102p00004fbcfe6b4dc23af37e3cdb06a4c634ed' BY TYPE (NAME='DATA_MATCH');遇到过的一个诡异情况:CRC32校验通过但实际数据不一致。后来发现是因为某些字段的字符集不同导致。所以金融级业务建议两种校验都做。
5. 常见问题排查指南
5.1 连接类问题
现象:注册存储单元时报连接失败
- 检查网络连通性(telnet mysql_host 3306)
- 确认数据库用户权限(GRANT ALL PRIVILEGES ON.TO 'user'@'%')
- 检查MySQL的max_connections参数是否足够
5.2 数据不一致问题
现象:迁移后查询结果不符合预期
- 先确认分片算法是否与业务预期一致
- 检查分片键的值分布(NULL值会进入默认分片)
- 使用SHOW SHARDING TABLE RULE验证实际生效的规则
5.3 性能类问题
现象:迁移速度越来越慢
- 检查目标库的索引是否合理(迁移期间可先去掉非必要索引)
- 监控目标库的CPU和IO情况(hdparm -tT /dev/sda)
- 考虑分批迁移(WHERE条件限定时间范围)
6. 生产环境注意事项
变更窗口:大型迁移建议在业务低峰期进行,提前通知相关方
回滚方案:始终保持源数据可查询,直到新集群稳定运行一周
监控指标:重点关注:
- 迁移进度百分比(SHOW MIGRATION STATUS)
- 目标库的慢查询数量
- Proxy节点的内存使用率
数据校验:除了工具自带的校验,建议编写业务逻辑校验脚本。比如订单总金额、用户数等关键指标应该一致
增量同步:迁移期间产生的增量数据,可以通过binlog同步工具补偿。有个取巧的做法:在业务低峰期短暂停写,快速完成最后差异同步
