當前位置:首頁 » 操作系統 » thp演算法

thp演算法

發布時間: 2022-09-03 23:14:02

⑴ Redis持久化

Redis支持RDB和AOF兩種持久化機制,持久化功能有效地避免因進程退出造成的數據丟失問題,當下次重啟時利用之前持久化的文件即可實現數據恢復。理解掌握持久化機制對於Redis運維非常重要。本章內容如下:

·首先介紹RDB、AOF的配置和運行流程,以及控制持久化的相關命令,如bgsave和bgrewriteaof。

·其次對常見持久化問題進行分析定位和優化。

·最後結合Redis常見 的單機多實例部署場景進行優化。

5.1RDB

RDB持久化是把當前進程數據生成快照保存到硬碟的過程,觸發RDB持久化過程分為手動觸發和自動觸發。

5.1.1觸發機制

手動觸發分別對應save和bgsave命令:

·save命令:阻塞當前Redis伺服器,直到RDB過程完成為止,對於內存比較大的實例會造成長時間阻塞,線上環境不建議使用。運行save命令對應

的Redis日誌如下:

* DB saved on disk

·bgsave命令:Redis進程執行fork操作創建子進程,RDB持久化過程由子進程負責,完成後自動結束。阻塞只發生在fork階段,一般時間很短。運行bgsave命令對應的Redis日誌如下:

* Background saving started by pid 3151

* DB saved on disk

* RDB: 0 MB of memory used by -on-write

* Background saving terminated with success

顯然bgsave命令是針對save阻塞問題做的優化。因此Redis內部所有的涉及RDB的操作都採用bgsave的方式,而save命令已經廢棄。

除了執行命令手動觸發之外,Redis內部還存在自動觸發RDB的持久化機制,例如以下場景:

1)使用save相關配置,如「save m n」。表示m秒內數據集存在n次修改時,自動觸發bgsave。

2)如果從節點執行全量復制操作,主節點自動執行bgsave生成RDB文件並發送給從節點,更多細節見6.3節介紹的復制原理。

3)執行debug reload命令重新載入Redis時,也會自動觸發save操作。

4)默認情況下執行shutdown命令時,如果沒有開啟AOF持久化功能則自動執行bgsave。

5.1.2流程說明

bgsave是主流的觸發RDB持久化方式,下面根據圖5-1了解它的運作流程。

1)執行bgsave命令,Redis父進程判斷當前是否存在正在執行的子進程,如RDB/AOF子進程,如果存在bgsave命令直接返回。

2)父進程執行fork操作創建子進程,fork操作過程中父進程會阻塞,通過info stats命令查看latest_fork_usec選項,可以獲取最近一個fork操作的耗時,單位為微秒。

3)父進程fork完成後,bgsave命令返回「Background saving started」信息並不再阻塞父進程,可以繼續響應其他命令。

4)子進程創建RDB文件,根據父進程內存生成臨時快照文件,完成後對原有文件進行原子替換。執行lastsave命令可以獲取最後一次生成RDB的時間,對應info統計的rdb_last_save_time選項。

5)進程發送信號給父進程表示完成,父進程更新統計信息,具體見info Persistence下的rdb_*相關選項。

5.1.3RDB文件的處理

保存:RDB文件保存在dir配置指定的目錄下,文件名通過dbfilename配置指定。可以通過執行config set dir{newDir}和config setdbfilename{newFileName}運行期動態執行,當下次運行時RDB文件會保存到新目錄。

運維提示

當遇到壞盤或磁碟寫滿等情況時,可以通過config set dir{newDir}在線修改文件路徑到可用的磁碟路徑,之後執行bgsave進行磁碟切換,同樣適用於AOF持久化文件。

壓縮:Redis默認採用LZF演算法對生成的RDB文件做壓縮處理,壓縮後的文件遠遠小於內存大小,默認開啟,可以通過參數config set rdbcompression{yes|no}動態修改。

運維提示

雖然壓縮RDB會消耗CPU,但可大幅降低文件的體積,方便保存到硬碟或通過網路發送給從節點,因此線上建議開啟。

校驗:如果Redis載入損壞的RDB文件時拒絕啟動,並列印如下日誌:

# Short read or OOM loading DB. Unrecoverable error, aborting now.

這時可以使用Redis提供的redis-check-mp工具檢測RDB文件並獲取對應的錯誤報告。

5.1.4RDB的優缺點

RDB的優點:

·RDB是一個緊湊壓縮的二進制文件,代表Redis在某個時間點上的數據快照。非常適用於備份,全量復制等場景。比如每6小時執行bgsave備份,並把RDB文件拷貝到遠程機器或者文件系統中(如hdfs),用於災難恢復。

·Redis載入RDB恢復數據遠遠快於AOF的方式。

RDB的缺點:

·RDB方式數據沒辦法做到實時持久化/秒級持久化。因為bgsave每次運行都要執行fork操作創建子進程,屬於重量級操作,頻繁執行成本過高。

·RDB文件使用特定二進制格式保存,Redis版本演進過程中有多個格式的RDB版本,存在老版本Redis服務無法兼容新版RDB格式的問題。針對RDB不適合實時持久化的問題,Redis提供了AOF持久化方式來解決。

5.2AOF

AOF(append only file)持久化:以獨立日誌的方式記錄每次寫命令,重啟時再重新執行AOF文件中的命令達到恢復數據的目的。AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式。理解掌握好AOF持久化機制對我們兼顧數據安全性和性能非常有幫助。

