1. 程式人生 > >OLTP系統REDIS資料庫效能測試紀錄

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望塵莫及。侷限性也還是有的,除了前面的坑,還有記錄太長之類的,也是影響效能的。