MySQL架构设计谈:从开发规范、选型、拆分到减压

1、MySQL数据库开发规范程序员

 

数据库规范到底有多重要?有过初创公司经历的朋友应该都深有体会。规范是数据库运维的一个基石,能有效地减小数据库出问题的几率,保障数据库schema的合理设计并方便后续自动化的管理。sql

 

曾经咱们花了大半年时间来作数据库规范化的工做,例如制定数据库开发指南、给程序员作培训等,推动的时候也会遇到一些阻力。但规范以后运维质量会有一个质的提高,也增进了DBA的工做效率。数据库

 

在开发规范方面,咱们划分为开发规范和运维规范两部分。缓存

 

1、开发规范安全

 

表设计的规范:服务器

 

  • 字段数量建议不超过20-50个网络

  • 作好数据评估,建议纯INT不超过1500万,含有CHAR的不要超过1000万。字段类型在知足需求条件下越小越好,尽可能使用UNSIGNED存储非负整数,由于实际使用时候存储负数的场景很少。数据结构

  • 将字符转换成数字存储。例如使用UNSIGNED INT存储IPv4 地址而不是用CHAR(15) ,但这种方式只能存储IPv4,存储不了IPv6。另外能够考虑将日期转化为数字,如:from_unixtime()、unix_timestamp()。架构

  • 全部字段均定义为NOT NULL,除非你真的想存储null。并发

 

索引设计的规范:

 

1)全部表必须有显式主键

 

  • InnoDB表是以主键排序存储的IOT表

  • 尽可能使用短、自增的列作索引

  • 复制结构使用row格式,若是表有主键能够加速复制

  • UNSIGNED INT自增列,也能够考虑BIGINT

  • TINYINT作主键可能致使MySQL Crash

  • 类型转换会致使查询效率很低

  • 可用uuid_short()代替uuid(),转成BIGINT存储

 

2)合理地创建索引

 

  • 选择区分度高的列做为索引

  • 单个索引字段数不超过5,单表索引数量不超过5,避免冗余索引

  • 创建的索引能覆盖80%主要的查询,不求全,解决问题的主要矛盾

  • 复合索引排序问题,多用explain去确认

 

SQL编写规范:

 

1)避免在数据库中进行大量计算任务

 

  • 大事务拆成多个事务,分批屡次操做

  • 慎用text、blob大型字段,如要用考虑好拆分方案

  • 频繁查询的字典表考虑用Cache抗

 

2)优化join

 

  • 避免大表与大表之间的join,考虑让小表去驱动大表join

  • 最多容许三表join,最好控制成两表

  • 控制join后面where选择的行数

 

3)注重where条件,多用EXPLAIN确认

 

  • where条件的字段,尽可能用区别度高的字段,这样走索引的性能更好

  • 出现子查询的SQL,先确认MySQL版本,利用explain确认执行计划

  • 进行分页优化;DML时候多个value合并

 

Schema Review:

 

1)字符集问题

 

表字符集选择UTF8 ,若是须要存储emoj表情,就改为UTF8mb4

 

2)Schema设计原则

 

  • 核心表字段数量尽量地少,有大字段要考虑拆分

  • 适当考虑一些反范式的表设计,增长冗余字段,减小JOIN

  • 资金字段考虑统一*100处理成整型,避免使用decimal浮点类型存储

  • 日志类型的表能够考虑按建立时间水平切割,按期归档历史数据

 

3)Schema设计目标

 

  • 快速实现功能为主,保证节省资源

  • 平衡业务技术各个方面,作好取舍

  • 不要在DB里进行大计算,减小复杂操做

 

总体来讲,这部分规范仍是很容易遵照的,实现起来也没有什么难度,就能取得很好的效果。

 

2、运维规范

 

(1)SQL审核

 

SQL评审这部分工做相信让不少的DBA同窗都叫苦连天,人肉审核不只效率低下,容易出错,对DBA的自身发展也很是不利,难道咱们来上班就是为了审核SQL的吗?在通过了一段痛苦的人肉审核以后,咱们接入了去哪儿网开源的Inception,并根据自身的业务特色作了一些调整。固然如今开源的SQL评审软件已经不少了,你们能够自由选择,也能够自行开发。

 

在审核与执行上线DDL语句的时候,要注意MySQL官方原生Online DDL和Percona公司的pt-osc之间的一些差别,例如pt-osc在执行时每次都要copy全表,相对来讲比较慢,好处是不锁表,而且有完善的条件检测和延时负载策略控制。官方Online DDL虽然官方也一直在改进,但生产环境使用还不是很完美,尤为要注意执行过程当中容易致使MDL锁。官方Online DDL也有优于pt-osc的地方,好比增删索引,重命名列等,以下图所示。

 

 

(2)权限控制

 

MySQL从5.6开始,逐步完善了权限系统,好比MySQL5.6能够安装检查密码强度的插件,5.7开始增长了密码过时机制、帐户锁定等功能,对SSL这一块也作了一些优化,8.0版本增长了角色的功能,权限系统已经逐步在向Oracle数据库靠拢了。在平常运维中,也可使用pt-show-grants工具提升权限审查的力度。应用程序帐号应只赋予SELECT、INSERT、UPDATE权限,DELETE的逻辑改用UPDATE实现,并启用sql_safe_updates选项。

 

