快速,持续,稳定,傻瓜式
支持Mysql,Sqlserver数据同步

DBbrain诊断日 | 不这么办,数据库敢崩个三天三夜给你看

在线QQ客服:1922638

专业的SQL Server、MySQL数据库同步软件

为了更好地帮助DBA运维数据库,腾讯云将在每月12日进行DBbrain诊断。腾讯云数据库智能管家DBbrain的能力为每个人提供了思路和建议。优化问题并使用数据库的方法!

此诊断日的主要共享内容:如何解决由热更新引起的雪崩效应。

这个问题是真实网络故障的真实案例,近几个月来许多客户也经历了类似的故障,这对于Di B来说尤其令人印象深刻。在DBA的过去几年中,我已经处理过类似的问题。以下共享内容将从对实际案例的回顾开始,深入分析失败的原因,为您提供有效且有效的紧急降级解决方案,并最终恢复业务。实施级别提供了一些启发性的建议。

1

第一部分案例分析

当业务中发生大量请求失败时,这种失败情况相对简单当时几乎处于”不可用”状态。同时,相应的MySQL数据库也有大量的CPU使用率过高警报。

1.登录数据库,并通过show processlist查看实时屏幕截图,如下所示:

2.MySQL版本是5.7 ,数据库表结构如下:

  • >

创建表`docid_generator`(`id` int(4)NOT NULL AUTO_INCREMENT,PRIMARY KEY(`id`))ENGINE = InnoDB AUTO_INCREMENT = 2 

