distributed-and-high-availability.md
分布式与高可用
MySQL Cluster 是什么?
它是基于 NDB 存储引擎的一套分布式集群方案,它和常见的 MySQL 集群的那种主库写数据 —— binlog —— 从库异步/半同步复制,读写分离的方案不太一样,那种其实就是一份主库加上多个备份
而 MySQL Cluster 使用的是 NDB 存储引擎,它将节点分为数据节点、SQL 节点和管理节点三种,数据被按照分片分布在多个数据节点上,每个数据节点都会有多个副本,会自动分片、自动副本同步,通过 SQL 节点对外提供标准的 MySQL 查询,收到请求后再去数据节点上拿数据,背后是共享无架构的同步复制
数据通常是内存为主 + 磁盘持久化,新增数据节点时会重新平衡数据,任意一个节点挂了,只要副本还在,集群就还能继续工作,它也支持分布式的事务,适合低延迟的实时场景,以及一些对高可用和高并发写要求极高的业务,但它的运维复杂度会比主从复制 + InnoDB 那套高不少
你在查询的时候调用的另一个服务宕机了怎么办?
A:嗯首先在调用失败之前应该就会有一些防御机制,比如超时控制和熔断降级等,同时也可以做有限次数的重试,对于一些可缓存的数据可以从比如说 redis 读取旧数据,当真的出现失败时应该会马上有实时监控的告警,比如钉钉,然后就可以先去看一下日志和告警信息来定位问题,再针对性地解决问题
Q:分库分表了解吗?项目中有没有实际用到?
A:有了解,分表就是把一张比较大的表按照某种规则拆分成多张同结构的小表,用来解决单表数据量过大导致的性能问题,比如说可以按时间、ID 或者是地理位置来分表;分库就是把一个数据库拆分成多个数据库,通常是把主库和从库分开,主库负责写入,从库负责读取,这样可以提高性能和可用性;在项目中我还没有实际用到分库分表,因为目前的项目数据量还不大,但我有考虑过在设计时就把这个架构考虑进去,以便后续扩展,比如说可以把用户表和游戏数据表分开,用户表可以按 ID 来分表,游戏数据表可以按时间来分表,这样就能更好地支持高并发和高可用性了;另外在设计时也要考虑到数据的一致性和完整性,比如说在分库分表后要保证跨库事务的一致性,可以使用两阶段提交或者是补偿事务等方式来实现
Q:如果现在有一个有十亿数据量的大表需要分表,该怎么做,分表之后怎么切业务
A:嗯首先要选一个既能均匀打散数据又能经常用来查询或关联的字段,比如 user_id 这种的做哈希分配,或者按时间做范围分区,设计好分表规则后就可以创建新的分表,然后把旧表的数据迁移到新表中,迁移时可以先把旧表的数据按规则分批次地插入到新表中,然后再把旧表的数据删除,最后再把旧表删除;在切换业务时可以先把新表的读写权限开放给部分用户进行灰度测试,测试通过后再全面切换到新表;在切换过程中要注意数据的一致性和完整性,比如说在切换前要先备份数据,在切换后要监控数据的一致性和完整性,确保没有数据丢失或错误
Q:MySQL 和 redis 的缓存一致性该如何保证
A:先更新 MySQL,写库之后再删除 redis 缓存,确保后续请求要么打到旧缓存要么打到库,避免出现反向失效,短延时后可以再删除一次缓存,防止并发写入时读到旧值,如果业务对一致性要求较高,可以在更新和删缓存之间加一下分布式锁,保证同一条记录在任何时刻只有一个线程在操作缓存;在写库时将缓存失效消息发送到消息队列,消费者异步订阅消息并在各节点删除或更新缓存,但要保证消息队列的消息不丢失,也可以通过监听 MySQL 的 binlog 来实时把数据变更同步到 redis
Q:数据量变成原来的十倍,该怎么办
A:主要有三个层面可以操作,一个是存储层,可以做分库分表和 MySQL 分区,把单表行数从千万级降到百万级以下,并重新评估索引,把高选择性字段建成联合或覆盖索引,也可以考虑只把热数据留在主库;缓存与异步层面的话可以考虑加深本地和 redis 的二级缓存,对于写入量大的统计、日志和推荐等可以用消息队列异步入库,减少对主库的直接冲击;最后应用与运维层面可以考虑读写分离,让从库承担更多读流量,关键服务拆分成独立的微服务做水平扩缩容,可以再结合告警和 k8s 或重新跑压测等
- 主从同步的机制是什么样的?是哪些操作会同步哪些操作不会同步?