5.2.1使用AOF

開啟AOF功能需要設置配置:appendonly yes,默認不開啟。AOF文件名通過appendfilename配置設置,默認文件名是appendonly.aof。保存路徑同RDB持久化方式一致,通過dir配置指定。AOF的工作流程操作:命令寫入(append)、文件同步(sync)、文件重寫(rewrite)、重啟載入(load),如圖5-2所示。

1)所有的寫入命令會追加到aof_buf(緩沖區)中。

2)AOF緩沖區根據對應的策略向硬碟做同步操作。

3)隨著AOF文件越來越大,需要定期對AOF文件進行重寫,達到壓縮的目的。

4)當Redis伺服器重啟時,可以載入AOF文件進行數據恢復。了解AOF工作流程之後,下面針對每個步驟做詳細介紹。

5.2.2命令寫入

AOF命令寫入的內容直接是文本協議格式。例如set hello world這條命令,在AOF緩沖區會追加如下文本:*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

Redis協議格式具體說明見4.1客戶端協議小節,這里不再贅述,下面介

紹關於AOF的兩個疑惑:

1)AOF為什麼直接採用文本協議格式?可能的理由如下:

·文本協議具有很好的兼容性。

·開啟AOF後,所有寫入命令都包含追加操作,直接採用協議格式,避免了二次處理開銷。

·文本協議具有可讀性,方便直接修改和處理。

2)AOF為什麼把命令追加到aof_buf中?Redis使用單線程響應命令,如果每次寫AOF文件命令都直接追加到硬碟,那麼性能完全取決於當前硬碟負載。先寫入緩沖區aof_buf中,還有另一個好處Redis可以提供多種緩沖區同步硬碟的策略,在性能和安全性方面做出平衡。

5.2.3文件同步

Redis提供了多種AOF緩沖區同步文件策略,由參數appendfsync控制,不同值的含義如表5-1所示。

表5-1AOF緩沖區同步文件策略

系統調用write和fsync說明:

·write操作會觸發延遲寫(delayed write)機制。linux在內核提供頁緩沖區用來提高硬碟IO性能。write操作在寫入系統緩沖區後直接返回。同步硬碟操作依賴於系統調度機制,例如:緩沖區頁空間寫滿或達到特定時間周期。同步文件之前,如果此時系統故障宕機,緩沖區內數據將丟失。

·fsync針對單個文件操作(比如AOF文件),做強制硬碟同步,fsync將阻塞直到寫入硬碟完成後返回,保證了數據持久化。除了write、fsync,Linux還提供了sync、fdatasync操作,具體API說明參

見:http://linux.die.net/man/2/write,http://linux.die.net/man/2/fsync,http://linux.die.net/man/2/sync

·配置為always時,每次寫入都要同步AOF文件,在一般的SATA硬碟上,Redis只能支持大約幾百TPS寫入,顯然跟Redis高性能特性背道而馳,不建議配置。

·配置為no,由於操作系統每次同步AOF文件的周期不可控,而且會加大每次同步硬碟的數據量,雖然提升了性能,但數據安全性無法保證。

·配置為everysec,是建議的同步策略,也是默認配置,做到兼顧性能和數據安全性。理論上只有在系統突然宕機的情況下丟失1秒的數據。(嚴格來說最多丟失1秒數據是不準確的,5.3節會做具體介紹到。)

5.2.4重寫機制

隨著命令不斷寫入AOF,文件會越來越大,為了解決這個問題,Redis引入AOF重寫機制壓縮文件體積。AOF文件重寫是把Redis進程內的數據轉化為寫命令同步到新AOF文件的過程。

重寫後的AOF文件為什麼可以變小?有如下原因:

1)進程內已經超時的數據不再寫入文件。

2)舊的AOF文件含有無效命令,如del key1、hdel key2、srem keys、set

a111、set a222等。重寫使用進程內數據直接生成,這樣新的AOF文件只保留最終數據的寫入命令。

3)多條寫命令可以合並為一個,如:lpush list a、lpush list b、lpush list c可以轉化為:lpush list a b c。為了防止單條命令過大造成客戶端緩沖區溢出,對於list、set、hash、zset等類型操作,以64個元素為界拆分為多條。

AOF重寫降低了文件佔用空間,除此之外,另一個目的是:更小的AOF文件可以更快地被Redis載入。AOF重寫過程可以手動觸發和自動觸發:

·手動觸發:直接調用bgrewriteaof命令。

·自動觸發:根據auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數確定自動觸發時機。

·auto-aof-rewrite-min-size:表示運行AOF重寫時文件最小體積,默認為64MB。

·auto-aof-rewrite-percentage:代表當前AOF文件空間(aof_current_size)和上一次重寫後AOF文件空間(aof_base_size)的比值。自動觸發時機=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage其中aof_current_size和aof_base_size可以在info Persistence統計信息中查看。當觸發AOF重寫時,內部做了哪些事呢?下面結合圖5-3介紹它的運行流程。

圖5-3AOF重寫運作流程

流程說明:

1)執行AOF重寫請求。

如果當前進程正在執行AOF重寫,請求不執行並返回如下響應:

ERR Background append only file rewriting already in progress

如果當前進程正在執行bgsave操作,重寫命令延遲到bgsave完成之後再執行,返回如下響應:

Background append only file rewriting scheled

2)父進程執行fork創建子進程,開銷等同於bgsave過程。

3.1)主進程fork操作完成後,繼續響應其他命令。所有修改命令依然寫入AOF緩沖區並根據appendfsync策略同步到硬碟,保證原有AOF機制正確性。

