MySQL应对并发的思考

目录

一、索引优化

二、请求合并

请求合并

合并的分析方法

三、需求裁剪

四、分布式数据库及反范式设计

基本认识

去关联化原则

分库方案

分表方案

反范式设计(冗余结构设计)

反范式设计的概念

冗余结构设计所面临的典型场景

冗余设计方案

五、认识负载

负载的构成

负载增长趋势

系统阈值

异常的监控和跟踪


一、索引优化

参见“索引优化”的单独章节。

二、请求合并

请求合并

如果查询请求过多,其实可以用内存来做缓存,比如memcache,比如redis,很多缓存方案,但是如果更新请求过多,那么缓存就没法用了。而更新请求往往比查询请求更消耗资源,这样系统i/o压力就非常大。

关于更新请求,是不是真的不能缓存呢?其实不是。

例如针对一个表的多个字段的update,可以合并到同一条语句中执行

合并的分析方法

对一个毫不熟悉的系统,如何快速分析其冗余请求的构成和合并的可能性,以及合并可能带来的开销降低呢?

1、慢查询;
2、先show processlist;看到有疑问的SQL,去explain,然后set profiling=1;
看看索引是不是对的,看看哪些SQL本身是有问题的。
3、加SQL打印日志:
第一,看查询和更新的比例。
第二,看最多查询的数据表有哪些,最多更新的数据表有哪些。
第三,看最多查询的数据表最多查询的SQL是什么样子的,
最多更新的数据表最多执行更新的SQL是怎样的,算出各自每秒的请求频率。
第四,关键分析,最多查询的SQL,基于同一主键查询的比例多不多(潜台词,可以缓存化)。
最多更新的SQL,基于同一主键的更新的比例高不高(潜台词,可以合并请求,异步处理,
当然必须根据具体业务诉求再核对一遍)

三、需求裁剪

所谓需求裁剪,并不仅仅是功能实现,还包括性能指标,以及所谓的边界条件。

案例1:搜索大翻页问题,负载越高的问题

淘宝搜索一个关键词,最多翻多少页?百度呢?google呢?
你们自行测试一下,这些巨头给出的搜索结果条目数,都是估算值,最大翻页数,基本不超过100页。
这就是设定了边界条件。

案例2:雪崩效应的处理。

当缓存扛不住,负载传递给数据库,瞬间过载,这就涉及一个灾难应急机制,简单说就是:降级服务,有损服务。在出现类似问题的时候,系统自动降级,将部分用户请求频次低,

 

 

价值低但是系统开销不低的功能或者数据临时阻断停止响应,确保整体系统的稳定性。

你损失的那些边界条件外的数据是1000个用户也不会有1个去查询的内容,
而如果你要满足这些可能需要付出500%甚至更多的系统开销和研发工作量,
这种对于很多早期创业公司来说,非常非常重要。

 

 

这就是思路的关键,用户对功能的需求,你的满足度的边界在哪里?很多程序员没有这个概念,对于数据规模小,请求并发少的应用来说,这个东西你不考虑也没什么大不了,但是如果面对数据规模大,请求并发大,你就应该有一个概念,如何设定需求的边界条件,既能满足用户的正常请求可以顺畅的响应,同时保证系统在开销可控的情况下稳定健壮的运营;而当系统出现类似单点故障,雪崩效应呈现的时候,如何设定新的边界条件,让用户在基本可用的情况下给系统一个恢复周期。这些问题都是需要提前思考,并且不断随着业务规模的增加而调整的。

案例3:关于主从分离同步的案例

刚开始做数据库主从读写分离的时候,经验也不是很丰富,然后发现一个问题,主从同步经常会有一个时延,虽然时间很短,大部分在1秒以内,但是在应用中,我们发现,用户发一个帖子,然后发完后就应该进入这个帖子的展示页吧,帖子发布到主数据库,而展示页调用的是从数据库,结果部分用户发完帖子,因为延迟,就看到了一个该帖子不存在的界面,这肯定是一个不好的情况么。当然,技术上肯定有各种解决方法,比如对这种新内容选择从主数据库访问,做一些标定等等,但是呢,我们就做了一个特别偷懒取巧的方案。什么方案呢?用户发完帖子后,先进入一个中转页,告诉用户您的帖子发布成功,3秒后自动进入帖子页。(对这个场景很多人都熟悉吧),就这么一个特简单甚至有点不是很友好的设计,主从同步延迟的问题就基本解决了。

四、分布式数据库及反范式设计

基本认识

