ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL关系链系统优化:Canal+Kafka实现高可用架构

MySQL关系链系统优化:Canal+Kafka实现高可用架构 1. 项目背景与核心价值在社交平台和内容社区中用户关系链关注/粉丝系统是最基础也最关键的模块之一。传统做法往往直接读写MySQL主库但随着用户量增长这种架构会面临三个典型问题写入瓶颈明星用户发布内容时粉丝关系链的并发写入可能压垮数据库读取延迟主从同步延迟导致新关注关系不能即时展现单点故障主库宕机时整个社交功能不可用我们设计的一主多从关系链系统通过Canal监听MySQL binlog变化将关系链事件推送到Kafka再由消费者同步到多个从库和缓存。实测在500万用户规模下关注操作响应时间从平均120ms降至35ms主库写入QPS下降72%。2. 技术架构详解2.1 核心组件选型Canal部署模式# 高可用部署建议 canal.admin.manager.url http://admin-server:8089/api/v1/${canal.admin.manager.url.base} canal.admin.manager.url.base canal/admin选择Canal 1.1.6版本而非最新版因其在MySQL 8.0兼容性和内存管理更稳定。关键配置项canal.instance.mysql.slaveId必须全局唯一canal.mq.filter.transaction.entry设置为true过滤空事务Kafka拓扑设计graph TD A[Canal Server] --|JSON格式| B(Kafka Topic:user_relation) B -- C[Consumer Group1:MySQL从库同步] B -- D[Consumer Group2:Redis缓存更新] B -- E[Consumer Group3:ES索引构建]实际生产环境需要配置# Kafka生产者参数 acksall retries5 compression.typesnappy2.2 关系链数据模型采用宽表设计避免联查CREATE TABLE user_relation ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL COMMENT 主用户ID, target_id bigint NOT NULL COMMENT 被关注用户ID, relation_type tinyint NOT NULL COMMENT 1-关注 2-拉黑, version bigint NOT NULL DEFAULT 0 COMMENT 版本号, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_user_target (user_id,target_id), KEY idx_target (target_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_bin重要提示必须使用utf8mb4_bin排序规则避免emoji导致的唯一键冲突3. 高可用实现方案3.1 Canal集群部署采用Zookeeper协调多实例# canal.properties配置 canal.zkServerszk1:2181,zk2:2181,zk3:2181 canal.instance.global.spring.xml classpath:spring/default-instance.xml故障转移流程通过HTTP API检测实例健康状态自动将故障实例的destination转移到其他节点记录最后消费位点防止重复消费3.2 Kafka多副本策略创建Topic时指定kafka-topics.sh --create \ --partitions 6 \ --replication-factor 3 \ --topic user_relation \ --config min.insync.replicas2消费者端配置建议props.put(enable.auto.commit, false); props.put(isolation.level, read_committed); props.put(max.poll.interval.ms, 300000);4. 关键问题解决方案4.1 顺序性保障针对同一用户的关系变更通过Kafka消息key保证顺序// 使用user_id作为partition key ProducerRecordString, String record new ProducerRecord( user_relation, String.valueOf(event.getUserId()), JsonUtils.toJson(event) );4.2 数据一致性校验开发定时核对任务def check_consistency(): # 从主库获取最新关系数 master_count mysql.query(SELECT count(*) FROM user_relation) # 从各个从库获取统计 for slave in slaves: slave_count slave.query(SELECT count(*) FROM user_relation) if abs(master_count - slave_count) threshold: alert_admin(f数据不一致: master{master_count} slave{slave_count})5. 性能优化实践5.1 MySQL批量插入使用LOAD DATA INFILE替代INSERTLOAD DATA INFILE /tmp/follows.csv INTO TABLE user_relation FIELDS TERMINATED BY , (user_id, target_id, relation_type);5.2 Redis缓存设计采用哈希结构存储关系HSET user:123:following 456 1 # 用户123关注了用户456 HSET user:123:following 789 1 HGETALL user:123:following缓存更新策略写操作双删缓存先删后更新再删设置随机过期时间避免雪崩使用Lua脚本保证原子性6. 监控指标设计关键监控项及阈值指标名称采集方式报警阈值Canal延迟时间Prometheus5s持续1分钟Kafka堆积量Burrow监控10万条消息MySQL主从延迟pt-heartbeat500msRedis缓存命中率INFO stats85%Grafana仪表盘配置示例{ panels: [{ title: 关系链同步延迟, targets: [{ expr: canal_delay_seconds{instance~$instance}, legendFormat: {{instance}} }] }] }7. 灾备恢复方案当主库完全不可用时通过Orchestrator自动提升从库为主库修改Canal配置指向新主库重置Kafka消费位点到故障前位置启动数据校验脚本恢复后检查清单所有从库show slave status验证复制状态Canal日志无Connection refused错误Kafka消费者lag指标归零抽样检查关键用户的关系数据我在实际部署中发现当网络分区发生时Zookeeper的选举超时时间需要调整为# zoo.cfg配置 tickTime2000 initLimit10 syncLimit5这种架构虽然增加了中间件复杂度但在我们电商平台的会员关注系统中成功支撑了618大促期间每秒3200的关注操作主库负载始终保持在40%以下。对于需要强一致性的场景建议在客户端增加本地缓存合并策略。
返回列表