3.2)由於fork操作運用寫時復制技術,子進程只能共享fork操作時的內存數據。由於父進程依然響應命令,Redis使用「AOF重寫緩沖區」保存這部分新數據,防止新AOF文件生成期間丟失這部分數據。

4)子進程根據內存快照,按照命令合並規則寫入到新的AOF文件。每次批量寫入硬碟數據量由配置aof-rewrite-incremental-fsync控制,默認為32MB,防止單次刷盤數據過多造成硬碟阻塞。

5.1)新AOF文件寫入完成後,子進程發送信號給父進程,父進程更新統計信息,具體見info persistence下的aof_*相關統計。

5.2)父進程把AOF重寫緩沖區的數據寫入到新的AOF文件。

5.3)使用新AOF文件替換老文件,完成AOF重寫。

5.2.5重啟載入

AOF和RDB文件都可以用於伺服器重啟時的數據恢復。如圖5-4所示,表示Redis持久化文件載入流程。

流程說明:

1)AOF持久化開啟且存在AOF文件時,優先載入AOF文件,列印如下日誌:

* DB loaded from append only file: 5.841 seconds

2)AOF關閉或者AOF文件不存在時,載入RDB文件,列印如下日誌:

* DB loaded from disk: 5.586 seconds

3)載入AOF/RDB文件成功後,Redis啟動成功。

4)AOF/RDB文件存在錯誤時,Redis啟動失敗並列印錯誤信息。

5.2.6文件校驗

載入損壞的AOF文件時會拒絕啟動,並列印如下日誌:

# Bad file format reading the append only file: make a backup of your AOF file,

then use ./redis-check-aof --fix <filename>

運維提示

對於錯誤格式的AOF文件,先進行備份,然後採用redis-check-aof--fix命令進行修復,修復後使用diff-u對比數據的差異,找出丟失的數據,有些可以人工修改補全。

AOF文件可能存在結尾不完整的情況,比如機器突然掉電導致AOF尾部文件命令寫入不全。Redis為我們提供了aof-load-truncated配置來兼容這種情況,默認開啟。載入AOF時,當遇到此問題時會忽略並繼續啟動,同時列印

如下警告日誌:

# !!! Warning: short read while loading the AOF file !!!

# !!! Truncating the AOF at offset 397856725 !!!

# AOF loaded anyway because aof-load-truncated is enabled

5.3問題定位與優化

Redis持久化功能一直是影響Redis性能的高發地,本節我們結合常見的持久化問題進行分析定位和優化。

5.3.1fork操作

當Redis做RDB或AOF重寫時,一個必不可少的操作就是執行fork操作創建子進程,對於大多數操作系統來說fork是個重量級錯誤。雖然fork創建的子進程不需要拷貝父進程的物理內存空間,但是會復制父進程的空間內存頁表。例如對於10GB的Redis進程,需要復制大約20MB的內存頁表,因此fork操作耗時跟進程總內存量息息相關,如果使用虛擬化技術,特別是Xen虛擬機,fork操作會更耗時。

fork耗時問題定位:對於高流量的Redis實例OPS可達5萬以上,如果fork操作耗時在秒級別將拖Redis幾萬條命令執行,對線上應用延遲影響非常明顯。正常情況下fork耗時應該是每GB消耗20毫秒左右。可以在info stats統計中查latest_fork_usec指標獲取最近一次fork操作耗時,單位微秒。

如何改善fork操作的耗時:

1)優先使用物理機或者高效支持fork操作的虛擬化技術,避免使用Xen。

2)控制Redis實例最大可用內存,fork耗時跟內存量成正比,線上建議每個Redis實例內存控制在10GB以內。

3)合理配置Linux內存分配策略,避免物理內存不足導致fork失敗,具體細節見12.1節「Linux配置優化」。

4)降低fork操作的頻率,如適度放寬AOF自動觸發時機,避免不必要的全量復制等。

5.3.2子進程開銷監控和優化

子進程負責AOF或者RDB文件的重寫,它的運行過程主要涉及CPU、內存、硬碟三部分的消耗。

1.CPU

·CPU開銷分析。子進程負責把進程內的數據分批寫入文件,這個過程屬於CPU密集操作,通常子進程對單核CPU利用率接近90%.

·CPU消耗優化。Redis是CPU密集型服務,不要做綁定單核CPU操作。由於子進程非常消耗CPU,會和父進程產生單核資源競爭。不要和其他CPU密集型服務部署在一起,造成CPU過度競爭。如果部署多個Redis實例,盡量保證同一時刻只有一個子進程執行重寫工作,具體細節見5.4節多實例部署」。

2.內存

·內存消耗分析。子進程通過fork操作產生,佔用內存大小等同於父進程,理論上需要兩倍的內存來完成持久化操作,但Linux有寫時復制機制(-on-write)。父子進程會共享相同的物理內存頁,當父進程處理寫請求時會把要修改的頁創建副本,而子進程在fork操作過程中共享整個父進程內存快照。

·內存消耗監控。RDB重寫時,Redis日誌輸出容如下:

* Background saving started by pid 7692

* DB saved on disk

* RDB: 5 MB of memory used by -on-write

* Background saving terminated with success

如果重寫過程中存在內存修改操作,父進程負責創建所修改內存頁的副本,從日誌中可以看出這部分內存消耗了5MB,可以等價認為RDB重寫消耗了5MB的內存。