● 用分库&拆表是解决数据库容量问题的唯一途径。

● 分库&拆表也是解决性能压力的最优选择。

● 分库 – 不同的数据表放到不同的数据库服务器中(也可能是虚拟服务器)

● 拆表 – 一张数据表拆成多张数据表,可能位于同一台服务器,也可能位于多台服务器(含虚拟服务器)。

 

去关联化原则

在设计之初,就要考虑去关联化,以备分库分表做准备。手段:反范式

● 摘除数据表之间的关联,是分库的基础工作。

● 摘除关联的目的是,当数据表分布到不同服务器时,查询请求容易分发和处理。

● 学会理解反范式数据结构设计,所谓反范式

第一要点是不用外键,不允许Join操作,不允许任何需要跨越两个表的查询请求。

第二要点是适度冗余减少查询请求,比如说,信息表,fromuid, touid, message字段外,还需要一个fromuname字段记录用户名,这样查询者通过touid查询后,能够立即得到发信人的用户名,而无需进行另一个数据表的查询。

● 去关联化处理会带来额外的考虑,比如说,某一个数据表内容的修改,对另一个数据表的影响。这一点需要在程序或其他途径去考虑。

 

 

分库方案

- 安全性拆分

将高安全性数据与低安全性数据分库,这样的好处第一是便于维护,第二是高安全性数据的数据库参数配置可以以安全优先,而低安全性数据的参数配置以性能优先。参见运维优化相关部分。

- 基于业务逻辑拆分

● 根据数据表的内容构成,业务逻辑拆分,便于日常维护和前端调用。

● 基于业务逻辑拆分,可以减少前端应用请求发送到不同数据库服务器的频次,从而减少链接开销。

● 基于业务逻辑拆分,可保留部分数据关联,前端web工程师可在限度范围内执行关联查询。

 

- 基于业负载压力拆分

● 基于负载压力对数据结构拆分,便于直接将负载分担给不同的服务器。

● 基于负载压力拆分,可能拆分后的数据库包含不同业务类型的数据表,日常维护会有一定的烦恼。

 

- 混合拆分组合

● 基于安全与业务拆分为数据库实例,但是可以使用不同端口放在同一个服务器上。

● 基于负载可以拆分为更多数据库实例分布在不同数据库上
例如,
    基于安全拆分出A数据库实例,
    基于业务拆分出B,C数据库实例,
    C数据库存在较高负载,基于负载拆分为C1,C2,C3,C4等 实例。
    数据库服务器完全可以做到 A+B+C1 为一台,C2,C3,C4各单独一台。

 

分表方案

 

数据量过大或者访问压力过大的数据表需要切分

 

纵向分表(常见为忙闲分表)

单数据表字段过多,可将频繁更新的整数数据与非频繁更新的字符串数据切分。
范例 user表 ,个人简介,地址,QQ号,联系方式,头像 这些字段为字符串类型,更新请求少;最后登录时间,在线时常,访问次数,信件数这些字段为整数型字段,更新频繁,可以将后面这些更新频繁的字段独立拆出一张数据表,表内容变少,索引结构变少,读写请求变快。

横向切表

● 等分切表,如哈希切表或其他基于对某数字取余的切表。等分切表的优点是负载很方便的分布到不同服务器;缺点是当容量继续增加时无法方便的扩容,需要重新进行数据的切分或转表。而且一些关键主键不易处理。
● 递增切表,比如每1kw用户开一个新表,优点是可以适应数据的自增趋势;缺点是往往新数据负载高,压力分配不平均。
● 日期切表,适用于日志记录式数据,优缺点等同于递增切表。
● 个人倾向于递增切表,具体根据应用场景决定。

热点数据分表

● 将数据量较大的数据表中将读写频繁的数据抽取出来,形成热点数据表。通常一个庞大数据表经常被读写的内容往往具有一定的集中性,如果这些集中数据单独处理,就会极大减少整体系统的负载。
● 热点数据表与旧有数据关系
    可以是一张冗余表,即该表数据丢失不会妨碍使用,因源数据仍存在于旧有结构中。优点是安全性高,维护方便,缺点是写压力不能分担,仍需要同步写回原系统。
    可以是非冗余表,即热点数据的内容原有结构不再保存,优点是读写效率全部优化;缺点是当热点数据发生变化时,维护量较大。
    具体方案选择需要根据读写比例决定,在读频率远高于写频率情况下,优先考虑冗余表方案。
