可扩展性和高可用
可扩展性
系统容量表示在一定时间内能够完成的工作量,最大吞吐量不等于容量,
- 可扩展性就是通过增加资源来提升容量,容量可以简单的理解为处理负载的能力
- 线性扩展就是增加一倍服务器,就增加一倍的容量,然而大部分系统不是这样,都只能以比线性扩展低的系数进行扩展,多数系统会达到一个吞吐量临界点,超过这个点增加投入,会带来负回报
- 原因是:
- 会有无法并发执行的一部分工作,不能并发,那么不管增加多少机器,都改变不了执行时间
- 而且服务器越多,通信的代价越大,通信的代价取决于通信信道的数量,信道的数量按照工作者数量的二次方增长,这也是性能倒退的原因
- 所以想要构建高可扩展性的系统,就需要尽量避免串行化和交互
- 但是也有可能会遇到比线性高的可扩展性,比如增加资源后,有可能吧一些i/o密集型工作变成纯内存的工作,这会带来超越线性的性能扩展
扩展mysql
-
mysql并不能完全利用高性能服务器的硬件,当cpu超过24个,内存超过128G时,mysql性能处于平缓,不在上升,所以在一个性能强大的服务器上运行多个实例,才更合理
-
mysql常见的扩展方式有:垂直扩展,水平扩展和向内扩展
-
垂直扩展,也就是使用更让好的机器
- 单台服务器比多台服务器更容易维护和开发,扩展也更加简单
- 但是入如果应用变得非常庞大,垂直扩展就会变得很困难
- 首先是成本问题,高配置的机器往往非常昂贵
- 另外如果使用了复制,主库升级配置后,一般不会配置一台和主库一样强大的从库,因为从库无法优先利用多核cpu和磁盘资源
- 而且硬件是有上限的,不可能无限扩展
-
水平扩展,也就是将任务分配到多台计算机
- 大概可以分为:复制、拆分和数据分片,最简单的方式就是通过复制把数据分发到多个服务器,读写分离,从库只做读操作;或者按照功能和职责对应用进行拆分,不同的节点执行不同的任务
- 数据分片是将数据分割成多块,然后存储到不同的节点,如果是想扩展写容量,就必须进行分片,只有一台主库,无论有多少从库,写容量都是无法扩展的
- 当然如果不是必要,尽量不要分片,先看能否通过调优和其他数据库来推迟分片
- 分片应用会有一个数据库访问的抽象层,用以降低应用和分片数据之间通信的复杂度
- 分片的最大问题,就是查找和获取数据,而且维护数据的一致性会很难,并且分片无法使用外键,对于重要且查询频繁的数据要减少分片
- 保持分片足够小更容易管理,对数据的备份和恢复也更加容易,但是太小的分片也会导致产生很多的表,从而导致跨分片的查询增加
-
向内扩展,也就是定期对数据进行清理和归档,对冷热数据进行分离
- 可以作为争取时间的短期策略,也可以作为处理大数据量的长期计划
- 归档时需要在不影响事务处理的情况下进行,关键是要高效的找到要删除的行
分片的实现:
- 对表的主键使用哈希将数据分割到各个分片中,
- 实现简单,但是扩展性很差,虽然简化了判断数据存储位置的操作,
- 但是会增加获取数据的难度,因为需要频繁检查所有分片来获取数据,
- 跨多个分片的查询性能比单个分片的性能要差很多,最差的情况就是不知道数据存储在那个分片,需要扫描所有的分片
- 选择分区键的时候,尽可能选择那些能够避免跨分片查询的,同时也要保证分片足够小,
- 如果可能,尽量让每个分片大小相同,这样可以在对分片进行分组的时候很容易平衡
- 跨分片的查询,需要对多个发片都执行一遍sql,最后在汇总,这类查询开销很大,最好能进行缓存
将数据分配到分片中:
-
将数据分配到分片中的方法:固定分配和动态分配,两种方法都需要一个分区函数,输入行的分区键值获得行的分片
-
固定分配:
- 分区函数只依赖于分区键的值,例如哈希和取模,实现简单开销低
- 缺点是:
- 如果分片不多,很难平衡分片间的负载
- 不能自定义数据放在哪个分片上,有可能会使热点数据的竞争很激烈
- 修改分片策略很困难,因为需要重新分配已有的数据
-
动态分配:
- 维护一个表作为分区的函数,分区键和分区号组成一条数据,通过分区键就可以获得分区号
- 动态分配增加了分区函数的开销,但是可以对数据存储位置做细粒度的控制,
- 可以生成不均衡的分片,对于服务器能力不同或者有特定目的时,很有帮助
-
显示分配
- 在插入的数据的时候,显示的选择分片,但是对于以有的历史数据会很难做到
部署分片的方法:
- 每个节点的分片使用单一数据库,并且库名相同
- 多个分片的表放在一个数据库,在表名上增加分片号
- 每个分片使用一个数据库,库中包含应用所需要的全部表,在数据库名上增加分片号,表上就不需要增加分片号了,这样就不要专门编写查询了
- 每个分片一个数据库,把分片号写到数据库名和表名
负载均衡:
-
基本思路就是:在一个服务器集群中尽可能的平衡负载量
-
目的:
- 负载均衡对于扩展策略有帮助,例如读写分离
- 能更有效的利用资源,能够控制请求的去路,可以把更多的工作分配给性能更好的机器
- 能够保证服务器的可用性
- 客户不需要知道到底请求的那台服务器
- 如果应用是有状态的,负载均衡器可以把相关的请求指向同一台服务器,避免状态丢失
-
许多负载均衡器都会支持http,但是mysql的连接是tcp,会有一些限制:
- 连接池和长连接会阻碍负载均衡器分发连接请求
- 负载均衡器通常只会针对http服务器做健康检查,mysql不接受3306端口的http请求,所以需要自己进行健康检查
-
负载均衡算法
- 随机
- 轮询
- 最少连接数
- 最快响应时间
- 哈希
- 权重等
高可用
-
高可用是相对的,不可能达到百分百的高可用
-
可用性和开销也不是线性的,可用性每提高一点,花费成本都会远超之前
-
高可用实际就是在宕机造成的损失和降低宕机时间花费的成本之间取一个平衡
-
此外,可用性的定义还应该包括应用是否能以足够好的性能处理请求
宕机的常见原因
- 最普遍的问题就是磁盘空间耗尽
- 应用的bug,很糟糕的sql和索引
- 复制导致的主备数据不一致
实现高可用:
-
可以尝试避免能导致宕机的原因来减少宕机时间
-
保证宕机时能快速恢复,最常见的策略就是制造冗余,并且具备故障转移,有两个相关的指标:
-
提升平均失效时间
- 遵循最小原则,保持系统干净整洁
- 使用良好的命名和约定来避免产生混乱
- 确保基本的配置正确
- 谨慎升级数据库服务器
- 除非证明有效,否则禁用缓存
- 避免使用法则的特性,例如复制过滤和触发器
- 监控重要的功能组件,例如磁盘空间
- 定期检查复制的完整性
- 定期归档清理
- 定期进行sql语句的审查
-
降低平均恢复时间
-
所有的宕机都是多方面原因造成的,在系统中建立冗余,保证单点的安全,打断整个链条,避免服务完全失效
-
因为地理位置、预算等,单点失效并不是总能消除的,任何一个不冗余的地方,都有是一个可能失效的单点,包括硬盘、服务器、甚至一个数据中心
-
可以增加空余容量和重复组件,来为系统增加冗余,例如建立一个集群然后做负载均衡
-
完全冗余mysql很困难,因为没有数据的数据库是没有用处的,所以必须确保备用服务器能够获取主服务器的数据
-
共享存储
- 共享存储能够为数据库和存储解耦,使用 共享存储时,服务器能够正常挂在文件系统进行操作,如果服务器挂了,备用服务器可以挂载相同的文件系统
- 共享存储可以避免除存储外的其他任何组件失效引起的数据丢失,但是共享存储本身也是一个会失效的单点,而且如果文件损坏,备用服务器也无法恢复
-
DRBD
- DRBD是一个以linux内核模块实现的同步复制技术,可以通过网卡将主服务器的数据复制到拎一个服务器上,并在主设备提交之前记录下来,
- 因为备用设备的写入需要在主设备写入之前完成,所以备用设备的性能需要至少和主设备一样
- DRBD故障转移无法做到秒级,至少需要几秒的时间把备用设备提升为主设备
- 比较昂贵,因为必须在主动-被动模式下运行,被动服务器因为处于被动状态,无法用于其他任务
- DRBD不能代替备份,例如磁盘损坏导致的数据损坏,复制的数据也会是损坏后的
- 对于写操作还增加了额外的负担、
-
这两种方法其实是保证了数据的安全,只要有数据就可以从故障中恢复
-
-
-