OLTP系统REDIS数据库性能测试纪录

为什么想到用REDIS:
由于客户追求较大大的并发交易极限,想尽可能提高数据库承载足够的压力。所以选择尝试测试一下REDIS的效果。

测试构思:
1.对于OLTP系统,使用REDIS数据库来缓存交易数据库(ORACLE)中长期不修改,或者修改频率较低数据(参数)。
优化目标:
1.利用REDIS的轻量级,更快的数据返回速度,降低交易响应时间,提高系统吞吐效率。
2.利用REDIS负载,减轻主数据库(ORACLE)的负载压力。

怎么实现:
系统中大量的数据库访问,都是通过标准数据访问封装来进行访问。优化的部分,也正是封装中,通过KEY值查询记录的功能,这是符合REDIS作为KEY值数据库的特性的。于是,我们在标准封装中设置一个优化清单。凡是,清单中的数据库表,封装里的程序都去REDIS中读取,若REDIS中没有读到,则去ORACLE中读取,并将该记录写入到REDIS中。当标准封装中,发现清单中的表,有修改变化的动作,随即将REDIS中改数据记录删除。
这么做最大的好处,几乎所有外部调用封装的程序,都不需要改。

坑和思路:
在这个实现策略下,我们开启了压力测试的过程。
然而,第一次试跑就以失败告终,REDIS以一主一从的模式部署,我们交易平均响应时间慢了10-20MS。于是,我们毫不犹豫的关掉了从节点REDIS。因为,以我们的优化策略,即使REDIS发生故障无法访问的时候,我们的交易会立刻回到ORACLE上来访问数据。所以从节点对我们来说,并没有那么重要。于是我们果断关闭了从节点。
之后,为了排除DB的BUFFER Pool和OS的缓存对测试结果的影响,我们反复的跑了几轮测试。基本上,在1000TPS的交易量下,发现整体交易响应时间没有任何降低的迹象(ORACLE远远没有到瓶颈),各种交易平均响应时间整体提高了2毫秒左右。同时发现了一处异常现象,那就是REDIS服务器的网络开销巨大,远远超过ORACLE服务器网络开销的减少,差不多10倍。
讲道理的话,系统原本和ORACLE交互的数据,现在和REDIS交互,那么这两者的网络增减之和应该近似于0才对。那么出现这个异常,果断推测,与REDIS交互的数据存储结构发生了变化。并且,这种结构占用的存储空间,远远大于了ORACLE的数据存储空间。
对于交易响应时间就存在两种可能,一种是与REDIS交互本身的程序开销(数据格式变化过程)。另一种是这多出来的数据,造成的网络开销。那么种种证据都指向了一件事情,序列化。
JAVA程序与数据库的交互,JAVA眼里只有对象,而数据库眼里只有一条记录。那么JAVA和REDIS之间,我们摆着两条路,要么把对象里面的数据全部TOSTRING,要么把对象序列化。按照比较主流的方案,我们第一次测试选择的是后者,默认的JDK序列化。因为起初,我们没有把序列化这件事情太当回事。测试结果不理想的情况下,依然是有两种选择,一种是丢掉序列化,回去TOSTING这条路。另一条就是试图优化序列化。在查看了各大论坛之后,我们决定把序列化这条路,走到黑。因为网上有各种论述,JDK序列化效率差,以及其他序列化方案的对比测试。
之后的测试,Json,kryo的序列化方案,被相继拿出来测试。好的方面是,我们解决了空间变大的问题。在三种序列化方案对比之后,我们确定了性能最好的kryo序列化。Oracle和REDIS服务器的网络增减之和近似于0了,然而响应时间几乎没有变化。也可能一笔交易少了1MS吧,反正几乎无法再系统误差中,把这个差异找出来。
这时候,观点“数据变大,产生的巨大的网络开销导致交易变慢,使得REDIS性能优势体现不出来”的推测,已经被证伪了。当网络传输量和ORACLE几乎相同的情况下,REDIS并没有变快。调取了REDIS SLOWLOG看了一番,语句都还很快,5,6微秒的几乎是大多数。
序列化的路已经到头了,还剩下TOSTRING。于是我们弄走了序列化,直接把记录转成STRING往REDIS里面丢。终于,这一次我们看到了交易响应时间,提高了2MS左右,有少量的性能提升。
再看看数据库的压力减轻情况。考虑到是原型测试,我们大约只将十分之一的SQL放到了REDIS服务器里面。在1000TPS的交易下,ORACLE数据库服务器的CPU使用率大约有百分之一左右的降低。算是在减轻数据库服务器的方面,有一些作用的,但是减少的程度比我们预期中的要小一点。可以推断作用的程度大小,还在于缓存内容范围和比例。

反思优化的场景:

  1. 如果在ORACLE中本身就是KEY值访问,只要在有B树索引的前提,响应时间本就非常快,要想靠REDIS对这种场景,提高较大的响应速度,几乎不可能。对于复杂的SQL语句,较多的数据IO的场景,可能用REDIS缓存会有更佳的优化效果。但是,这样的改造就变得很难有较好的通用性,程序修改也对应会比较复杂。
  2. 序列化的使用要慎重,对于最求高响应的时候,序列化和反序列化,确实是一个耗时间的过程。不过公平来讲,对于一个几百毫秒的交易,不到10毫秒的序列化和反序列化过程,其实并不算什么很大的开销。如果本身ORACLE中的SQL语句并不是特别快,比如50MS吧,那么即使序列化和反序列化的过程用掉10MS,那对于交易性能至少也还有30MS的显著提升(REDIS的反应非常快,通常就是几微秒的速度)。而我们系统中的KEY值访问型SQL,在ORACLE中,本身就非常的快,交易的整体SQL次数多(构建访问),但是单SQL速度快。以这样的测试来把锅丢在序列化头上,也有点说不过去。但是,REDIS并非我们之前想的那样,可以适应于我们这样特点的系统,它还是有很多的局限性。
  3. 关于缓解ORACLE服务器压力方面,虽然是有一些效果。但是,于效果一起存在的是一些风险。举个例子,如果客户要1000TPS的峰值交易量,ORACLE如果能达到,那REDIS就变得可有可无。但是如果,ORACLE只能到800,用了REDIS可以到1000的话。这就有一个问题,当REDIS出现故障的时候,可能直接导致ORACLE数据库崩盘,要使用的话,就必须配合其他流控之类的手段,已确保异常情况下,系统的稳定性。

尾声:
REDIS体量小,代码简洁,数据进出速度也是相当相当快的,几微秒的速度,各种R-DBMS望尘莫及。局限性也还是有的,除了前面的坑,还有记录太长之类的,也是影响性能的。

猜你喜欢

转载自blog.csdn.net/weixin_43549321/article/details/83547855
今日推荐