AOF重寫時,Redis日誌輸出容如下:

* Background append only file rewriting started by pid 8937

* AOF rewrite child asks to stop sending diffs.

* Parent agreed to stop sending diffs. Finalizing AOF...

* Concatenating 0.00 MB of AOF diff received from parent.

* SYNC append only file rewrite performed

* AOF rewrite: 53 MB of memory used by -on-write

* Background AOF rewrite terminated with success

* Resial parent diff successfully flushed to the rewritten AOF (1.49 MB)

* Background AOF rewrite finished successfully

父進程維護頁副本消耗同RDB重寫過程類似,不同之處在於AOF重寫需要AOF重寫緩沖區,因此根據以上日誌可以預估內存消耗為:53MB+1.49MB,也就是AOF重寫時子進程消耗的內存量。

運維提示

編寫shell腳本根據Redis日誌可快速定位子進程重寫期間內存過度消耗情況。

內存消耗優化:

1)同CPU優化一樣,如果部署多個Redis實例,盡量保證同一時刻只有一個子進程在工作。

2)避免在大量寫入時做子進程重寫操作,這樣將導致父進程維護大量頁副本,造成內存消耗。Linux kernel在2.6.38內核增加了Transparent Huge Pages(THP),支持huge page(2MB)的頁分配,默認開啟。當開啟時可以降低fork創建子進程的速度,但執行fork之後,如果開啟THP,復制頁單位從原來4KB變為2MB,會大幅增加重寫期間父進程內存消耗。建議設置「sudo echo never>/sys/kernel/mm/transparent_hugepage/enabled」關閉THP。更多THP細節和配置見12.1Linux配置優化」。

3.硬碟

·硬碟開銷分析。子進程主要職責是把AOF或者RDB文件寫入硬碟持久化。勢必造成硬碟寫入壓力。根據Redis重寫AOF/RDB的數據量,結合系統工具如sar、iostat、iotop等,可分析出重寫期間硬碟負載情況。·硬碟開銷優化。優化方法如下:

a)不要和其他高硬碟負載的服務部署在一起。如:存儲服務、消息隊列服務等。

b)AOF重寫時會消耗大量硬碟IO,可以開啟配置no-appendfsync-on-rewrite,默認關閉。表示在AOF重寫期間不做fsync操作。

c)當開啟AOF功能的Redis用於高流量寫入場景時,如果使用普通機械磁碟,寫入吞吐一般在100MB/s左右,這時Redis實例的瓶頸主要在AOF同步硬碟上。

d)對於單機配置多個Redis實例的情況,可以配置不同實例分盤存儲AOF文件,分攤硬碟寫入壓力。運維提示

配置no-appendfsync-on-rewrite=yes時,在極端情況下可能丟失整個AOF重寫期間的數據,需要根據數據安全性決定是否配置。

5.3.3AOF追加阻塞

當開啟AOF持久化時,常用的同步硬碟的策略是everysec,用於平衡性能和數據安全性。對於這種方式,Redis使用另一條線程每秒執行fsync同步硬碟。當系統硬碟資源繁忙時,會造成Redis主線程阻塞,如圖5-5所示。

阻塞流程分析:

1)主線程負責寫入AOF緩沖區。

2)AOF線程負責每秒執行一次同步磁碟操作,並記錄最近一次同步時間。

3)主線程負責對比上次AOF同步時間:

·如果距上次同步成功時間在2秒內,主線程直接返回。

·如果距上次同步成功時間超過2秒,主線程將會阻塞,直到同步操作完成。

通過對AOF阻塞流程可以發現兩個問題:

1)everysec配置最多可能丟失2秒數據,不是1秒。

2)如果系統fsync緩慢,將會導致Redis主線程阻塞影響效率。

AOF阻塞問題定位:

1)發生AOF阻塞時,Redis輸出如下日誌,用於記錄AOF fsync阻塞導致拖慢Redis服務的行為:

Asynchronous AOF fsync is taking too long (disk is busy). Writing the AOF buffer

without waiting for fsync to complete, this may slow down Redis

2)每當發生AOF追加阻塞事件發生時,在info Persistence統計中,aof_delayed_fsync指標會累加,查看這個指標方便定位AOF阻塞問題。

3)AOF同步最多允許2秒的延遲,當延遲發生時說明硬碟存在高負載問題,可以通過監控工具如iotop,定位消耗硬碟IO資源的進程。優化AOF追加阻塞問題主要是優化系統硬碟負載,優化方式見上一節。

5.4多實例部署

Redis單線程架構導致無法充分利用CPU多核特性,通常的做法是在一台機器上部署多個Redis實例。當多個實例開啟AOF重寫後,彼此之間會產生對CPU和IO的競爭。本節主要介紹針對這種場景的分析和優化。上一節介紹了持久化相關的子進程開銷。對於單機多Redis部署,如果同一時刻運行多個子進程,對當前系統影響將非常明顯,因此需要採用一種措施,把子進程工作進行隔離。Redis在info Persistence中為我們提供了監控子進程運行狀況的度量指標,如表5-2所示。

我們基於以上指標,可以通過外部程序輪詢控制AOF重寫操作的執行,整個過程如圖5-6所示。

流程說明:

1)外部程序定時輪詢監控機器(machine)上所有Redis實例。

2)對於開啟AOF的實例,查看(aof_current_size-aof_base_size)/aof_base_size確認增長率。

3)當增長率超過特定閾值(如100%),執行bgrewriteaof命令手動觸發當前實例的AOF重寫。

