Home | 简体中文 | 繁体中文 | 杂文 | 知乎专栏 | Github | OSChina 博客 | 云社区 | 云栖社区 | Facebook | Linkedin | 视频教程 | 打赏(Donations) | About
知乎专栏多维度架构 微信号 netkiller-ebook | QQ群:128659835 请注明“读者”

第 18 章 多维度架构之分库分表

目录

18.1. 分表需要从业务角度考虑
18.2. 最后总结

分库和分表是架构必经之路,我想问问你是怎么分库和分表?

很多系统在设计之初就没有考虑过后期的分库与分表,甚至开发团队没有架构和DBA人员,开发团队也比较年轻,对于数据库的架构定义非常随意,满足当前需求即可。

实际上数据库结构等同于建筑里面的地基,地基没有打好,后面的优化都是徒劳的,最终不得不重构数据库结构。

那么你是怎样分库分表的?

任何系统数据流都是漏斗形状的,数据库是漏斗末端,架构设计是尽量在前端计算,合并,拆分,分流,缓存,最终将有价值的数据写入数据库。数据库的访问是结果集越小越好。

基于这种认识,通常分库和分表,我们想到的就是首先垂直分表,这种方式简单易操作。

	
当前(本年度数据库)(热数据)
2019年数据
2018年数据
以此类推

或者按照月份分表

当前(热数据)
10月数据
9月数据
以此类推
	
	

这样分表可以缩小结果集,能快速解决查询瓶颈问题。但是新的挑战来了,由于分表后,索引是独立不连续的,历史数据的查询或遍历数据变的复杂了,要么使用联合查询,要么一张表一张表的遍历。

同理水平分表也是粗暴的将一些尺寸较大的列独立成新表,以降低单个表的容量尺寸。

如果是单纯的数据查找,还是能忍受,我们可能根据时间来选择查询的表,如果是复杂的SQL操作,就只能逐一查询,在程序中二次计算,合并等等操作。

这种分库或分表的思路,理论上属于数据归档。将热数据放在当前数据库中,将很少查询的冷数据放在另一个库中。但是对于 user 这种表就无能为力,你不知道那个用户什么时候会做登录操作。

18.1. 分表需要从业务角度考虑

分表需要从业务角度考虑,数据库服务于业务逻辑。

由于我即负责产品也负责架构,长期的工作中,总结出一套分库分表的策略。

我分表策略是:

  1. 从UI角度出发
  2. 从业务流角度出发

举例一,用户表分表?

用户表怎样水平拆分呢? 用户登录的逻辑是这样的,第一个UI 输入用户名和密码,提交后验证密码,用户是否过期,记录登录时间,IP地址。第二个UI,载入用户资料,包括用户姓名,年龄,性别等等…..

数据库我是这样设计的:

			
+-----------------------------------------------+
| Member                                        |
+-----------------------------------------------+
| id | username | password | ip | ctime | mtime |			
+-----------------------------------------------+
			
			

就这么简单,会员表服务于第一UI

			
+-----------------------------------------------+
| Profile                                       |
+-----------------------------------------------+
| id | member_id | name | sex | age | mtime |…… |			
+-----------------------------------------------+
			
			

服务于第二个UI,通过 member_id 关联数据

怎么样?用户登录过程并不会去访问 profile 表,只有登录成功才会访问。

用户表怎样垂直拆分呢? 将 username 做crc32/md5/sha1 运算,使用哪种随你,取出第一个字符用于分表。

例如 neo, netkiller 两个用户被分到 member_n 表中,jerry,jam 被分到member_j 表中,配套的还有 profile_n, profile_j 等等。我们甚至还可以使用外键约束 member_n 和 profile_n 两个表。

当用户登录时,对用户ID做一次 hash 运算,就知道去哪个表中找到该用户的数据。

举例二,商品表如何分表?

商品信息表数据量非常大,我们可以基于品类分库或分表,我们UI设计中,一般只有首页才会将不同分类的产品聚合到一起。进入品类分类页面后,只会访问该品类的数据表。

这就是从业务流的角度进行分表,用户操作是逐渐被引导至我们想呈现的页面。

举例三,海量用户如何分库?

海量用户分库的思路是,用户被分配到指定数据库,该用户所有的数据都会产生在该数据库中,也可以理解为基于数据库隔离用户。

基于该思路分库,这样表名保持不变。

例如 neo, netkiller 被分配到 schema_n.member, schema_n.profile

例如 jerry, jam 被分配到 schema_j.member, schema_j.profile

一旦用户登录,便被锁定到指定的数据库,接下来所有操作,用户产生的数据,都被存储在该数据库中。索引连续,外键约束,触发器,存储过程,均不影响使用。

使用分区表

使用分区别将分区数据写入挂载的SSD盘上。例如 /opt/data/ 下面挂载了四块SSD,目录名是 partition1~4。

			
CREATE TABLE your_table (id INT, cdate DATE)
engine='InnoDB'
PARTITION BY LIST(YEAR(cdate))
(
  PARTITION p2020 VALUES IN (2020)
    DATA DIRECTORY = '/opt/data/partition1',
    
  PARTITION p1999 VALUES IN (1999)
    DATA DIRECTORY = '/opt/data/partition2',
   
  PARTITION p1998 VALUES IN (1998)
    DATA DIRECTORY = '/opt/data/partition3',
    
  PARTITION p1997 VALUES IN (1997, 1996, 1995)
    DATA DIRECTORY = '/opt/data/partition4'
);