可扩展性。 即通过增加资源提升整个系统吞吐量的能力
一般会有如下的角度影响负载:
- 数据量
- 用户量 更多的用户,意味着更多的数据,更复杂的查询,更多的事务
- 用户活跃度 容易造成热点
- 相关数据集的大小 即关联数据,比如好友
可扩展性的数学表现:
- 最简单的是线性的,资源翻倍,吞吐量翻倍
- 但是由于有些工作是线性的,无法通过并发来提升,这样曲线就会趋于平缓
- 再引入扩展带来的内部节点或者是线程间的通信,会造成曲线的不降反升
- 考虑到有一些I/O密集型的应用,扩展只会可能变成全都读取内存,还有可能造成曲线上扬
扩展Mysql
通常系统初建时要考虑一点可扩展性。在扩展之前,要先压榨单机性能,比如算法调优等等。
向上扩展就是换CPU,磁盘等等。总有上限。
横向扩展
读写分离
通过Mysql复制,将数据分发到多个服务器上,然后备库用于读查询。
按功能分
更像是系统层面分离。比如一个网站分为论坛,新闻等多个库。这样分发很快就会有界限。还得考虑其他的分发
数据分片
用的最多
扩展写容量必须分片
要有足够大的数据量以及业务可分的时候才分。
一般可以按照用户ID,时间等进行分片
分区键 , 决定哪一行存储在哪个位置。
常常是分厂重要的实体主键,会尽量避免跨库的查询和通讯。 特别是不能定位在哪个节点上,需要所有节点扫描。
可以使用ER图找到处于中间的点
多个分区键
这种情况可以把要分区的键的表的关键字段在其中另外一个键的表中做冗余。来做关联查询
问题1: 跨片查询和聚合。 可以使用汇总表,搜索引擎
问题2:一致性。外键失效,需要应用保证
数据分配策略
都会有分区方法,传入分区键, 输出分区号
固定分配:
分区方法只依赖分区键。
比如哈希函数和取模运算。 CRC32();
特性:
- 简单开销低
- 如果分片大但数量少,则不好分配负载
- 无法自定义数据放到哪个分片上。 比如活跃度。 分片切分的小一点可以缓解这个问题
- 修改策略困难
动态分配
利用外部资源,可以是表或者是目录服务器等等。来记录分区键和分区iD之间的关系。 这种可以很灵活。
通常都是两种结合使用。 比如先用静态的方式处理一下分区键,再用动态的方式把处理后的结果映射到分区Id上
显示分配
就是分配策略本身已经显示成为了分区键的一部分。能直接看出来。
重新均衡分片数据
可以使用动态分配策略。相对随机的分配。
并且还能够根据每个服务器的负载情况选择关闭
还可以为想均衡的表简历备库,然后修改访问机制,各负责一般的数据,然后删除不用的数据。
唯一ID
分片了,自增主键就不好用了。
可以有如下的方案搞:
- auto_increment_increment和auto_increment_offset. 设置步长和偏移量来解决,比如第一个表是1,3,5. 第二个表是2,4,6
- 全局表自增来生成唯一
- 使用memcached的incr(),也可以用redis
- 使用复合值,分片id_自增
- 使用guid
分片工具
基于分片的系统,如果应用创建多个数据源分别访问分片就有点数不过去了,应该有抽象层。其应该具有如下的功能:
- 连接到正确的分片并执行查询
- 分布性一致性校验
- 跨分片关联操作
- 跨分片结果集聚合
- 锁和实物管理
- 对新分片的处理能力。
有很多不错的工具可用:
Hibernate Shards
HiveDB
Sphinx 全文检索引擎,在分片中的聚合关联查询等有用。
多实例扩展
为了更大的压榨CPU的性能,可以单机多实例多分片的部署
还可以通过虚拟化技术
这种扩展可能会带来I/O的瓶颈,可以使用多网卡的方式
集群扩展
云,集群。这个是理想的状态,数据库能够弹性扩展,自动分片等等。
Mysql收到了No SQL的挑战,其中一点就是Nosql可以更好地集群,但是Nosql存在很多其他的问题,比如事务,查询上的弱点,其为了解决这些弱点,也越来越像关系型数据库。
NDB Cluster是一个可扩展的数据库,既可以使用NoSQL,又可以使用Mysql存储引擎,我们经常可以选用的类似的组件有:
- Mysql Cluster
- Clustrix
- ScaleBase
- Akiban 查询加速器,可以加在备库上,目前没有生产环境的使用
向内扩展
对不需要的数据进行归档和清理
需要考虑如下的问题:
- 对应用的影响 不影响业务,高效的找到行,并小块小块的删除,以平衡一次归档的行数锁,事务负载间的平衡
- 数据一致性
- 避免数据丢失
- 接触归档, 要有一个补充方案,如当前找不到了,应该设计高效的去归档数据部分检查的策略
保持活跃数据独立
- 分表 分成热表和不热表有利于高效的利用缓存。缓存每次缓存一页,一页中有10%热的可能就会整页缓存,造成了90浪费,分表之后,热度数据可能占据整个页的80%,效率更高。
- 分区
- 基于时间数据分区 把最近的时间的数据放到高速硬盘中。可以使用动态分片来实现这种策略。使用如下的分片目录表:users(user_id, shard_new, shard_archive, archive_timestamp)。定时数据转移。记录新分片和旧分片以及切换分片的时间。
负载均衡
前端负载均衡器,根据服务器性能情况分发请求。
目的: 更有效的使用资源。 可用性提高(保证有服务有用), 透明。
跟分片和复制关系密切,可以部署在任何一个环节,比如应用前端,数据库前端等
可选的方案: DNS, LVS, TCP代理等等。普遍使用F5, HAProxy
直接连接
应用直连。不使用中间件完全用业务来判断负载,如选择不同的备库做不同的逻辑。
1. 读写分离
写用主库,读用主备分担,实时性的用主库,其他用备库
让应用检查复制延迟,提高容忍脏数据的能力
基于会话,自己修改的数据查看时查主库。
基于版本,查看下备库的时间戳版本类型的字段查看下如果太旧就查主库
2. 修改DNS
比较粗的方式,把主库和备库绑定在不同的DNS中,然后切换。但是因为不是原子的,会被缓存等等原因并不是很好用。
引入中间件
- 负载均衡器
一般的负载均衡器都是HTTP协议的,但是Mysql需要TCP协议的,因此要使用能支持TCP协议的,但是这不是专门为Mysql设计的,还是会有一些限制。- 不能很好的均衡,因为无法知道负载权重
- 均衡器并不能很好的分辨Mysql连接的状态,保证他能尽量练到固定的服务器,提高缓存效率
- 线程池可能用不到负载分发
- 要求均衡器支持TCP分发及TCP端口监测等等。
- 负载均衡算法
- 随机
- 轮询 依次发送请求
- 最少连接数 适合有新服务器加入的时候,因为加入了新的服务器,其响应速度没有缓存会比较慢,因此先把最少连接数
- 最快响应
- 哈希 对源IP进行hash
- 权重
- 排队,设置最大连接数。排队处理
一主多备间的负载均衡
- 功能分区
报表,分析,数据仓库,全文索引等 - 过滤和数据分区
通过复制的过滤功能,将不同的数据分配在不同的备库上 - 保证备库跟上主库 MASTER_POS_WAIT()可以保证主库等待备库同步
- 同步写操作, 有半同步机制