加载热点数据方案选择
定时从旧有数据结构中按照新的策略获取
在从旧有数据结构读取时动态加载到热点数据
剔除热点数据方案选择
基于特定策略,定时将热点数据中访问频次较少的数据剔除
如热点数据是冗余表,则直接删除即可,如不是冗余表,需要回写给旧有数据结构。

● 热点数据表可以用单独的优化的硬件存储,比如昂贵的闪存卡或大内存系统。

● 热点数据表的动态维护

● 通常,热点数据往往是基于缓存或者key-value 方案冗余存储

 

反范式设计(冗余结构设计)

反范式设计的概念

● 无外键,无连表查询。
● 便于分布式设计,允许适度冗余,为了容量扩展允许适度开销。
● 基于业务自由优化,基于i/o 或查询设计,无须遵循范式结构设计。

 

冗余结构设计所面临的典型场景

●原有展现程序涉及多个表的查询,希望精简查询程序
●数据表拆分往往基于主键,而原有数据表往往存在非基于主键的关键查询,无法在分表结构中完成
●存在较多数据统计需求(count, sum等),效率低下。

 

冗余设计方案

基于展现的冗余设计
● 为了简化展现程序,在一些数据表中往往存在冗余字段

 

基于查询的冗余设计
● 涉及分表操作后,一些常见的索引查询可能需要跨表,带来不必要的麻烦。确认查询请求远大于写入请求时,应设置便于查询项的冗余表。
冗余表要点
-数据一致性,简单说,同增,同删,同更新。
-可以做全冗余,或者只做主键关联的冗余,比如通过用户名查询uid,再基于uid查询源表。

基于统计的冗余结构
● 为了减少会涉及大规模影响结果集的表数据操作,比如count,sum操作。应将一些统计类数据通过冗余数据结构保存。
● 冗余数据结构可能以字段方式存在,也可能以独立数据表结构存在,但是都应能通过源数据表恢复。

历史数据表
● 历史数据表对应于热点数据表,将需求较少又不能丢弃的数据存入,仅在少数情况下被访问。

 

五、认识负载

负载的构成

● CPU开销是多少,是哪些进程和服务占用的。
● 内存开销是多少,是哪些进程和服务占用的,如果内存占用了swap分区,大量的硬盘虚拟内存操作,效率自然会直线下降。
● I/O开销 是多少,读请求的频率,写请求的频率,什么服务和什么操作占用了大量的i/o。
● 连接数是多少,是怎么分布的,比如http链接多少,数据库链接多少,memcache链接多少,当然更细致的三次握手的链接是多少。
了解这些,是优化的基础。

 

负载增长趋势

随着应用请求的增加,你的系统的负载是怎么增加的。
第一种,是线性增加,就是请求两倍,负载变成两倍。
第二种,是指数增加,请求两倍,负载变成四倍甚至更多。

第三种,收敛增加,随着你的请求增加规模,负载的增加低于线性增加并逐步收敛,比如说,大量使用缓存和异步更新,请求越多,缓存命中率越高,异步更新的请求合并率越高,这样负载的增加就呈现为收敛性,这样系统的支撑性就会很强大。

系统阈值

很多时候,我们系统出现瓶颈,并不是因为负载很高,而是因为某个请求规模超越了系统阈值,导致无法应答请求。

典型范例如:

syn flood攻击时,最大的syn连接池被占满,导致无法应答新的请求,而此时服务器负载非常之低,这就是典型服务器很闲但不响应的情况。
http链接数越界,http链接超时设置较长,大量链接没有释放,导致链接数超过默认最大值,http服务器无法响应新请求。
mysql链接数越界,大量使用常链接或不释放链接,导致大量sleep链接占满系统默认连接数,数据库无法响应新请求。
最大文件打开数越界,大量使用临时文件和缓存文件,大量的文件打开操作,而系统默认值没有调优。

 

要充分理解各种系统阈值,并针对自己的应用特性进行调优,才可以充分发挥系统硬件特性,实话说,很多系统或服务的默认阈值都偏低。

 

异常的监控和跟踪

要对各种异常敏感,很多严重的性能问题其实是有先兆的,比如偶尔的501错误,偶尔的访问卡顿,偶尔的链接出错,很多时候,用户刷新一下,这个问题就没有了,但是很可能此事系统已经进入了一个不稳定的状态。

 

有经验和有意识的架构师或运维专家,应该会做日志的跟踪和审计,随时查看这种错误信息的出现频率,并对此进行持续的跟踪监控,在高并发的真实环境中,在一定比例内,这样的偶发异常是非常难免的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值