首页 > 数据库 >关于2022年3月14日到3月18日数据库发生数次断连的一些思考与总结

关于2022年3月14日到3月18日数据库发生数次断连的一些思考与总结

时间:2023-02-23 12:47:19浏览次数:60  
标签:14 预约 18 数据库 接口 查询 获取 首页 2022

1 问题记录 抽样调查

3月14号九点到十点左右的时候 医院医生反馈患者列表获取极其缓慢

3月16号九点到十点左右的时候 数据库发生断连超时

3月17号12点左右 数据库发生断连超时

 

取出3月16号凌晨4点到下午17点50服务器Token校验成功的请求,依次放入相对应的文件,使用Java程序进行接口访问次数统计,结果如下图:

 

 

 

接口访问统计折线图

 

 

2访问量排名靠前接口逐一分析

2.1查询预约记录接口(访问量第一名69904次)

(1)查询预约记录接口所做的工作是:根据患者ID和渠道名称,查询患者的注册信息。根据注册信息里的IDCard和idType 查询院内接口未来一定时间范围内的预约记录。未优化之前的老代码逻辑是无论院内返回的预约记录里的预约状态是否是取消,都for循环根据院内返回的字段查一遍数据库的register_order表。在查询表的时候,把所有的字段全部获取到(事实上用到的字段只是其中一小部分),以及在SQL里面使用了 in (可能会导致全表查询)。

(2)优化后的代码:根据院内返回的odStatus状态,如果是-1(患者主动取消)则不进行数据库查询。以及查询register_order表的时候 做了返回vo的封装,只获取代码里需要的字段,舍弃不需要的字段。(相同的查询条件下 获取查询返回的字段越少 SQL查询所耗的时间越少)。先不在sql里面筛选出status为1和4的订单,而是查出列表后使用Java stream流筛选出对应的结果,避免产生全表查询。

(3)接口访问频率分析:该接口目前在微信支付宝随申办都在使用,这个接口之所以调用频率如此频繁,是因为多数患者进入我们的app,都是先进行预约挂号,付费等操作。为了实时获取最新的订单状态,必须通过查询预约记录接口来实时获取院内返回的预约状态,以及通过register_order表获取cureNo、origin、registerOrderId等后续支付或进入在线看病聊天室需要的字段。所以,针对这种访问量异常频繁的接口,每做一个小优化,对数据库IO压力都是会有着明显性的缓解的。

2.2 Message中转接口(访问量第二名 64619次)

这个中转接口里面根据type做了不同的方法转接,相当于落干个接口的中转站。但是通过计数发现,一段时间内的Message接口访问,将近87%的访问量都中转到了 type=PAT_REGISTER_ORDER_NOTIFY(获取用户预约数量)上面,所以可以看作 获取用户预约数量是3月16号访问量的银牌接口。

 

 

(1)获取用户预约数量做的工作很简单,根据患者的customerId和appName查询register_order表,返回该患者在当前渠道有效的预约数量。然而就是看似如此简单的工作,因为被设置在微信、支付宝、随身办的首页上,导致只要是患者进入了小程序首页,或者跳转到了首页,都会调用获取预约数量接口。优化前的代码,直接根据customerId查询register_order表,用到了 in(可能会导致全表查询)查询当前日期之后的有效预约订单量,查询出list(相当于查询所有符合条件的register_order 实体所有字段的list)再根据list获取size。把size返回给前端。

 

(2)优化后的代码,直接通过患者id和appName查询customer_register表(此方法做了缓存处理),获取到注册信息,查询院内接口未来一定时间范围内的预约记录。再根据院内返回的 list 筛选出odStatus 为0(已预约)和1(已挂号)的预约记录。不通过查register_order表获取预约数量。虽然没有区分出当前渠道,但是这样做并不会给患者带来多大的影响(患者点击进预约记录会查看到具体的预约信息),反而完全不走数据库减轻了数据库大量的IO。如果院内后续反应预约查询接口访问频繁(实际上在优化之前这个接口访问量也是非常大的),则可以做一个限制,比如十秒内首页不重复获取预约数量。

 

(3)接口频率分析:这个接口会有如此高的频率,原因很明显,因为被设置到了进入小程序首页自动调用。相当于一个用户,进入小程序,这里点一下,那里一下,然后回到首页,如此操作。他哪怕是啥都没干,获取预约数量接口也会重复地去调用。可以想象到,在访问量高峰,数据IO压力接近超负荷的时候,如果接近上千的患者同时进入首页,即使大部分人没有使用任何功能,只是单纯地点击,也让数据库进行了上千次的预约记录查询(而且是短时间内高并发超负荷查,系统查询频率最高、数据量巨大的register_order表)

2.3 获取极速配药订单查询接口(第三名 59603次)

(1)获取极速配药订单接口所做的工作是:根据患者ID和渠道名称,查询患者的极速配药订单状态,前端在首页设置了自动访问该接口。通过status(1,2,3,4)在首页显示不同的提示信息,提示患者进行极速配药的后续操作。这个接口看似简单,跟第二名的获取预约数量接口影响还要小很多(至少它没有查询regsiter_order这个高频率表),因为大部分人压根没有使用过极速配药(管理平台极速配药日平均订单不超过两百),所以在查询customer_recipe_order表的时候,大部分的查询结果都为空,会直接返回给前端空结果。

那么为什么要单独分析这个普通的查询接口呢?原因跟查询预约数量接口一样,它们都会在用户进入首页自动调用,并且每次切换都会调用。导致它的查询并发量非常巨大,虽然大部分会查询空结果,但是这照样对数据库产生了很大的IO压力。

 

(2)优化后的代码:根据后端代码逻辑分析出:customer_recipe_order表在每天的凌晨一点会自动轮询前一天的订单列表,状态查出来为4(药品待支付)的,会被直接设置为6(前一天12点之前未付支付取消该订单),状态查出来为1(挂号待支付)的,会被直接设置为0(没有付挂号费用)。所以可以得出结论,只要不是当天使用极速配药的患者,在首页查询这个获极速配药订单接口是没有任何意义的。因为非当天的订单状态永远不会是(1,2,3,4)里的任何一个。所以即使有数据返回给前端,前端也不会有任何显示。

 

根据这个结论,设置了用户在调用保存病情评估表和处方信息保存新创建的customer_recipe_order对象时,设置一个redis缓存,过期时间设置为当前距第二天零点间隔的秒数再加600秒。然后在获取极速配药订单接口新增一个参数,mainPage 如果是首页调用该接口就传1。(目前前端已经在微信小程序部署上线)。在首页调用该接口的用户,如果没有在redis缓存中取到当天的预约记录,那么就默认为这个用户今天没有使用极速配药。直接返回空数据给前端。

这样做既考虑到了使用极速配药的那一小部分患者的使用体验。也避免了数据库进行大量的无意义查询操作。

 

(3)接口访问频率分析:该接口目前在微信支付宝随申办都在使用,这个接口之所以调用频率如此频繁,是因为这个接口被设置到了进入小程序首页自动访问。看似不起眼的查询,在接口调用频率异常飙升的情况下,对数据库的IO压力也是不得不引起重视的。

 

(4)可以想象到,当用户访问量飙升的时候,超大量的用户在进入微信、随申办、支付宝小程序首页的时候,这个接口就会被疯狂调用(虽然在用户看来他们好像没有干任何事和没有看到任何有效的提醒)。加上第二名的获取就诊预约数量接口,相当于在高峰期时极短的时间内,大量的客户端高并发地调用这两个接口,后端也没有做任何的措施,导致接口调用几次,可怜的数据库就得查几次。数据库连接池爆掉,近两周反复发生超时的问题,不能说百分之百,至少百分之六十与大量客户端首页短时间内异常疯狂地调用这两个接口有关系。

2.4 其余接口调用分析

(1)获取文章内容接口 排名第四 16479次。这个接口目前在支付宝上使用,微信端已经转移到访问微服务接口。这个接口的访问频率跟前三位大哥比起来少了不少。可以说虽然他排名第四实际上就访问量来说只能算是小弟。但是一万六千多的日访问量也是会对数据库产生IO压力的。优化前的老系统没有对这个接口进行redis缓存,事实上这个接口返回的内容很简单,就是两篇文章。而且很长时间内都没有改动过。所以优化后的代码将它进行了redis缓存。与此相同的还有排名第十的小弟获取国家字典接口,同样做了redis缓存优化。

 

2.5 后端部分代码逻辑优化

涉及到轮循查询register_order表的重点做了优化,详情看后端代码git提交记录。

 

3 总结与反思

(1)发生数据库断连,这已经不是一个新问题了,早在去年,也出现过几次。当时的想法一直是认为数据库容量不够,需要扩容。但是从来没想过,我们的前端,我们的后端在处理业务的时候,是否真的在有节制地使用数据库的资源。毕竟无论怎么扩容,数据库的资源始终是有限的。本次抽样统计出的接口访问量排名以及做的相关代码优化,虽然不能百分之百确定以后是否可以避免此类情况的发生。但是可以肯定的是,通过这些优化,我们的数据库负载量是可以得到很大程度的减轻的

(2)反复发生数据库断连,不能简单地认为就是数据库容量不够,数据库需要扩容、需要迁移接口才能解决问题。而是要全方位考虑导致这个问题的各种可能的原因。排名第二和第三的接口,与排名第四的接口访问量差距如此悬殊,就很明显地说明了一些问题。前端在首页自动调取接口,如果处理不当,所造成的无意义的、高并发量的查询是对数据库可能有着毁灭性打击的。

(3)在平时的开发过程中,一定要谨慎使用进入首页调取接口这个操作。一定要考虑到这个操作如果所有用户进入首页都会调,是不是会产生大量无意义的查询。以及这个操作的目的是什么,如果只是为了服务使用一个特定功能的用户群体(比如获取极速配药订单接口),而不惜让所有用户都去调这个接口,是否做了相对应的屏蔽措施,避免产生大量的,查询结果为空的无意义查询,给数据库造成压力。

 

 

OVER......

标签:14,预约,18,数据库,接口,查询,获取,首页,2022
From: https://www.cnblogs.com/dontang-blog/p/17147524.html

相关文章