一个高并发系统的瓶颈主要在数据库层, 为了缓解数据库的压力, 我们可以这样做:
全局ID生成
这是水平分库分表后的问题.
(1) UUID
全球唯一, 但太长了, 不适合做全局ID.
(2) 序列表生成全局ID
当写并发不高时, 可以使用此方法. 从t_sequence表中获取ID, 每次获取一批ID, 然后在内存中自增返回.
CREATE TABLE `t_sequence` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`table_name` varchar(64) NOT NULL COMMENT '表格名称',
`max_id` bigint(20) NOT NULL COMMENT '当前的最大id',
`step` smallint(6) NOT NULL COMMENT '每次取的id跨度',
`modify_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `ind_tbl_name` (`table_name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;
/**
* 从t_sequence表中获取ID, 每次获取一批ID, 然后在内存中自增返回.
*/
public Long getNextId() {
sequenceLock.lock();
try {
if (nextId < maxId) {
return nextId++;
}
//更新nextId和maxId, 循环多次(伪代码)
select id,max_id,step from t_sequence where id=? and table_name=?
update t_sequence set max_id = max_id +step,modify_time=now() where id=? and table_name=? and max_id=?
nextId = max_id;
maxId = nextId + step;
return nextId++;
} finally {
sequenceLock.unlock();
}
}
(3) SnowFlake算法
Snowflake 是 Twitter 开源的分布式 ID 生成算法, 其结果为 long(64bit) 的数值.
分片策略
这是水平分库分表后的问题. 这里MySQL的分片策略和Redis集群的分片策略差不多, 可以相互对照下.
(1) ID取模分片
最简单且使用最广泛的分片策略, 缺点是扩容后需要迁移数据.
(2) 一致性哈希算法
是ID取模分片的优化方案, 但扩容后仍然有部分数据需要迁移.
(3) Range分片
根据时间范围分片, 比如每月一张表, 每天一张表等, 在一些统计业务中会用到.
分布式事务
这是垂直分库后的问题. 分布式事务解决方案
跨节点Join和聚合
分库分表后的数据入Elasticsearch, 然后在Elasticsearch进行搜索聚合.
一开始一个数据库服务器中就设计32个库, 每个库中32张表, 当数据库服务器并发压力太大时, 就迁移一半的数据库到另一个数据库服务器上, 最终可以达到32个数据库服务器, 每个数据库服务器上一个数据库. 这是种比较奢侈的设计方案, 也只有大厂敢这么设计.
(1) 如何实现MySQL的读写分离?
当单库的并发太高时, 我们就需要做读写分离, 写请求走主库, 读请求走从库, 来降低数据库服务器(MySQL)的压力. 使用Sharding-JDBC中间件来实现.
(2) MySQL主从复制原理的是啥?
MySQL主从复制原理
(3) 如何解决MySQL主从同步的延时问题?
Sharding-JDBC和MyCat这两个中间件随便用哪个都可以, 都比较方便.