4)運行期間循環檢查aof_rewrite_in_progress和aof_current_rewrite_time_sec指標,直到AOF重寫結束。

5)確認實例AOF重寫完成後,再檢查其他實例並重復2)~4)步操作。從而保證機器內每個Redis實例AOF重寫串列化執行。

5.5本章重點回顧

1)Redis提供了兩種持久化方式:RDB和AOF。

2)RDB使用一次性生成內存快照的方式,產生的文件緊湊壓縮比更高,因此讀取RDB恢復速度更快。由於每次生成RDB開銷較大,無法做到實時持久化,一般用於數據冷備和復制傳輸。

3)save命令會阻塞主線程不建議使用,bgsave命令通過fork操作創建子進程生成RDB避免阻塞。

4)AOF通過追加寫命令到文件實現持久化,通過appendfsync參數可以控制實時/秒級持久化。因為需要不斷追加寫命令,所以AOF文件體積逐漸變大,需要定期執行重寫操作來降低文件體積。

5)AOF重寫可以通過auto-aof-rewrite-min-size和auto-aof-rewrite-percentage參數控制自動觸發,也可以使用bgrewriteaof命令手動觸發。

6)子進程執行期間使用-on-write機制與父進程共享內存,避免內存消耗翻倍。AOF重寫期間還需要維護重寫緩沖區,保存新的寫入命令避免數據丟失。

7)持久化阻塞主線程場景有:fork阻塞和AOF追加阻塞。fork阻塞時間跟內存量和系統有關,AOF追加阻塞說明硬碟資源緊張。

8)單機下部署多個實例時,為了防止出現多個子進程執行重寫操作,建議做隔離控制,避免CPU和IO資源競爭。

⑵ redis怎麼進行內存管理

當mem_fragmentation_ratio>1時,說明used_memory_rss-used_memory多出的部分內存並沒有用於數據存儲,而是被內存碎片所消耗,如果兩者相差很大,說明碎片率嚴重。 

當mem_fragmentation_ratio<1時,這種情況一般出現在操作系統把Redis內存交換(Swap)到硬碟導致,出現這種情況時要格外關注,由於硬碟速度遠遠慢於內存,Redis性能會變得很差,甚至僵死。Redis進程內消耗主要包括:自身內存+對象內存+緩沖內存+內存碎片,其中Redis空進程自身內存消耗非常少,通常used_memory_rss在3MB左右,used_memory在800KB左右,一個空的Redis進程消耗內存可以忽略不計。

◆ 緩沖內存主要包括: 客戶端緩沖、復制積壓緩沖區、AOF緩沖區。客戶端緩沖指的是所有接入到Redis伺服器TCP連接的輸入輸出緩沖。輸入緩沖無法控制,最大空間為1G,如果超過將斷開連接。

◆ 復制積壓緩沖區: Redis在2.8版本之後提供了一個可重用的固定大小緩沖區用於實現部分復制功能,根據repl-backlog-size參數控制,默認1MB。對於復制積壓緩沖區整個主節點只有一個,所有的從節點共享此緩沖區,因此可以設置較大的緩沖區空間,如100MB,這部分內存投入是有價值的,可以有效避免全量復制AOF緩沖區:這部分空間用於在Redis重寫期間保存最近的寫入命令,AOF緩沖區空間消耗用戶無法控制,消耗的內存取決於AOF重寫時間和寫入命令量,這部分空間佔用通常很小。

Redis默認的內存分配器採用jemalloc, 可選的分配器還有:glibc、tcmalloc 。內存分配器為了更好地管理和重復利用內存,分配內存策略一般採用固定范圍的內存塊進行分配。內存碎片問題雖然是所有內存服務的通病,但是jemalloc針對碎片化問題專門做了優化,一般不會存在過度碎片化的問題,正常的碎片率(mem_fragmentation_ratio)在1.03左右。

一般以下場景容易出現高內存碎片問題:

●  頻繁做更新操作,例如頻繁對已存在的鍵執行append、setrange等更新操作。大量過期鍵刪除,鍵對象過期刪除後,釋放的空間無法得到充分利用,導致碎片率上升。

出現高內存碎片問題時常見的解決方式如下:

●  數據對齊:在條件允許的情況下盡量做數據對齊,比如數據盡量採用數字類型或者固定長度字元串等,但是這要視具體的業務而定,有些場景無法做到。

●  安全重啟:重啟節點可以做到內存碎片重新整理,因此可以利用高可用架構,如Sentinel或Cluster,將碎片率過高的主節點轉換為從節點,進行安全重啟子進程內存消耗主要指執行AOF/RDB重寫時Redis創建的子進程內存消耗。Redis執行fork操作產生的子進程內存佔用量對外表現為與父進程相同,理論上需要一倍的物理內存來完成重寫操作。

內存大頁機制(Transport Huge Pages,THP),是linux2.6.38後支持的功能,該功能支持2MB的大爺內存分配,默認開啟。在redis.conf中增加了一個新的配置項「disable-thp」來控制THP是否開啟。

子進程內存消耗總結如下:

1、Redis產生的子進程並不需要消耗1倍的父進程內存,實際消耗根據期間寫入命令量決定,但是依然要預留出一些內存防止溢出。

2、需要設置sysctl vm.overcommit_memory=1允許內核可以分配所有的物理內存,防止Redis進程執行fork時因系統剩餘內存不足而失敗。

3、排查當前系統是否支持並開啟THP,如果開啟建議關閉,防止-onwrite期間內存過度消耗。

