系统设计的垂直拆分和分平拆分
second60 20180420
1背景
当一个系统/网站,刚开始的时候,所有的业务模块和数据都是放在一起的,只有小量的人来开发和维护;
但当系统/网站不断丰富功能和业务的时候,系统将会变的越来越庞大,也会逐渐拆分成各个子系统来支撑,这此就需要把系统拆分,把原来强耦合的系统,拆分成弱耦合的多个子系统,数据表也因为数据量大,需要按业务垂直拆分和按大小来水平拆分。
2 系统的拆分
对于系统来说,一般都是系统初始设计时,就考虑好整个系统的架框,分好框架层次,和各个服务,考虑框架的通用性,可配置,可扩展,可兼容等特点。
虽然前期设计好系统框架,但难免随时业务和功能的扩张,系统变的比较庞大,需要对系统进行进一步的细分,主要有两个方向,即垂直扩展和水平扩展。
2.1 系统的垂直扩展
对于系统的垂直扩展,即把系统按业务分级,把可独立,或可划分的业务独立出子系统。
2.1.1 例1
一个简单交易系统,会按业务分,独立出账户类服务,资金类服务,交易类服务。
优点:
1. 耦合度由强耦合变低耦合
2. 拆分后,各子系统接口通用,可服务于其他子系统
3. 每个子系统独立,子系统出问题,只会影响部份涉及此子系统的业务,不会影响全部业务
2.1.2 例2
又如果,一个游戏后台业务进程
刚开始,可能游戏后台需求简单,把所有业务都放在一个服务中,可能包括:活动类,任务类,社交类。
但后面需求扩展后,可按业务分子服务,分为:活动类服务,任务类服务,社交系统等。
2.2 系统的水平扩展
对于系统的水平扩展,即相同的业务,多分几个服务,但各服务其实是一样的,也就是集群。
例如:一个订单服务,每天的订单量十万,一个服务可以搞定,但当订单量达到二十万压力很大时,可以多启一个相同的服务,即相当,两个服务,每个服务处理十万的订单量。当订单量逐渐增加,服务数量也随着增长。
参考:分布式和集群
2.3 数据库的扩展
系统运营初期,数据量比较小,所有数据表都在一个库中;但当业务量大后,数据量大,数据表也会变的很庞大,系统数据库操作将会变的比较慢。
比如:前期,数据表的大小可能就只有百万的数据量,但发展起来后,数据量增长到上千万一个表。无论是查找速度,还是更新速度,都会变的比较慢。
单表数据量大将会成为性能的瓶颈。
2.3.1 数据库的垂直拆分
数据库的垂直拆分,就是按业务,分库分表。
把原有的一个数据库,按业务分成多个数据库,每个数据库放不同业务的表。
垂直拆分,即把不同的表拆分到不同的数据库中。
例如:
一个电商系统,只有一个数据库,数据库中有用户表,订单表,支付表等。垂直扩展后,把数据库分成用户信息库,订单交易库,支付数据库。
垂直拆分的优点:
1. 拆分后,业务分类,规则明确清晰
2. 系统可扩展性好,可进一步细节
3. 数据库维护方便简单,相关功能的人,只需关注自已的关注的库
4. 可读性高,维护成本降低
缺点:
1. 之前有关联的不同库的表,不能再join, 交互通过接口方式解决,代码量增大
2. 每个子库关可能存在性能瓶颈,影响其他库,解决方法,可通过缓存解决
3. 解决不了单表数据量大的瓶颈问题
2.3.2 数据库的水平拆分
垂直拆分,其实就是业务的拆分,数据库拆分后,可以更加明确每个库的业务,也更方便维护,但解决不了大数据的瓶颈问题。这时就需要用到数据库的水平拆分。
数据库的水平拆分,简单点,就是分库分表。 把同一个表拆分到不同的数据库或数据表中。
水平拆分,按照某个字段(通常是主键)的规则,分散到多个库表中。库可以是同一个库,也可以是不同的库。
水平拆分的常用方法:
1. id取模,比如:uid% n ---->分到n个表中
2. 按年或月或日,折分表,比如:订单表,每日一个表放当日的订单。
3. 按范围分表,比如:1-999999放表1,1000000-1999999放表2
4. 按指定规则分表,如按地区等分表
5. 哈希拆分,但要避免哈希值冲突
6. 按枚举分表
7. 按热度分表,热度大的表分小点,热度小的历史数据表数据大点定期整理
2.3.2.1 例一-id取模
比如,某系统的一个用户表,原数据量增长后,数据量达到一千万用户,单表数据量比较大,考虑按uid取模分表,分10个表,即uid%10分别分到不同库表当中。
原表: t_user
分表后:
t_user_00 | 存放以0结尾的用户 |
|
t_user_01 | 存放以1结尾的用户 |
|
t_user_02 | 存放以2结尾的用户 |
|
t_user_03 | 存放以3结尾的用户 |
|
t_user_04 | 存放以4结尾的用户 |
|
t_user_05 | 存放以5结尾的用户 |
|
t_user_06 | 存放以6结尾的用户 |
|
t_user_07 | 存放以7结尾的用户 |
|
t_user_08 | 存放以8结尾的用户 |
|
t_user_09 | 存放以9结尾的用户 |
|
分表后,每个表的数据量将会减少为原来的十分之一,每个表还可以续继增加用户。
id取模分表的优点:
1. 每个表的数据分配比较均匀,即每个表约点n分之一的数据量,后台添加用户后也比罗均匀。
2. 业务处理中找表,无须添加复杂的找表的规则,只须uid%n取得操作哪个表t_user_(uid%n)
3. 查询和插入效率,相对单表,将更加有效
id取模分表的缺点:
1. 后续扩展比较困难,如果继续添加表,需重新整理表中的数据,然后再分到更多的表中,特别是7*24小时不停服的业务中。
2.3.2.2 例二-按年日期分表
比如,电商系统,每天的订单量都上千万上亿,因此,可以订单表,可以按日期做为一个维度,开分表。当然维度是很好的,按日期,按地区等。再这里如按日期为维度,每天一个订单表,事先建好一个月的表。
生产数据表: t_user_order
当月初时,把上个月的数据放到历史订单表中
t_user_order_20180401 | 20180401订单表 |
|
t_user_order_20180402 | 20180402订单表 |
|
t_user_order_20180403 | 20180403订单表 |
|
t_user_order_20180404 | 20180404订单表 |
|
t_user_order_20180405 | 20180405订单表 |
|
t_user_order_20180406 | 20180406订单表 |
|
....... |
|
|
按年月日分表优点:
1. 生产有一个主表,定期把数据放到日期表中,主表将变小
2. 对于数据备份,分析,或后台对历史数据的处理,不会影响到现有的生产库
3. 通常用来历史备份
4. 通过主表和备份表的方式,不会影响到原有逻辑
按年月日分表缺点:
1. 数据不一定均匀,如商城搞活动或节日,数据表可能大好几倍
2. 历史数据的读取,可能要定义一定的规则去历史表中读取
2.3.2.3按范围分表
比如,某表的生产数据id是从1开始自增1慢慢增长,可以按id范围分表。规则如下:
起始id | 结束id | 表 | 库 |
1 | 10000000 | t_XX_01 | db_1 |
10000001 | 20000000 | t_XX_02 | db_2 |
20000001 | 30000000 | t_XX_03 | db_3 |
30000001 | 40000000 | t_XX_04 | db_4 |
|
|
|
|
优点:
1. 数据是按表慢慢增长,使用率高,表1用完后再用表2,可以预见性的扩展表
缺点:
1. 数据活跃度不可预知,存在热点问题,即可能某个表操作很频繁,某个表操作很少
2.3.2.4按地区枚举分表
比如广东某电信后台经营分析系统,每天数据从21个地区分发数据到数据集市,因此,可以按地区枚举建表,因为每天数据量大,同时可以再加个时间维度。
地区分别为:
广州市 | gz |
| 江门市 | jm |
深圳市 | sz | 茂名市 | mm | |
珠海市 | zh | 惠州市 | hz | |
汕头市 | st | 梅州市 | mz | |
佛山市 | fs | 汕尾市 | sw | |
韶关市 | sg | 河源市 | hy | |
湛江市 | zj | 阳江市 | yj | |
肇庆市 | zq | 清远市 | qy | |
东莞市 | dg | 中山市 | zs | |
潮州市 | cz | 揭阳市 | jy | |
云浮市 | yf |
|
|
按地区和按日期两个维度分表
惠州 |
|
|
t_record_hz_20180401 | t_record_gz_20180401 | t_record_sz_20180401 |
t_record_hz_20180402 | t_record_gz_20180402 | t_record_sz_20180402 |
t_record_hz_20180403 | t_record_gz_20180403 | t_record_sz_20180403 |
t_record_hz_20180404 | t_record_gz_20180404 | t_record_sz_20180404 |
t_record_hz_20180405 | t_record_gz_20180405 | t_record_sz_20180405 |
|
|
|
2.4水平和垂直分表的目的
水平分表目的
1. 解决表与表之间的IO竟争问题
垂直分表的目的
1. 解决单表中数据量大的问题
3 总结
无论是系统的垂直还是水平分子系统,还是数据库的垂直和水平拆分。目的都是为了整体系统的效率和维护开发成本。如果在初期规划好可能会出现的风险的瓶颈,并做好系统扩展,是比较容易应对出现的风险问题。
相反,当一个系统初期只为了开发效率而忽略了扩展和通用性,那个后期风险来的时候,可能整体系统的维护和扩展成本很大,甚至要重构系统,那是一件多么可怕的事情。