另外一个有效控制权限的方法就是SQL堡垒机,早期咱们经过改造MyWebSQL实现,在Web版客户端的基础上加入了一些资源控制策略、审计、语法校验等功能。后续又使用Python开发了功能更完备的SQL堡垒机,同时支持MySQL、Oracle、Greenplum等数据库。

 

 

 

SQL堡垒机不只可控制公司内部人员的数据库权限,追溯各种人员对数据库的操做,也能避免大查询或全表更新的状况发生,支持审计需求,总体运维质量提高了一个台阶。

 

(3)MySQL版本选择

 

  • MySQL社区版,用户群体最大

  • MySQL企业版,收费

  • Percona Server版,新特性多,和MySQL社区版最接近

  • MariaDB版,国内用户暂时很少

  • 选择优先级:MySQL社区版> Percona Server > MariaDB > MySQL 企业版

 

对于版本选择这件事,建议你们仍是跟进官方社区版比较好,目前比较稳定的版本是MySQL5.6,推荐你们使用。有特殊需求的话再选择MySQL5.七、PXC、TiDB、TokuDB等数据库。

 

2、MySQL高可用架构选型

 

MySQL高可用方面,目前业界主流依然是基于异步复制的技术,例如Keepalived、MHA、ZooKeeper等,要求数据强一致的场景逐步开始使用分布式协议,这方面的典型表明有PXC、Group Replication、TiDB。下面咱们就重点来讲说keepalived、MHA和PXC这几种你们用得比较多的架构。

 

1、keepalived高可用架构

 

 

业内使用很是广泛,它部署容易、方便维护,还节省服务器资源。这种架构的一个好处就是在发生切换后,原Master只需从新拉起来便可恢复高可用,不须要过多干预。扩展起来也方便,能够任意挂载只读库和灾备库。但它存在的问题也很明显,好比Keepalived的检测机制不完善、有脑裂隐患、数据一致性较弱等等。

 

还须要注意主从拓扑的设计。以下图,只读库挂到哪一个Master比较合适?显然是M2,其它两种拓扑在发生切换后都会影响到只读库的访问。

 

 

2、MHA

 

 

MHA自诞生以来,就获得了业内的普遍关注,并迅速流行开来。与keepalived相比,MHA最大的优势就是在发生故障切换以后,能自动补齐binlog,最大程度保证数据一致性。从服务器能自动切换,无需人工干预,能很是好的工做在读写分离的环境下。基于Perl语言的脚本也很是方便进行二次开发。MHA很是适合读写压力比较大的应用。

 

但因为MHA在工做时须要配置SSH互信,所以选择这种架构时内网安全必定要作到位。另外也能够搭配Binlog Server使用。

 

3、PXC

 

 

PXC全称是Percona XtraDB Cluster,是Percona公司基于Galera协议开发的一个产品。PXC牺牲了CAP里面的P(Partition Tolerance),保留了C(Consistency )和A(Availability )。这种结构很是适合电商、金融类业务,自PXC和Group Replication出现之后,MySQL完全扫清了进入金融行业的障碍。

 

PXC的优点:

 

  • 同步复制,解决了传统架构复制延迟和脑裂的问题

  • 数据强一致

  • 多主复制,每一个节点均可以读写数据

  • 并行复制,多个事务能够并行推送到其余节点

  • 高可用,单点故障不影响集群可用性

  • 新节点自动部署

  • 与传统MySQL几乎彻底兼容

 

使用PXC要注意的问题:

 

  • 不要有大事务

  • 木桶效应,集群性能取决于性能最差的那个节点

  • 并发效率有损失

  • 网络要求较高,建议万兆网络

  • 多点并发写时锁冲突、死锁问题多

  • 写没法扩展,没法解决热点更新问题

 

除此以外,还有一类采用DNS/ZooKeeper的高可用架构,这种架构一般都须要自行开发,无通用的方案,比较适合大规模集群的高可用,这里咱们不过多赘述。

 

下面简单回顾一下上述几种高可用架构:

 

  1. 双Master架构:很是成熟,使用很广泛,要注意延迟和数据的一致性。

  2. PXC: 分布式协议,数据强一致性,并发效率略低,可用性好

  3. MHA:各项指标介于M-M和PXC之间,性能无损失,适合读写分离架构。

 

总而言之,没有最完美的架构,只有最适合的架构。选择适合本身业务的便可。

 

3、MySQL sharding拆分

 

接下来是第三个议题,MySQL拆分原则和分库分表设计。

 

首先先提一个问题,为何要拆,不拆不行吗?按照咱们的经验来看,当数据和业务到了必定的规模,都不可避免的要面临分库分表的问题。这就好像汽车的发动机同样,要达到更高的性能,4缸6缸明显是不够用的,V八、V12才是王道。

 

拆分能解决以下几个问题:

 

  • 单库并发较大

  • 单库物理文件太大

  • 单表过大,DDL没法接受

  • 防止出现性能瓶颈,提高性能

  • 防止出现抖动不稳定现象

 