在日誌信息中可以查看到關於THP的日誌內容, 如下:

Redis使用maxmemory參數限制最大可用內存。限制內存的目的主要有:

1、用於緩存場景,當超出內存上限maxmemory時使用LRU等刪除策略釋放空間。

2、防止所用內存超過伺服器物理內存。

需要注意 ,maxmemory限制的是Redis實際使用的內存量,也就是used_memory統計項對應的內存。由於內存碎片率的存在,實際消耗的內存可能會比maxmemory設置的更大,實際使用時要小心這部分內存溢出。

Redis的內存回收機制主要體現在以下兩個方面:

1、刪除到達過期時間的鍵對象。

2、內存使用達到maxmemory上限時觸發內存溢出控制策略。

刪除過期鍵對象:

Redis所有的鍵都可以設置過期屬性,內部保存在過期字典中。由於進程內保存大量的鍵,維護每個鍵精準的過期刪除機制會導致消耗大量的CPU,對於單線程的Redis來說成本過高,因此Redis採用惰性刪除和定時任務刪除機制實現過期鍵的內存回收。

● 惰性刪除:惰性刪除用於當客戶端讀取帶有超時屬性的鍵時,如果已經超過鍵設置的過期時間,會執行刪除操作並返回空,這種策略是出於節省CPU成本考慮,不需要單獨維護TTL鏈表來處理過期鍵的刪除。但是單獨用這種方式存在內存泄露的問題,當過期鍵一直沒有訪問將無法得到及時刪除,從而導致內存不能及時釋放。正因為如此,Redis還提供另一種定時任務刪除機製作為惰性刪除的補充。

● 定時任務刪除:Redis內部維護一個定時任務,默認每秒運行10次(通過配置hz控制)。定時任務中刪除過期鍵邏輯採用了自適應演算法,根據鍵的過期比例、使用快慢兩種速率模式回收鍵, 流程如圖所示。

當Redis所用內存達到maxmemory上限時會觸發相應的溢出控制策略。具體策略受maxmemory-policy參數控制,Redis支持6種策略, 如下所示:

1)noeviction: 默認策略,不會刪除任何數據,拒絕所有寫入操作並返回客戶端錯誤信息(error)OOM command not allowed when used memory,此時Redis只響應讀操作。

2)volatile-lru: 根據LRU演算法刪除設置了超時屬性(expire)的鍵,直到騰出足夠空間為止。如果沒有可刪除的鍵對象,回退到noeviction策略。

3)allkeys-lru: 根據LRU演算法刪除鍵,不管數據有沒有設置超時屬性,直到騰出足夠空間為止。

4)allkeys-random: 隨機刪除所有鍵,直到騰出足夠空間為止。

5)volatile-random: 隨機刪除過期鍵,直到騰出足夠空間為止。

6)volatile-ttl: 根據鍵值對象的ttl屬性,刪除最近將要過期數據。如果沒有,回退到noeviction策略。

⑶ mime郵件附件解碼

在網路上找到的, 你看看,可能會有幫助的

MIME 編碼方式簡介
Subject: =?gb2312?B?xOO6w6Oh?=
這里是郵件的主題,可是因為編碼了,我們看不出是什麼內容,其原來的文本是: 「你好!」我們先看看 MIME 編碼的兩種方法。
對郵件進行編碼最初的原因是因為 Internet 上的很多網關不能正確傳輸8 bit 內碼的字元,比如漢字等。編碼的原理就是把 8 bit 的內容轉換成 7 bit 的形式以能正確傳輸,在接收方收到之後,再將其還原成 8 bit 的內容。
MIME 是「多用途網際郵件擴充協議」的縮寫,在 MIME 協議之前,郵件的編碼曾經有過 UUENCODE 等編碼方式 ,但是由於 MIME 協議演算法簡單,並且易於擴展,現在已經成為郵件編碼方式的主流,不僅是用來傳輸 8 bit 的字元,也可以用來傳送二進制的文件 ,如郵件附件中的圖像、音頻等信息,而且擴展了很多基於MIME 的應用。從編碼方式來說,MIME 定義了兩種編碼方法Base64與QP(Quote-Printable) :
Base 64 是一種通用的方法,其原理很簡單,就是把三個Byte的數據用 4 個Byte表示,這樣,這四個Byte 中,實際用到的都只有前面6 bit,這樣就不存在只能傳輸 7bit 的字元的問題了。Base 64的縮寫一般是「B」,像這封信中的Subject 就是用的 Base64 編碼。
另一種方法是QP(Quote-Printable) 方法,通常縮寫為「Q」方法,其原理是把一個 8 bit 的字元用兩個16進制數值表示,然後在前面加「=」。所以我們看到經過QP編碼後的文件通常是這個樣子:=B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1。
------------------------------------------------------
http://www.china-askpro.com/msg36/qa99.shtml
------------------------------------------------------
http://ke..com/view/160611.htm

參考資料:我想你說的解碼不成功的可能是QP編碼

⑷ 最優布車方案怎麼做啊! 黑書上的貪心章節習題

代碼就不貼了,基本演算法就是首先在所有位置中找出擁有最大控制數的車,將其控制范圍標記,之後再找出第二大控制數(未標記)的位置,標記,依次遞推.......最後的答案就是最優解

⑸ PHP源碼解密

請務必試試.
網路一下:清風發明"空格"zend
不錯的話.給加個分吧.我沒半點分數了.

⑹ pascal高精度加法