3.业务请求会话如下:

  • ul>

     connectupdate docid_generator set id = last_insert_id(id + 1);选择last_insert_id()退出

    通过初步调查,我们了解到表Record中只有一个字段和一行,该部分的业务逻辑是通过last_insert_id(expr )mysql中的功能功能;根据进程列表执行耗时的反向订单视图,最长的耗时的sql也是这种类型的更新请求; innodb status可以在等待此记录的X锁中看到大量事务;更新的X锁定使请求只能串行执行,导致响应缓慢,但是第一批更新请求被卡住的原因是什么?

    Pref分析表明,lock_deadlock_recursive函数占据了CPU回收事件的近50%。此功能通过深度优先算法进行递归调用,以检测是否满足死锁条件,然后执行最小成本事务回滚。

    检查information_schema中的innodb_trx事务锁定等待队列,发现已经有6100多个锁定等待消息。

    在检查了文档之后,我们发现InnoDB监视器输出的最新死锁检查信息包含”在锁表中等待的时间太长或太久” GRAPH,”我们将回滚以下事务”,指示等待事务列表的长度已达到200的限制。具有200个以上事务的等待列表被视为死锁,并且尝试检查等待列表的事务将被回滚。如果锁定的线程必须在等待列表上查看该事务拥有的超过1,000,000个锁,则可能会发生相同的错误。

    每个请求都维护自己的锁定队列。在这种情况下,并发操作数为200,因为单个记录X锁只能按顺序执行,并按顺序维护其自己的锁队列,记录阻塞队列长度的限制为(1 + 199)* 200/2!因此,此阶段需要很长时间。

    更容易知道为什么要花这么长时间。因为业务场景是单个ID分配,所以只有一条记录,并且逻辑上不会有死锁,因此可以完全关闭死锁检测功能。幸运的是,版本5.7 innodb_deadlock_detect可以关闭死锁检测。结束后,我们又进行了200项并发测试,从最初的10s增加到0.2s,性能提高了50倍。

    在这里进行分析,我相信每个人都必须对该失败案例有更深入的了解。在前面的介绍中,为了不中断故障分析的连续性,跳过了一些数据库概念。这里有一些详细介绍给您。

    “死锁”可以理解为由于争用资源或彼此通信而由两个或多个线程引起的阻塞现象。将无法前进。此时,据说系统处于死锁状态或系统具有死锁。这些始终在等待的进程称为死锁进程。

    在数据库中,我们可以将图像理解为:

    如上所示,事务A正在等待事务B释放id = 2锁,事务B正在等待事务A释放ID = 1的锁。

    这种情况是死锁。解决死锁的方法有两种:

    1)直接输入并等待直到超时。可以通过参数innodb_lock_wait_timeout

    设置此超时。2)启动死锁检测。找到死锁后,死锁链中的某个事务将主动回滚以允许执行其他事务。将参数innodb_deadlock_detect设置为on,这意味着打开此逻辑。

    innodb_deadlock_detect = on,此选项用于禁用MySQL的死锁检测功能。在高度并发的系统上,当许多线程正在等待同一锁时,死锁检测可能会导致速度降低。发生死锁时,如果禁用死锁检测,则可能会更有效,因此您可以依靠innodb_lock_wait_timeout的设置进行事务回滚。

    MySQL默认使用死锁检测,InnoDB自动检测发送死锁的事务,并回滚导致死锁的一个或所有事务。 InnoDB将选择权重较小的事务以在导致死锁的事务中回滚。该权重值可以由事务中插入,更新和删除的行数确定。

    如果innodb_table_locks = 1(默认值)且autocommit = 0,则InnoDB可以感知到表锁的存在,并且上层MySQL层知道行级锁。否则,InnoDB无法检测到由MySQL LOCK TABLES语句设置的表锁或由InnoDB以外的存储引擎设置的锁的死锁。通过设置innodb_lock_wait_timeout系统变量的值来解决这些情况。

    1

    部分? Ⅱ有效且有效的紧急降级解决方案

    如果电子商务业务处于大促销和高增长的情况,则在线教育业务在诸如注册之类的高并发场景中也遇到了类似的热更新失败。以及签到,游戏服务开放等。我相信每个人都不会有太多的时间来合理化和挖掘问题的根本原因,做出最合理的计划优化也就更加困难。此时,无论使用哪种方法,用户或业务方对数据库的要求都必须首先运行业务(恢复)。

    因此,对于热点更新失败,DBA通常会紧急使用计划:重新启动,切换,终止(无论是使用pt-kill还是您自己的终止脚本,显然很难解决,并且会增加阻塞)1.权限控制(很可能会损害某些正常的核心业务逻辑并导致仍然失败的业务)。很有可能无法完成业务恢复。即使损失减少了,也很难不依靠业务方的干预来完成。

    腾讯云数据库智能管家DBbrain为了防止用户数据库在热点更新时被沉重的压力挂断,提供了” SQL限流”和”热点数据保护”两项功能,以帮助用户实现有效和有效的降级和保护在数据库方面确保用户核心业务的正常运行。

    1.SQL当前限制

    DBbrain提供了” SQL当前限制”功能,可以帮助用户在数据库端实现优雅的临时降级。通过在SQL进入数据库内核之前拒绝该方法,它可以解决更多的高并发错误,并且无法通过kill迅速恢复。除了上述的”由死锁检测阻止方案引起的热点更新”之外,它还适用于:

    • 某种类型的SQL并发具有急剧上升,影响正常服务(例如缓存渗透或异常调用),导致非并发的SQL语句突然上升。
    • 存在数据偏斜SQL,它会影响正常业务,例如在大促销期间提取某些大数据,从而导致整个系统繁忙。
    • 未创建索引SQL,这会影响正常业务。例如,新启动的SQL调用特别大,并且未创建索引,从而导致整个系统繁忙。

    用户可以在DBbrain控制台中设置目标SQL的特征。

    • SQL类型:选择,更新,删除,插入,替换
    • 最大并发数:相同时的并发数时间超过设置的阈值SQL将被拒绝
    • 当前限制时间:支持设置规则的持续时间,超时后不再生效
    • SQL关键字:匹配时关键字匹配不正确遍历关键字以查看SQL中是否存在此关键字。如果有几个关键字,它们将被匹配几次。

    DBbrain将基于SQL示例的关键字自动拒绝请求,以确保业务的核心服务正常运行,并计算该期间内被拒绝的SQL请求的数量打开” SQL限制”的时间。

    2.热点更新保护

    DBbrain旨在消除尖峰,并极大地优化了单个更新行数据的运行性能。启用自动热点更新检测后,系统将自动检测是否存在单行热点更新(在同一数据行上等待的行锁数超过32个后续事务将开始等待),如果是,它将将导致大量并发更新排队执行以减少由于大量行锁或触发大量死锁检测而导致的并发性能下降。

    DBbrain提供的”热点更新保护”功能支持自动结束和手动关闭两种模式,并且可以设置自动结束时间以实现灵活的控制。

    3.热点更新优化建议

    在上述情况下,高于5.7.15的版本可以通过关闭死锁检测方法来提高性能,您可以使用腾讯云数据库智能管家DBbrain提供的” SQL电流限制”和”热点更新保护”来减轻由于大量热点更新而导致的数据库负载压力。然后,以下各章将从业务实现的角度分享一些启发性的建议。

    3.1)基于MySQL的实现

    表结构如下:

    创建? TABLE?`id_allocate`? (`id`?bigint?NOT?NULL?AUTO_INCREMENT,business_tag?varchar(20)?不是?null,PRIMARY?KEY?(`id`),UNIQUE?KEY?`Name`?(Business_tag))ENGINE = InnoDB AUTO_INCREMENT = 2; 

    3.1.1)与上述示例类似,通过mysql last_insert_id(expr)函数方法:

    请求逻辑:

     connectupdate ? id_allocate?组? id = last_insert_id(id + 1)?哪里? business_tag = \#x27; test1 \#x27 ;;选择? last_insert_id()exit 

    注意:在5.7以上,请关闭innodb_deadlock_detect死锁检测;

    3.1.2)通过mysql auto_increment字段,删除business_tag字段,仅保留id字段,请求逻辑:

     connectinsert?进? id_allocate?值(null);选择? last_insert_id()退出

    注意:数据量将继续增加,并且可以定期删除或创建低峰对于分区表,请定期删除历史数据

    纯粹依靠在MySQL实现上,第一种方法更简单易用。为了获得高可用性,通常的想法是存在于两个MySQL实例中,设置增量步长和起始值,例如两个数据库,设置auto-increment-increment = 2,设置auto-increment-offset为1和2。 request两个DB依次获得1、3、5、7和2、4、6、8。此方法可以避免单个MySQL故障的影响,但与此同时,系统的严格单调增加也已成为趋势增加(如果单个计算机出现故障,则id可能会变小)。/p>

    3.2)基于Redis的实现

    使用redis的incr和incrby方法,支持的qps更高。同样,如果您担心高可用性,您可以将两个密钥分别设置为存储在两个Redis实例上,这可以通过控制incrby的初始值和偏移量来保证,此处的明显缺点是Redis数据无法持久保存,但目前腾讯云Redis支持主从同步

    3.3)服务实现 ,双机房灾难恢复和备份功能。 p>

    表结构:

    创建?表? `id_allocate`? (`id`?bigint?NOT?NULL?AUTO_INCREMENT,business_tag?varchar(20)?不是?null,max_id?bigint?不是?null,step?int?not?null,PRIMARY?KEY?(`id`), UNIQUE?KEY?name (business_tag))ENGINE = InnoDB AUTO_INCREMENT = 2; 

    business_tag标识企业;

    max_id标识当前分配的最大ID;

    步骤标识每次idallocate-server访问数据库时被拉开的id间隔的大小。

    实现思路:第三方通过调用idallocate-server服务获取ID。 idallocate-server内存至少包含三个值:当前中值,最大id1和最大id2; id2和id1之间的差异仅一步之遥。最初,idallocate-server服务从数据库更新了两次,分别获得了初始值mid,id1和id2:

     beginselect ? max_id?从? id_allocate?哪里? business_tag = \#x27; test1 \#x27 ;对于?更新;? #获取midupdate? id_allocate?组? max_id = max_id +步骤在哪里? business_tag = \#x27; test1 \#x27 ;;选择? max_id?从? id_allocate?哪里? business_tag = \#x27; test1 \#x27 ;; #获取id1commit 
     beginupdate? id_allocate?组? max_id = max_id +步骤在哪里? business_tag = \#x27; test1 \#x27 ;;选择? max_id?从? id_allocate?哪里? business_tag = \#x27; test1 \#x27 ;; #Get id2commit 

    当第三方请求idallocate-server获取ID时,mid一直在增加,当达到id1的90%时,您需要检查id2是否已经存在,如果不存在,则访问数据库获取它。如果存在,则在中间达到id1的大小后,将分配id2部分。当中点达到id2的90%时,有必要检测id1是否存在。依次循环以确保idallocate-server内存中至少存在一个步长缓冲区编号段。

    在上述方案中:

    1.可用性:idallocate-server服务可以水平扩展以避免单个点; MySQL级别可以通过主备集群半同步,也可以通过强一致性同步来确保,并且MySQL在短时间内发生故障不会影响服务。

    2.性能:将更新MySQL的请求减少到纯MySQL id分配方法的1/步(一次更新db,而没有step id大小),减轻了对数据库;同时,通过设计id2和id1双数段,它避免了延迟故障,该延迟故障是在完全分配单个id1后需要等待idallocate服务器实时更新db的。

    按照”腾讯云数据库”的官方微信并回复”诊断日”以查看以前所有诊断日的内容。

    欢迎提交文稿

    工作时不知道遇到麻烦时该怎么办?欢迎您为诊断日做贡献。所选病例将由腾讯云高级专家”咨询”,并将在DBbrain d上进行在线分析和教学诊断日帮您提供解决方案。 如果提交论文,您可以得到一个企鹅娃娃。如果选择问题,将获得腾讯云数据库千元代金券提交论文后请关注”腾讯云数据库”的官方微信,并回复”投稿”。

    ?特殊体验云数据库

    ↓↓单击此处获得更多惊喜优惠

相关推荐

 
QQ在线咨询
售前咨询热线
QQ1922638