11.1 什么是可拓展性
可拓展性表明当需要增加资源以执行更多工作时系统能获得划算的等同提升。而缺乏拓展能力的系统在达到收益递减的转折点后,将无法增长
考虑负载的几个因素
- 数据量:应用所能积累的数据量是可拓展性的最普遍的挑战。
- 用户量:在用户量累计到一定程度后,数据量也开始成比例增长且速度快过用户数增长。用户量大意味着TPS相应增大,也意味着复杂查询
- 用户活跃度:用户的活跃度可能存在突然性,因为某个活动瞬间增加了很大的负载
- 相关数据集的大小:如果用户间存在关系,应用可能需要在整个关联用户群体上执行查询和计算,这比处理一个个单独用户的数据量要复杂,如某些社交网站的高人气的用户组带来的挑战。
当前的实力拓展更为贴近USL,当增加到一定程度后反而负增长
11.2 拓展MYSQL
11.2.1 预估系统的瓶颈点的几个思考方向
- 应用的功能完成了多少。比如应用的核心功能没有实现,何谈瓶颈点
- 预期最大负载
- 如果依赖系统的每个部分来分担负载,在某个模块失效时会如何,这种情况需要预先准备一些额外方案来支持
11.2.2 拓展前可以尝试减缓的方法
- 优化性能:性能调优,如建立适当的索引,优化慢查询
- 替换性能更强的硬件
11.2.3 向上拓展
也称为垂直拓展:意味着机器升级,比如机器从四核升级为32核,从复杂性成本来说,向上拓展比向外拓展更简单。
缺点
- 增加机器性能的天花板很明显,数据量有限
- 对于有复制的机器来说,很难给从服务器配备相同条件的硬件资源
- 单服务器的读限制很容易达到,特别是复杂的读查询时,但在mysql内部读是单线程,无论你是多少核的机器,效率并不能提高,所以提升不大
11.2.4 向外拓展(横向拓展)
复制、拆分、数据分片
常见的有通过复制将数据分发到多个服务器,然后将备库用于读查询,这样的对读为主的应用比较有效果,但是会出现重复缓存
另外一个比较常见的向外拓展方法是将工作负载分布到多个节点。
- 按功能分库:按职责拆分,意味着不同的节点执行不同的任务。
- 数据分片:大多数应用只会对需要做分片处理的数据做分片 ——通常是那些将会增长的非常庞大的数据
采用分片的应用通常会有一个数据访问层,用于降低应用和分片数据存储之间通信的复杂度,但无法完全隐藏分片。因为相比于数据存储,应用通常更了解跟查询相关的一些信息。分片带来的缺陷很明显——复杂性
选择分区键:数据分片带来的除了复杂度还有查找和获取数据的挑战。一个好的分区键通常是数据一个非常重要的实体的主键。这些键决定了分片单元。而确定分区键的一个好的办法就是实体——关系图或数据模型图。尽量把相关联的实体靠得更近。通常同时还要考虑查询场景,选择分区键尽可能选择那些能够避免跨分片查询的,但同时让分片尽可能小,避免导致数据量太大。
多个分区键:复杂的数据模型会使分区更加困难。所以部分应用有多个分区键,可类比mysql的联合索引。
跨分片查询:
分配数据、分片、节点:分片和节点不是一对一,应该尽可能让分片比节点小得多,这样可以在单个节点上存储多个分片。保持分片足够小更容易管理。这将使得数据的备份和回复更容易,小表也方便转移。
固定分配:
动态分配:动态分配最大的好处就是对数据存储位置做出更细致的控制。
重新平衡分片数据:
生产全局唯一ID:当需要把现有系统转换为分片数据存储时,经常会需要在多台机器上生成全局唯一ID,有以下几种办法。1.比如只有两台服务器,可以配置两台服务器的自增幅度为2,初始偏移量设置 (需要对服务器进行认真仔细的配置)2.全局节点中创建一个表,通过表的自增来获取id 3.使用memcached等自增长函数 4.批量分配数字,应用可以从全局节点中请求一批数字,用完后申请
分片工具:当涉及数据库多分片结构时,首先需要做的是将查询层抽象化,不应该让各应用直接面对数据源,抽象层需要连接正确的分片被执行,分布式一致校验,跨分片结果集聚合,跨分片关联操作,锁和事务,创建新的数据分片