本人的程序。。可以通過。。您可以嘗試。。望採納
type
thp=array[0..500]of longint;
var i,k,l:integer;
aa,bb,cc:thp;
s1,s2,s:ansistring;
function tohp(var st:ansistring):thp;
var i,len:longint;
code:integer;
a:thp;
begin
fillchar(a,sizeof(a),0);
len:=length(st);
i:=0;
repeat
i:=i+1;
val((st,len-3,4),a[i],code);
st:=(st,1,len-4);
len:=len-4;
until len<=0;
a[0]:=i;
tohp:=a;
end;

function plus(a:thp;b:thp):thp;
var i:longint;
overflow:longint;
result:thp;
begin
fillchar(result,sizeof(result),0);
overflow:=0;
i:=1;
while (i<=a[0])or(i<=b[0])or (overflow>0) do
begin
if i<=a[0] then inc(overflow,a[i]);
if i<=b[0] then inc(overflow,b[i]);
if overflow>=10000 then
begin
result[i]:=overflow-10000;
overflow:=1;
end
else
begin
result[i]:=overflow;
overflow:=0;
end;
i:=i+1;
end;
result[0]:=i-1;
while (result[0]>1)and (result[result[0]]=0) do
result[0]:=result[0]-1 ;
plus:=result;
end;

begin
while eof<>true do
begin
readln(s);
k:=pos(' ',s);
l:=length(s);
s1:=(s,1,k-1);
s2:=(s,k+1,l-k);
aa:=tohp(s1);
bb:=tohp(s2);
cc:=plus(aa,bb);
write(cc[cc[0]]);
for i:=cc[0]-1 downto 1 do
begin
if cc[i]<1000 then write('0');
if cc[i]<100 then write('0');
if cc[i]<10 then write('0');
write(cc[i]) ;
end;
writeln;
end;
end.

⑺ 現在有什麼跟當初比特幣一樣的投資,可以入手

THP(TurboHigh Performance)中文:渦輪幣。是基於 Proof Of Capacity (以下簡稱:POC) 的新型加密貨幣。其主要的特點是使用硬碟作為共識的參與者,降低加密貨幣對電力資源的消耗 ,降低參與門檻,讓其生產方式更趨向去中心化方式,並更加安全可信,讓人人都能參與到加密貨幣的開采,通過數學演算法以及分布式開采產生信用和價值。
POW(工作量證明): POW機制是依賴機器算力進行數學運算來獲取數字貨幣。誰的算力(計算力量)高,誰就能產出更多數字貨幣。勞動致富,多勞者多得(BTC就是POW機制挖礦)!
但存在致命的缺點:
1、礦機設備成本貴(幾萬到十幾萬不等),設備折舊率高。
2、設備很費電(成本高)。
3、並非真正的中心化(如果你足夠有錢你買很多礦機,你的計算能力就大,當計算量大於50%的時候整個網路就是你說了算,會造成獨裁。)

⑻ 韓信點兵問題

