当前位置: 澳门新濠3559 > 编程 > 正文

db.php配置信息里的localhost,最终导致了业务异常

时间:2019-12-08 22:39来源:编程
关于这个问题我纠结了很久,每次打开网页yiidbConnection::open几乎都耗时1000ms。 db.php配置信息里的localhost,最终导致了业务异常澳门新濠3559。在一次排查线上case的过程中,经分析后发现

关于这个问题我纠结了很久,每次打开网页yiidbConnection::open几乎都耗时1000ms。

db.php配置信息里的localhost,最终导致了业务异常澳门新濠3559。在一次排查线上case的过程中,经分析后发现问题的原因是由于缓存淘汰策略存在问题而引起了缓存与数据库不一致,最终导致了业务异常

导语在知乎等地方经常看到有人问,Python的多线程是不是鸡肋?为何我用多线程性能一点没有提升,有时候性能反而下降?在这里通过日常工作中遇到的问题以及自己的一些总结,来一探Python多线程究竟是不是鸡肋;如果不是,那又该如何使用。**

其实这个问题很好解决:只要把configdb.php配置信息里的localhost,改成ip地址就好,可能是地址解析的原因才会耗时那么久。

优化前的流程

1、遇到的问题

 

写流程:
  • 淘汰cache
  • 写db

工作中常用到python来分析文件,统计数据;随着业务的发展,原先的代码性能受到了一定的挑战,下面根据两个案例来讲解在python的使用过程中,遇到的一些问题,以及自己的一些总结。

读流程:
  • 读cache,若命中则返回
  • 若未命中,则读db,将读出来的数据经过处理后写入缓存

注意:本文分析的前提是不考虑因请求db或cache失败而引起的数据不一致

案例一:数据统计,将文件按照一定的逻辑统计汇总后,入库到本地db中。

什么场景下会出现数据不一致

在高并发的互联网应用中,读和写会同时存在,在缓存淘汰策略设置得不当的情况,就有可能发生数据不一致的情况,看看如下场景

澳门新濠3559 1

1.png

若执行的顺序恰好为①清cache ②读cache miss ③读db ④写db ⑤写cache,在程序没有异常的情况下,就会出现缓存与数据库不一致的现象

最开始的代码流程框图:

若先写db,再清cache会不会出现数据不一致?

这种场景下,仍然会出现数据不一致,只是出现的概率会比先清cache后写db要小些,请看如下场景

假如读、写请求正好发生在同一时刻且请求db和cache时程序都没有发生异常

澳门新濠3559 2

写请求
  • 更新db(耗时4ms)
  • 清除cache(耗时2ms)

大概流程:

读请求
  • 读cache miss(耗时1ms)
  • 读db(耗时2ms)
  • 处理从db读出来的数据(耗时10ms)
  • 写cache(耗时2ms)

在这种场景下,写请求在更新完db后,此时读请求读到的数据就变成脏数据了,由于读请求处理数据的时间较长,导致写cache发生在写请求清除cache之后,这样就导致cache里存的是脏数据,进而引发缓存与数据库不一致的问题

在使用了分布式缓存的应用中,当缓存的数据粒度比较粗时,往往需要针对从数据库里读出来的数据做进一步的处理,若数据处理的时间较长,在高并发的场景下,就很有可能会出现数据不一致的现象。

1、循环读文件,按照一定格式将文本进行拆分计算

优化方案

采取清除两次cache的方案;第一次发生在操作完数据库后,同步清除,第二次延迟清除,延迟清除可以使用支持延迟投递的消息队列来实现。

澳门新濠3559 3

2.png

2、根据指定的key来统一汇总数据

3、入库本地DB,入库时,会先查找db中是否存在这条记录,然后再判断是否插入db中;相当于这里会有两次db操作,一次查询,一次写入。

一开始业务量小,db数据量少,整个流程耗时较短,在秒级能够完成,随着业务发展,所需时间也有秒级变成了分钟级,十分钟级别等。

测试1:

通过对其中的一个业务某天的数据进行测试,它的耗时主要分部为,读文件(文件大小1G左右)耗时2秒,逻辑计算及汇总58s,数据入库32s;总耗时大概在1分半钟。

1.1 方案1

流水线形式的多线程

澳门新濠3559 4

线程1负责读取数据,然后通过python自带的Qeueue,Q1传递数据给线程2;

线程2负责逻辑计算,然后通过Q2传递数据给线程3;