肯定要进行数据库的拆分了,应该怎么拆呢?

 

垂直拆分

 

优势:

  • 拆分简单明了,拆分规则明确

  • 应用程序模块清晰,整合容易

  • 数据维护方便易行,容易定位

 

缺点:

  • 表关联须要改到程序中完成

  • 事务处理变的复杂

  • 热点表还有可能存在性能瓶颈

  • 过分拆分会形成管理复杂

 

水平拆分

 

优势:

  • 不会影响表关联、事务操做

  • 超大规模的表和高负载的表能够打散

  • 应用程序端改动比较小

  • 拆分能提高性能,也比较易扩展

 

缺点:

  • 数据分散,影响汇集函数的使用

  • 切分规则复杂,维护难度增长

  • 后期迁移较复杂

 

要先分库仍是先分表?

 

  • 分库的优势:实现简单,库与库之间界限分明,便于维护,缺点是不利于频繁跨库操做,单表数据量大的问题解决不了。

  • 分表的优势:能解决分库的不足点,可是缺点偏偏是分库的优势,分表实现起来比较复杂,特别是分表规则的划分,程序的编写,以及后期的数据库拆分移植维护。

 

一巴掌拍板直接选分库或分表都是不可取的,主要是看须要达到什么样的扩展方式,才能决定先分库仍是先分表,根据具体的场景决定。分库分表的最终目的仍是为了扩展,并且要看拆分的规划设计是针对哪一层。

 

上述问题都解决了,该考虑如何实现了,究竟是在应用程序中实现,仍是使用中间件?我的建议若是是小规模的拆分,直接在程序逻辑中实现便可,大规模的拆分再考虑使用各类中间件。

 

目前业内已经开源了不少的MySQL中间件产品,例如Atlas、DBProxy、MyCAT、OneProxy、DRDS、Vitess等等,每一个中间件都有本身的特色,个别不太成熟的可能会存在一些Bug,选用以前要作好相关的调研与测试工做,上线使用必定要保证本身能hold住。若是要彻底贴合自身业务,而且掌控得较好的仍是要自行开发。

 

下面说说咱们的拆分经验。

 

首先咱们先在压力比较大的数据库上作垂直拆分,剥离出活动、后台统计等业务。这一步也是最容易实现的。

 

接下来,若是是消息类的数据,就基于时间维度进行拆分,单表控制在5-10G,行数控制到500-1000w这个样子。这个时候咱们发现数据库的性能是比较好的,并且比较好维护。若是是用户类的数据,就按照Hash或Range进行拆分。这种状况下用这种方法拆分会拆的比较均匀一些。

 

并发仍然比较高怎么办?能够在时间维度拆分的基础上再按Range或Hash进行拆分。

 

最后要注意的就是不要过分的拆分,会形成复杂度的上升。Schema设计合理的状况下,10亿的数据量也能跑的好好的。个别不关键的应用,例如日志、监控数据等,使用分区表、TokuDB也能抗。拆分对应用层老是有损的。

 

要作个“懒”DBA。

 

 

4、利用NoSQL为MySQL减压

 

最后一个议题,咱们聊一聊NoSQL。NoSQL如今遍地开花,应用也很普遍了,业内用的比较多的主要集中在Redis、MongoDB、Cassandra等NoSQL数据库上。今天咱们主要来讲说和MySQL关联最为密切的Redis。

 

为何要使用Redis?

 

  • 数据存储在内存中,访问速度快

  • 能支持大批量操做及爆发性负载

  • 数据结构丰富,有效缓解MySQL压力

  • 协议简单,支持各类语言的API

  • 存储大量数据无需担忧性能

 

Redis主要做用仍是抗读的压力。读操做先到Redis,Redis中取不到再从MySQL数据库访问,从MySQL读取到数据后,还要回写到Redis。

 

使用Redis要注意的几点:

 

性能方面,因为Redis彻底是基于内存的访问,性能无需担忧。

 

在使用Redis时,要注意Cache 和Storage不要混合使用。不要依赖Redis的持久化,持久化这一块Redis要努力的还不少。另外若是你把Redis拿来作Storage的话,一旦Redis的内存跑满,那就惨了,全部的Redis链接都会卡着不响应。若是只是把Redis来作cache的话,那问题就不大。

 

还有诸如缓存穿透、缓存雪崩、热点key重建时缓存失效这些问题也是重点关注的对象。

 

如何利用Redis给MySQL加速:

 

1)利用K/V结构,缓存结果,例如存储用户信息、全局排行、统计信息等。

2)利用其丰富的数据结构为MySQL减压,例如计数器、排序、Hash(把表映射到Redis中)、消息队列等。

 

总结

 

 

 

系统架构设计是一个长期总结与进化的过程,讲究均衡与取舍。在进行大规模MySQL架构设计的过程当中,除了要汲取别人的经验以外,还要关注各类架构背后的业务场景与架构思想,与本身的实际业务场景相结合,才能设计出一个好的系统架构来。

相关文章
相关标签/搜索