韓信點兵又稱為中國剩餘定理,相傳漢高祖劉邦問大將軍韓信統御兵士多少,韓信答說,每3人一列餘1人、5人一列餘2人、7人一列餘4人、13人一列餘6人……。劉邦茫然而不知其數。
我們先考慮下列的問題:假設兵不滿一萬,每5人一列、9人一列、13人一列、17人一列都剩3人,則兵有多少?
淮安民間傳說著一則故事——「韓信點兵」:秦朝末年,楚漢相爭。有一次,韓信將1500名將士與楚王大將李鋒交戰。苦戰一場,楚軍不敵,敗退回營,漢軍也死傷四五百人,於是,韓信整頓兵馬也返回大本營。當行至一山坡,忽有後軍來報,說有楚軍騎兵追來。只見遠方塵土飛揚,殺聲震天。
漢軍本來已十分疲憊,這時隊伍大嘩。韓信兵馬到坡頂,見來敵不足五百騎,便急速點兵迎敵。他命令士兵3人一排,結果多出2名;接著命令士兵5人一排,結果多出3名;他又命令士兵7人一排,結果又多出2名。
韓信馬上向將士們宣布:我軍有1073名勇士,敵人不足五百,我們居高臨下,以眾擊寡,一定能打敗敵人。漢軍本來就信服自己的統帥,這一來更認為韓信是「神仙下凡」、「神機妙算」。於是士氣大振。一時間旌旗搖動,鼓聲喧天,漢軍步步進逼,楚軍亂作一團。交戰不久,楚軍大敗而逃。
韓信點兵的題目
首先我們先求5、9、13、17之最小公倍數9945(註:因為5、9、13、17為兩兩互質的整數,故其最小公倍數為這些數的積),然後再加3,得9948(人)。
在一千多年前的《孫子算經》中,有這樣一道算術題:「今有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二,問物幾何?」按照今天的話來說:一個數除以3餘2,除以5餘3,除以7餘2,求這個數。這樣的問題,也有人稱為「韓信點兵」.它形成了一類問題,也就是初等數論中的解同餘式。
①有一個數,除以3餘2,除以4餘1,問這個數除以12餘幾?解:除以3餘2的數有:2,5,8,11,14,17,20,23…它們除以12的余數是:2,5,8,11,2,5,8,11…除以4餘1的數有:1,5,9,13,17,21,25,29…它們除以12的余數是:1,5,9,1,5,9,….
一個數除以12的余數是唯一的.上面兩行余數中,只有5是共同的,因此這個數除以12的余數是5。如果我們把①的問題改變一下,不求被12除的余數,而是求這個數.很明顯,滿足條件的數是很多的,它是5+12×整數,整數可以取0,1,2,…,無窮無盡.事實上,我們首先找出5後,注意到12是3與4的最小公倍數,再加上12的整數倍,就都是滿足條件的數.這樣就是把「除以3餘2,除以4餘1」兩個條件合並成「除以12餘5」一個條件.《孫子算經》提出的問題有三個條件,我們可以先把兩個條件合並成一個.然後再與第三個條件合並,就可找到答案.②一個數除以3餘2,除以5餘3,除以7餘2,求符合條件的最小數。
解:先列出除以3餘2的數:2,5,8,11,14,17,20,23,26…再列出除以5餘3的數:3,8,13,18,23,28…
這兩列數中,首先出現的公共數是8.3與5的最小公倍數是15.兩個條件合並成一個就是8+15×整數,列出這一串數是8,23,38,…,再列出除以7餘2的數2,9,16,23,30…就得出符合題目條件的最小數是23.
事實上,我們已把題目中三個條件合並成一個:被105除餘23.
那麼韓信點的兵在1000-1500之間,應該是105×10+23=1073人
中國有一本數學古書「孫子算經」也有類似的問題:「今有物,不知其數,三三數之,剩二,五五數之,剩三,七七數之,剩二,問物幾何?」答曰:「二十三」術曰:「三三數剩一置幾何?答曰:五乘七乘二得之一百四。
五五數剩一復置幾何?答曰,三乘七得之二十一是也。
七七數剩一又置幾何?答曰,三乘五得之十五是也。
三乘五乘七,又得一百零五。
則可知已,又三三數之剩二,置一百四十,五五數之剩三,置六十三,七七數之剩二,置三十,並之,得二百三十三,以二百一十減之,即得。凡三三數之剩一,則置七十,五五數之剩一,則置二十一,七七數之剩一,則置十五,即得。」
孫子算經的作者及確實著作年代均不可考,不過根據考證,著作年代不會在晉朝之後,以這個考證來說上面這種問題的解法,中國人發現得比西方早,所以這個問題的推廣及其解法,被稱為中國剩餘定理。
韓信點兵的演算法總結
1.算兩兩數之間的能整除數
2.算三個數的能整除數
3.用1中的三個整除數之和減去2中的整除數之差(有時候是倍數)
4.計算結果即可
韓信帶1500名兵士打仗,戰死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韓信馬上說出人數:1049
如多一人,即可湊整。倖存人數應在1000~1100人之間,即得出:3乘5乘7乘10減1=1049(人)
到了明代,數學家程大位用詩歌概括了這一演算法,他寫道:三人同行七十稀,五樹梅花廿一枝,七子團圓月正半,除百零五便得知。
這首詩的意思是:用3除所得的余數乘上70,加上用5除所得余數乘以21,再加上用7除所得的余數乘上15,結果大於105就減去105的倍數,這樣就知道所求的數了。
金庸先生曾在作品《射鵰英雄傳》引用過此段。

⑼ 運行時出現floating point error domain 跪求解決方法

換一下演算法.枚舉運算,對輸入的四個數a,b,c,d執行下面54種運算.如果有某一個得數是24即可以算出否則不能.
a+b+c+d
a+b+c-d
a+b-c-d
a*b+c+d
a*b*c+d
a*b+c*d
a*b*c*d
a/b+c+d
a/b/c+d
a/b+c/d
a*b*c/d
a*b/c/d
a*b/c+d
a/b+c*d
a*b-c-d
a*b*c-d
a*b-c*d
a*b/c-d
a*b+c-d
(a+b+c)*d
(a+b-c)*d
(a*b+c)*d
(a*b-c)*d
(a/b+c)*d
(a/b-c)*d
(a-b/c)*d
(a+b+c)/d
(a+b-c)/d
(a*b+c)/d
(a*b-c)/d
(a/b+c)/d
(a+b)*c+d
(a-b)*c+d
(a+b)/c+d
(a-b)/c+d
(a+b)*c-d
(a-b)*c-d
(a+b)/c-d
(a+b)*c*d
(a-b)*c*d
(a+b)/c*d
(a-b)/c*d
(a+b)/c/d
(a+b)*(c+d)
(a+b)*(c-d)
(a-b)*(c-d)
(a+b)/(c+d)
(a+b)/(c-d)
a/b+c-d
a+b/(c+d)
a*b/(c+d)
a+b/(c-d)
a*b/(c-d)
a/(b-c/d)

熱點內容
ios數據上傳伺服器 發布:2024-05-02 13:39:27 瀏覽:351
Php面向對象模式 發布:2024-05-02 13:33:32 瀏覽:80
安卓手機軟體如何快速打開 發布:2024-05-02 13:25:16 瀏覽:963
安卓網頁圖片不顯示怎麼辦 發布:2024-05-02 13:16:00 瀏覽:673
虛擬機搭建linux 發布:2024-05-02 13:02:48 瀏覽:186
哈弗f7配置怎麼使用 發布:2024-05-02 12:53:14 瀏覽:575
psv重新構建資料庫 發布:2024-05-02 12:43:53 瀏覽:792
農行對公密碼器的憑證號碼在哪裡 發布:2024-05-02 12:38:55 瀏覽:890
雙子星腳本 發布:2024-05-02 12:26:01 瀏覽:142
域名如何將程序部署到伺服器 發布:2024-05-02 12:25:38 瀏覽:948