线程3负责汇总数据,然后通过Q3传递数据给线程4;

线程4则入库数据;

这个方案在实现之后立马就被废弃了,它的效率比单进程的效率低很多,通过查看系统调用之后,发现是因为多个线程一直在竞争锁,以及线程切换导致其执行效率还不如单线程。

1.2 方案二

数据分片+分段多线程

在不同的时机采用多线程来处理,同时尽量避免多线程对同一资源进行竞争,以减少锁的切换带来的消耗。因此这里在逻辑计算和数据入库阶段分别采用数据分组,多线程执行的方式来进行处理。

分段一、逻辑计算和汇总,将内存读到内存中后,按照线程数量,将数据切分成多块,让第i个线程thread[i]处理第i份数据data[i],最后再将计算得到的4份数据汇总,按照相同的key进行汇总;得到sum_data

分段二、将sum_data按照线程数量,切分成多份,同样让thread[i]处理sum_data[i]的数据,让他们各自进行数据的查询以及写入操作。

澳门新濠3559 5

测试2:

对同一个文件进行测试,读文件耗时2秒,逻辑计算及汇总62s,数据入库10s;总耗时大概在70多秒,相比最开始的单线程,时间大概下降了20多s;但可以看出,逻辑计算的时间相比单线程确增加了不少,而入库操作的时间减少了20多s;这里就引发一个问题,逻辑计算跟入库的差异在哪里?为何前面的多线程性能下降,而后面性能确大幅度提高。

这里的原因究竟为何?

案例二:案例2的整体流程为,将几份不同的数据源从db中取出来,按天取出,经过一定的整合后,汇总插入到一个目标db中。

一开始的代码流程:

澳门新濠3559 6

同样最初的时候,需要整合的数据量较少,db中的数据量也较少。随着业务增长,每天需要处理的数据量也逐渐增加,并且db中的数据量也越来越大,处理的时间也从开始的秒级别也逐渐增加到分钟级别,每次都是统一处理一个月的数据,整体耗时需要几个小时。

测试3:

对某天的数据进行测试,结果为:取数据+整合 耗时30s;插入数据耗时约8分钟

更改成以下模型:

入库操作同样需要先根据key查找当前db中是否存在该条数据,不存在则写入

澳门新濠3559 7

测试4:

取数据+整合 耗时30s;插入数据耗时约2分钟

更改之后性能大幅度提升,由原先的8分半钟,缩减为不到2分半钟左右,缩减的时间主要体现在入库阶段;

从以上两个例子可以看到,当涉及I/0操作时,python的多线程能发挥较好的性能;而当涉及到CPU密集型逻辑运算时,python的多线程性能不升反降。这里都是由于python的GIL在发挥的作用。

2、了解python的GIL

这里我们使用的解释器为官方实现的CPython,它是由C语言实现的python解释器。同时还存在由Java实现的Jython解释器,由.NET实现的IronPython等解释器。这里我们主要是依据CPython来讲解GIL锁。

GIL,全称Global Interpreter Lock, 是一个全局解释器锁,当解释器需要执行python代码时,都必须要获得这把锁,然后才能执行。当解释器在遇到到I/O操作时会释放这把锁。但如果当程序为CPU密集型时,解释器会主动的每间隔100次操作就释放这把GIL锁,这样别的线程有机会执行,具体的间隔次数是由sys.setcheckinterval( number )来设定这个值,通过sys.getcheckinterval()返回这个值,默认为100。所以,尽管Python的线程库直接封装操作系统的原生线程,但Python进程,在同一时间只会有一个获得了GIL的线程在跑,其它的线程都处于等待状态等着GIL的释放。就这样对于CPU密集型操作来说,多线程不但不会提升性能,还会因为线程切换,锁竞争等导致性能的下降。

在我们上面的两个例子中,当涉及到数据的查询与插入时,都需要进行I/O交互,并且会等待数据库服务器返回,这个时候,线程会主动释放锁,其他线程能够合理利用这个时间,来做同样的事情。

知道了GIL之后,我们才能更加合理的使用python的多线程,并不是所有场景都适用于多线程。

同样,Python的多线程也并不是大家所说的鸡肋,在适合的场景用上了,还是能够起到惊艳的作用

-END-

内容转自公众号:腾讯课堂coding学院

编辑:编程 本文来源:db.php配置信息里的localhost,最终导致了业务异常

关键词: