『壹』 數據條數太多,插入到資料庫有延遲,怎麼解決
1.我們往資料庫中導入的數據通常是有固定的模板的,也就是有列頭,但是可能excel中的一條數據分布存儲在不同的數據表中,那麼我們怎麼來導入了,我們可以在類文件中直接拼接sql語句插入,這樣做的話我認為比較麻煩。我的做法是:在數據中建一個中間表暫且叫做Temp表跟excel中列一一對應,其中表中多加state列用來標識數據驗證失敗還是成功的(0代表數據沒有問題,-1代表有問題)、failReason記錄導入失敗原因,然後再添加一個配置文件來做excel列和數據表的映射。 2.要導入的數據通常要做驗證,那些不符合導入規則的數據時不允許或者不能導入的。我把數據分兩步來驗證,一部分在代碼段驗證,一部分在資料庫驗證。至於怎麼分那就自己去根據情況分析了。我是把諸如字元長度限制,正則表達式規則限制等放 在代碼段驗證,把諸如資料庫中字典值是否存在等要訪問資料庫的驗證放在數據中驗證,這樣的話就可以減少訪問資料庫的次數。把再客戶端驗證過的數據,不管是通過的不同過的都插入到temp表中,只是state值不同。 3.然後怎麼把插入temp中數據分別插入到不同的數據表中了,大家一定想到了觸發器,沒有錯,我用的就是after觸發器,在我把excel中的數據插入到temp表中的時候,那麼就會觸發after觸發器,在觸發器中對插入的數據進行處理,如果插入的數據state值為-1,代表在代碼端的驗證就沒有通過,那麼就不需要進行下一步處理了,如果state值為0,那麼在觸發器中接著處理,比如檢測字典值在字典表中存不存在等,如果不滿足要求就把temp表中的當前插入的記錄state值改成-1,把校驗失敗原因更新到failReason欄位中,不再處理。如果一切校驗都沒有問題的話,那麼就編寫插入語句,把數據插入到不同的表中去。 4.數據導入完成了,那麼那些有問題數據怎麼辦了?把它查詢出來生成一個按原模板後加一列「失敗原因」導成excel文件,其實就是state值為-1的那些記錄,然後返回給用戶查看。 通過以上步驟之後那麼整個導入功能就完成了,以上只是一種思路,望大家完善。 本站技術原創欄目文章均為中睿原創或編譯,
『貳』 Redis常見延遲問題排查手冊!附33條優化建議
Redis作為內存資料庫,擁有非常高的性能,單個實例的QPS能夠達到10W左右。但我們在使用Redis時,經常時不時會出現訪問延遲很大的情況,如果你不知道Redis的內部實現原理,在排查問題時就會一頭霧水。
很多時候,Redis出現訪問延遲變大,都與我們的使用不當或運維不合理導致的。
下面我們就來分析一下Redis在使用過程中,經常會遇到的延遲問題以及如何定位和分析。
如果在使用Redis時,發現訪問延遲突然增大,如何進行排查?
首先,第一步,建議你去查看一下Redis的慢日誌。Redis提供了慢日誌命令的統計功能,我們通過以下設置,就可以查看有哪些命令在執行時延遲比較大。
首先設置Redis的慢日誌閾值,只有超過閾值的命令才會被記錄,這里的單位是微妙,例如設置慢日誌的閾值為5毫秒,同時設置只保留最近1000條慢日誌記錄:
# 命令執行超過5毫秒記錄慢日誌
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近1000條慢日誌
CONFIG SET slowlog-max-len 1000
設置完成之後,所有執行的命令如果延遲大於5毫秒,都會被Redis記錄下來,我們執行SLOWLOG get 5查詢最近5條慢日誌:
127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693 # 慢日誌ID
2) (integer) 1593763337 # 執行時間
3) (integer) 5299 # 執行耗時(微妙)
4) 1) 'LRANGE' # 具體執行的命令和參數
2) 'user_list_2000'
3) Ɔ'
4) '-1'
2) 1) (integer) 32692
2) (integer) 1593763337
3) (integer) 5044
4) 1) 'GET'
2) 'book_price_1000'
...
通過查看慢日誌記錄,我們就可以知道在什麼時間執行哪些命令比較耗時, 如果你的業務經常使用O(n)以上復雜度的命令, 例如sort、sunion、zunionstore,或者在執行O(n)命令時操作的數據量比較大,這些情況下Redis處理數據時就會很耗時。
如果你的服務請求量並不大,但Redis實例的CPU使用率很高,很有可能是使用了復雜度高的命令導致的。
解決方案就是,不使用這些復雜度較高的命令,並且一次不要獲取太多的數據,每次盡量操作少量的數據,讓Redis可以及時處理返回。
如果查詢慢日誌發現,並不是復雜度較高的命令導致的,例如都是SET、DELETE操作出現在慢日誌記錄中,那麼你就要懷疑是否存在Redis寫入了大key的情況。
Redis在寫入數據時,需要為新的數據分配內存,當從Redis中刪除數據時,它會釋放對應的內存空間。
如果一個key寫入的數據非常大,Redis 在分配內存時也會比較耗時。 同樣的,當刪除這個key的數據時, 釋放內存也會耗時比較久。
你需要檢查你的業務代碼,是否存在寫入大key的情況,需要評估寫入數據量的大小,業務層應該避免一個key存入過大的數據量。
那麼有沒有什麼辦法可以掃描現在Redis中是否存在大key的數據嗎?
Redis也提供了掃描大key的方法:
redis-cli -h $host -p $port --bigkeys -i 0.01
使用上面的命令就可以掃描出整個實例key大小的分布情況,它是以類型維度來展示的。
需要注意的是當我們在線上實例進行大key掃描時,Redis的QPS會突增,為了降低掃描過程中對Redis的影響,我們需要控制掃描的頻率,使用-i參數控制即可,它表示掃描過程中每次掃描的時間間隔,單位是秒。
使用這個命令的原理,其實就是Redis在內部執行scan命令,遍歷所有key,然後針對不同類型的key執行strlen、llen、hlen、scard、zcard來獲取字元串的長度以及容器類型(list/dict/set/zset)的元素個數。
而對於容器類型的key,只能掃描出元素最多的key,但元素最多的key不一定佔用內存最多,這一點需要我們注意下。不過使用這個命令一般我們是可以對整個實例中key的分布情況有比較清晰的了解。
針對大key的問題,Redis官方在4.0版本推出了lazy-free的機制,用於非同步釋放大key的內存,降低對Redis性能的影響。即使這樣,我們也不建議使用大key,大key在集群的遷移過程中,也會影響到遷移的性能,這個後面在介紹集群相關的文章時,會再詳細介紹到。
有時你會發現,平時在使用Redis時沒有延時比較大的情況,但在某個時間點突然出現一波延時,而且 報慢的時間點很有規律,例如某個整點,或者間隔多久就會發生一次。
如果出現這種情況,就需要考慮是否存在大量key集中過期的情況。
如果有大量的key在某個固定時間點集中過期,在這個時間點訪問Redis時,就有可能導致延遲增加。
Redis的過期策略採用主動過期+懶惰過期兩種策略:
注意, Redis的主動過期的定時任務,也是在Redis主線程中執行的 ,也就是說如果在執行主動過期的過程中,出現了需要大量刪除過期key的情況,那麼在業務訪問時,必須等這個過期任務執行結束,才可以處理業務請求。此時就會出現,業務訪問延時增大的問題,最大延遲為25毫秒。
而且這個訪問延遲的情況, 不會記錄在慢日誌里。 慢日誌中 只記錄真正執行某個命令的耗時 ,Redis主動過期策略執行在操作命令之前,如果操作命令耗時達不到慢日誌閾值,它是不會計算在慢日誌統計中的,但我們的業務卻感到了延遲增大。
此時你需要檢查你的業務,是否真的存在集中過期的代碼,一般集中過期使用的命令是expireat或pexpireat命令,在代碼中搜索這個關鍵字就可以了。
如果你的業務確實需要集中過期掉某些key,又不想導致Redis發生抖動,有什麼優化方案?
解決方案是, 在集中過期時增加一個隨機時間,把這些需要過期的key的時間打散即可。
偽代碼可以這么寫:
# 在過期時間點之後的5分鍾內隨機過期掉
redis.expireat(key, expire_time + random(300))
這樣Redis在處理過期時,不會因為集中刪除key導致壓力過大,阻塞主線程。
另外,除了業務使用需要注意此問題之外,還可以通過運維手段來及時發現這種情況。
我們需要對這個指標監控,當在 很短時間內這個指標出現突增 時,需要及時報警出來,然後與業務報慢的時間點對比分析,確認時間是否一致,如果一致,則可以認為確實是因為這個原因導致的延遲增大。
有時我們把Redis當做純緩存使用,就會給實例設置一個內存上限maxmemory,然後開啟LRU淘汰策略。
當實例的內存達到了maxmemory後,你會發現之後的每次寫入新的數據,有可能變慢了。
導致變慢的原因是,當Redis內存達到maxmemory後,每次寫入新的數據之前,必須先踢出一部分數據,讓內存維持在maxmemory之下。
這個踢出舊數據的邏輯也是需要消耗時間的,而具體耗時的長短,要取決於配置的淘汰策略:
具體使用哪種策略,需要根據業務場景來決定。
我們最常使用的一般是allkeys-lru或volatile-lru策略,它們的處理邏輯是,每次從實例中隨機取出一批key(可配置),然後淘汰一個最少訪問的key,之後把剩下的key暫存到一個池子中,繼續隨機取出一批key,並與之前池子中的key比較,再淘汰一個最少訪問的key。以此循環,直到內存降到maxmemory之下。
如果使用的是allkeys-random或volatile-random策略,那麼就會快很多,因為是隨機淘汰,那麼就少了比較key訪問頻率時間的消耗了,隨機拿出一批key後直接淘汰即可,因此這個策略要比上面的LRU策略執行快一些。
但以上這些邏輯都是在訪問Redis時,真正命令執行之前執行的,也就是它會影響我們訪問Redis時執行的命令。
另外,如果此時Redis實例中有存儲大key,那麼在淘汰大key釋放內存時,這個耗時會更加久,延遲更大,這需要我們格外注意。
如果你的業務訪問量非常大,並且必須設置maxmemory限制實例的內存上限,同時面臨淘汰key導致延遲增大的的情況,要想緩解這種情況,除了上面說的避免存儲大key、使用隨機淘汰策略之外,也可以考慮拆分實例的方法來緩解,拆分實例可以把一個實例淘汰key的壓力分攤到多個實例上,可以在一定程度降低延遲。
如果你的Redis開啟了自動生成RDB和AOF重寫功能,那麼有可能在後台生成RDB和AOF重寫時導致Redis的訪問延遲增大,而等這些任務執行完畢後,延遲情況消失。
遇到這種情況,一般就是執行生成RDB和AOF重寫任務導致的。
生成RDB和AOF都需要父進程fork出一個子進程進行數據的持久化,在fork執行過程中,父進程需要拷貝內存頁表給子進程,如果整個實例內存佔用很大,那麼需要拷貝的內存頁表會比較耗時,此過程會消耗大量的CPU資源,在完成fork之前,整個實例會被阻塞住,無法處理任何請求,如果此時CPU資源緊張,那麼fork的時間會更長,甚至達到秒級。這會嚴重影響Redis的性能。
具體原理也可以參考我之前寫的文章:Redis持久化是如何做的?RDB和AOF對比分析。
我們可以執行info命令,查看最後一次fork執行的耗時latest_fork_usec,單位微妙。這個時間就是整個實例阻塞無法處理請求的時間。
除了因為備份的原因生成RDB之外,在 主從節點第一次建立數據同步時 ,主節點也會生成RDB文件給從節點進行一次全量同步,這時也會對Redis產生性能影響。
要想避免這種情況,我們需要規劃好數據備份的周期,建議 在從節點上執行備份,而且最好放在低峰期執行。 如果對於丟失數據不敏感的業務,那麼不建議開啟AOF和AOF重寫功能。
另外,fork的耗時也與系統有關,如果把Redis部署在虛擬機上,那麼這個時間也會增大。所以使用Redis時建議部署在物理機上,降低fork的影響。
很多時候,我們在部署服務時,為了提高性能,降低程序在使用多個CPU時上下文切換的性能損耗,一般會採用進程綁定CPU的操作。
但在使用Redis時,我們不建議這么干,原因如下。
綁定CPU的Redis,在進行數據持久化時,fork出的子進程,子進程會繼承父進程的CPU使用偏好,而此時子進程會消耗大量的CPU資源進行數據持久化,子進程會與主進程發生CPU爭搶,這也會導致主進程的CPU資源不足訪問延遲增大。
所以在部署Redis進程時,如果需要開啟RDB和AOF重寫機制,一定不能進行CPU綁定操作!
上面提到了,當執行AOF文件重寫時會因為fork執行耗時導致Redis延遲增大,除了這個之外,如果開啟AOF機制,設置的策略不合理,也會導致性能問題。
開啟AOF後,Redis會把寫入的命令實時寫入到文件中,但寫入文件的過程是先寫入內存,等內存中的數據超過一定閾值或達到一定時間後,內存中的內容才會被真正寫入到磁碟中。
AOF為了保證文件寫入磁碟的安全性,提供了3種刷盤機制:
當使用第一種機制appendfsync always時,Redis每處理一次寫命令,都會把這個命令寫入磁碟,而且 這個操作是在主線程中執行的。
內存中的的數據寫入磁碟,這個會加重磁碟的IO負擔,操作磁碟成本要比操作內存的代價大得多。如果寫入量很大,那麼每次更新都會寫入磁碟,此時機器的磁碟IO就會非常高,拖慢Redis的性能,因此我們不建議使用這種機制。
與第一種機制對比,appendfsync everysec會每隔1秒刷盤,而appendfsync no取決於操作系統的刷盤時間,安全性不高。因此我們推薦使用appendfsync everysec這種方式,在最壞的情況下,只會丟失1秒的數據,但它能保持較好的訪問性能。
當然,對於有些業務場景,對丟失數據並不敏感,也可以不開啟AOF。
如果你發現Redis突然變得非常慢, 每次訪問的耗時都達到了幾百毫秒甚至秒級 ,那此時就檢查Redis是否使用到了Swap,這種情況下Redis基本上已經無法提供高性能的服務。
我們知道,操作系統提供了Swap機制,目的是為了當內存不足時,可以把一部分內存中的數據換到磁碟上,以達到對內存使用的緩沖。
但當內存中的數據被換到磁碟上後,訪問這些數據就需要從磁碟中讀取,這個速度要比內存慢太多!
尤其是針對Redis這種高性能的內存資料庫來說,如果Redis中的內存被換到磁碟上,對於Redis這種性能極其敏感的資料庫,這個操作時間是無法接受的。
我們需要檢查機器的內存使用情況,確認是否確實是因為內存不足導致使用到了Swap。
如果確實使用到了Swap,要及時整理內存空間,釋放出足夠的內存供Redis使用,然後釋放Redis的Swap,讓Redis重新使用內存。
釋放Redis的Swap過程通常要重啟實例,為了避免重啟實例對業務的影響,一般先進行主從切換,然後釋放舊主節點的Swap,重新啟動服務,待數據同步完成後,再切換回主節點即可。
可見,當Redis使用到Swap後,此時的Redis的高性能基本被廢掉,所以我們需要提前預防這種情況。
我們需要對Redis機器的內存和Swap使用情況進行監控,在內存不足和使用到Swap時及時報警出來,及時進行相應的處理。
如果以上產生性能問題的場景,你都規避掉了,而且Redis也穩定運行了很長時間,但在某個時間點之後開始,訪問Redis開始變慢了,而且一直持續到現在,這種情況是什麼原因導致的?
之前我們就遇到這種問題, 特點就是從某個時間點之後就開始變慢,並且一直持續。 這時你需要檢查一下機器的網卡流量,是否存在網卡流量被跑滿的情況。
網卡負載過高,在網路層和TCP層就會出現數據發送延遲、數據丟包等情況。Redis的高性能除了內存之外,就在於網路IO,請求量突增會導致網卡負載變高。
如果出現這種情況,你需要排查這個機器上的哪個Redis實例的流量過大占滿了網路帶寬,然後確認流量突增是否屬於業務正常情況,如果屬於那就需要及時擴容或遷移實例,避免這個機器的其他實例受到影響。
運維層面,我們需要對機器的各項指標增加監控,包括網路流量,在達到閾值時提前報警,及時與業務確認並擴容。
以上我們總結了Redis中常見的可能導致延遲增大甚至阻塞的場景,這其中既涉及到了業務的使用問題,也涉及到Redis的運維問題。
可見,要想保證Redis高性能的運行,其中涉及到CPU、內存、網路,甚至磁碟的方方面面,其中還包括操作系統的相關特性的使用。
作為開發人員,我們需要了解Redis的運行機制,例如各個命令的執行時間復雜度、數據過期策略、數據淘汰策略等,使用合理的命令,並結合業務場景進行優化。
作為DBA運維人員,需要了解數據持久化、操作系統fork原理、Swap機制等,並對Redis的容量進行合理規劃,預留足夠的機器資源,對機器做好完善的監控,才能保證Redis的穩定運行。
在上文中,主要講解了 Redis 常見的導致變慢的場景以及問題定位和分析,主要是由業務使用不合理和運維不當導致的。
『叄』 mysql響應時間多久正常
mysql響應時間5秒正常。
MySQL是一個關系型資料庫管理系統,由瑞典MySQL AB公司開發,屬於Oracle旗下產品。MySQL 是最流行的關系型資料庫管理系統之一,在WEB應用方面,MySQL是最好的RDBMS(Relational Database Management System,關系資料庫管理系統) 應用軟體之一。
MySQL是一種關系型資料庫管理系統,關系資料庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度並提高了靈活性。
MySQL所使用的 SQL 語言是用於訪問資料庫的最常用標准化語言。MySQL 軟體採用了雙授權政策,分為社區版和商業版,由於其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點,一般中小型網站的開發都選擇 MySQL 作為網站資料庫。