網站首頁 編程語言 正文
Redis - 數據結構和持久化機制
- 前言
- 一. Redis 底層數據結構
- 1.1 鍵值之間的組織結構
- 1.2 哈希沖突和 rehash
- 1.2.1 漸進式 rehash
- 1.3 Redis 單線程
- 1.3.1 Redis 6.0 多線程
- 1.4 總結
- 二. Redis 持久化機制
- 2.1 AOF 日志如何實現快速恢復
- 2.1.1 AOF 寫回策略
- 2.1.2 AOF 重寫機制
- 2.1.3 AOF 阻塞問題
- 2.2 RDB 如何實現快速恢復
- 2.2.1 使用RDB案例分析
- 2.2.2 題外話 - 什么是Swap
前言
Redis
這塊的復習,看的是蔣德鈞老師的相關文章,主要是想Redis
實戰相關的一些理論知識和解決方案。
Redis
是一種典型的鍵值數據庫,即Key-Value
形式的一種存儲關系。
Redis
是一種內存數據庫,數據都保存在內存上。
一. Redis 底層數據結構
Redis
中常見的數據類型有5大類:
-
String
:字符串。 -
List
:列表。 -
Hash
:哈希。 -
Set
:集合。 -
Sorted Set
:有序集合。
Redis
中底層的數據結構一共有6大類(實際上也就是Value
的存儲形式):
- 簡單動態字符串。
- 雙向鏈表。
- 壓縮列表。
- 哈希表。
- 跳表。
- 整數數組。
兩者的映射關系圖如下:
除了String
類型,其他的List、Hash、Sorted Set、Set
類型統稱為集合類型,一個鍵對應一個集合的數據。
1.1 鍵值之間的組織結構
Redis
中使用一個哈希表來保存所有的鍵值對,也因此叫做全局哈希表。
- 哈希表實際上就是一個數組,由多個哈希桶組成,數組元素就是一個哈希桶。
- 每個哈希桶又保存了鍵值對數據。
- 鍵值對數據并不是值本身,而是指向值的指針。 這里無論是
key
還是value
都是存的指針。
如圖:
由于Key - Value
之間的存儲關系是一個哈希表。因此我們可以用O(1)
的時間復雜度來查找到鍵值對。但是,當Redis
中寫入的數據量越來越多的時候,操作有可能會突然變慢了,是因為哈希表結構存在著哈希沖突問題以及 rehash
操作帶來的操作阻塞。
1.2 哈希沖突和 rehash
我們知道,哈希表中每個哈希桶都會存儲若干個鍵值對(entry
),而這些鍵值對存儲于哪一個哈希桶中,由Key
的哈希值來決定。那么哈希沖突也就是兩個 key
的哈希值和哈希桶計算對應關系時,正好落在了同一個哈希桶中。
每個哈希桶中元素(entry
)之間的組織方式又是什么呢?每個entry
之間會通過 next
指針相連,成一個鏈表。就是哈希沖突鏈。目的是為了在發生哈希沖突的時候,可以通過哈希沖突鏈進行逐一的元素查找操作。如圖:
雖然哈希沖突鏈用于解決哈希沖突,但是我們上文也提到了一個字眼,會根據指針進行逐一的查找
,也就是O(N)
的一個時間復雜度。因此倘若哈希沖突越嚴重,即同一個哈希桶中的元素越多,那么對應元素的查找時間也就越久。
而這樣的操作對于Redis
來說是不可接受的,因為Redis
就是追求快,因此Redis
此時會對哈希表做rehash
操作。也就是增加現有的哈希桶數量,讓entry
元素能夠在更多地哈希桶之間分散保存,從而減少單個哈希桶中的元素數量。
Redis
準備了兩個全局哈希表,簡稱H1
和H2
。平時插入的元素假設都默認使用H1
,這時候H2
并沒有被分配空間。 當數據到達一定程度,閾值一般是當前哈希表總容量的0.75倍
,Redis
開始執行rehash
。
rehash
的一個大概流程:
-
H2
分配更大的空間,是H1
容量的兩倍。 - 將
H1
中的數據映射并拷貝給H2
中。 - 釋放掉
H1
的空間。
下一次rehash
以此類推,H1
變兩倍… 還需要注意的一點是,在數據的拷貝過程中,如果一次性拷貝所有的數據,會造成Redis
線程的阻塞,無法服務其他的請求。因此采用了漸進式rehash
。
1.2.1 漸進式 rehash
漸進式rehash
也就是在拷貝數據階段下,Redis
每處理一個請求,就會從H1
的某個索引位置開始,將該索引對應的哈希桶上的所有entry
拷貝到H2
中,等下一個請求的時候,則拷貝下一個自然順序的所有entry
。如圖:
在漸進式rehash
的過程中,會同時使用H1
和H2
兩個哈希表,新添加到字典的鍵值對一律會被保存到H2
里面,而H1
則不再進行任何添加操作,這一措施保證了H1
包含的鍵值對數量會只減不增,并隨著rehash
操作的執行而最終變成空表。
一句話總結就是:將一次性大量拷貝的過程拆分為多次處理請求的過程中。
最后,我們知道哈希表在查找元素方面的時間復雜度是O(1)
,而數組和壓縮列表這類數據結構則在O(N)
,那么為什么Redis
還將其作為底層的數據結構呢?原因有兩點:
- 內存利用率高:數組和壓縮列表的數據結構比較緊湊,比鏈表的占用空間要更少。而
Redis
作為內存數據庫,數據都保存在內存上,需要提高內存的利用率。 - 數組對
CPU
高速緩存支持更好:集合數據元素較少情況下,默認采用內存緊湊排列的方式存儲,同時利用CPU
高速緩存不會降低訪問速度。當數據元素超過設定閾值后,避免查詢時間復雜度太高,轉為哈希和跳表數據結構存儲,保證查詢效率。
1.3 Redis 單線程
為什么Redis
使用單線程去處理呢?首先來說下多線程的優缺點:
- 優點:在合理的資源分配情況下,可以增加系統中同一時間內處理請求的個數,即提高吞吐率。
- 缺點:同時多線程對共享資源的并發訪問控制,需要有額外的機制進行保證,例如鎖。而這個額外的機制,就會帶來額外的開銷。 有時候控制不好反而會讓效率減低。
因此為了減少多線程帶來的額外開銷和多線程同時訪問共享資源的并發問題,Redis
直接采用了單線程模式。
注意:
- 這里的單線程指的是
Redis
的網絡IO
和鍵值對讀寫是由一個線程來完成的。 - 實際上
Redis
的其他功能,例如持久化、異步刪除、集群數據的同步等操作是由額外的線程執行的。
那么為什么Redis
單線程還這么快呢?從上文我們可以得到兩個原因:
-
Redis
是一個內存型數據庫,大部分操作在內存上完成。 - 高效的數據結構,哈希表保存鍵值對。跳表加快查詢。
其實還有一個原因就是多路復用機制 IO模型復習傳送門。可以讓其在網路IO
操作中能夠并發的處理大量的客戶端請求,實現高吞吐率。
在 Redis
只運行單線程的情況下,該機制允許內核中,同時存在多個監聽套接字和已連接套接字。內核會一直監聽這些套接字上的連接請求或數據請求。一旦有請求到達,就會交給 Redis
線程處理,這就實現了一個 Redis
線程處理多個 IO
流的效果。
而對于Redis
的IO
模型而言,為了能夠在請求到達的時候能夠及時通知Redis
線程,Redis
運用了基于事件的回調機制:針對不同的事件,調用對應的處理函數。 如圖:
總的來說其流程很簡單:
- 客戶端有著不同的請求,而這些請求都作為一個個事件被放入到事件隊列中。
-
Redis
單線程則對該事件隊列不斷進行處理。
再做個小總結,Redis
單線程快,快在內存操作、哈希和跳表等數據結構、多路復用IO
機制,但是Redis
單線程處理IO請求也有它的性能瓶頸,主要包括兩個方面:
- 由于網絡
IO
和鍵值對讀寫是由一個線程來完成的,因此一旦上一個請求阻塞了,后面的請求都要等待前一個耗時請求處理完成,才能夠自己做處理。 -
并發量非常大的時候,單線程讀寫客戶端
IO
存在性能瓶頸,雖然采用IO
多路復用機制,但是讀寫客戶端數據依舊是同步IO
,只能單線程依次讀取客戶端的數據,無法利用到CPU
多核。
耗時操作可能有:
-
操作超大字符串
Key
,即bigKey
:bigKey
的寫入和刪除都需要消耗更多的時間,即在分配內存和釋放內存上耗費的時間更久。 -
使用耗時命令,比如范圍查詢,時間復雜度就是
O(N)
,N
越大,越耗時。 -
大量
Key
集中過期:因為Redis
的過期機制是在主線程中執行的,而大量的Key
過期會導致大把時間耗費在Key
的刪除上。 - 淘汰策略:同理,淘汰策略也是在主線程上執行的。
-
AOF
刷盤開啟always
機制:每次寫入都需要把這個操作刷到磁盤,寫磁盤的速度遠比寫內存慢,會拖慢Redis
的性能; - 主從全量同步生成
RDB
:雖然采用fork
子進程生成數據快照,但fork
這一瞬間也是會阻塞整個線程的,實例越大,阻塞時間越久。
1.3.1 Redis 6.0 多線程
這里只做介紹和了解:Redis
在6.0版本引入了多線程,原因如下:
-
Redis
的瓶頸不在CPU
,而在內存和網絡,內存不夠可以增加內存或通過數據結構等進行優化。 -
Redis
的網絡IO
的讀寫占用了部分CPU
的時間,如果可以把網絡處理改成多線程的方式,性能會有很大提升。(注意:針對客戶端的讀寫是并行的,每個命令的真正操作依舊是單線程的)
引入后好處:
- 充分利用服務器的多核資源。
- 多線程分攤
Redis
同步IO
讀寫負荷,要么都同時讀,要么都同時寫,沒有同時讀寫的情況。
1.4 總結
5種數據類型,6種數據結構。(左側為數據類型,右側為數據結構組成)
-
String
:簡單動態字符串。 -
List
:雙向鏈表+壓縮列表。 -
Hash
:壓縮列表+哈希表。 -
Set
:哈希表+整數數組。 -
Sorted Set
:跳表+壓縮列表。
Redis
用一個全局的哈希表保存著所有的鍵值對:
- 一個哈希表本質上是一個數組,數組的每個元素是一個哈希桶。
- 哈希桶中的元素組成一個哈希沖突鏈。即不同的
Key
計算出的hash
值相等 - 元素存儲的時候,根據
Key
的hash
值來決定放到哪個哈希桶。 - 若發生哈希沖突。則在哈希沖突鏈上逐一查找。
Redis
通過漸進rehash
的方式,避免哈希沖突太嚴重(目的)。利用兩個全局哈希表來進行數據的漸進拷貝和擴容。
Redis
采用單線程模型。Redis
的網絡 IO
和鍵值對讀寫是由一個線程來完成的。其快的原因主要有兩點:
-
Redis
是一個內存型數據庫,大部分操作在內存上完成。 - 高效的數據結構,哈希表保存鍵值對。跳表加快查詢。
二. Redis 持久化機制
Redis
的持久化主要有兩大機制:
-
AOF
日志:記錄每次對服務器寫的操作,當服務器重啟的時候會重新執行這些命令來恢復原始的數據。 -
RDB
快照:能夠在指定的時間間隔內對你的數據進行快照存儲。
2.1 AOF 日志如何實現快速恢復
我們知道,Mysql
中有redo log
,都是先寫日志,再將數據寫入磁盤中。即WAL(Write Ahead Log)
。這個日志也叫重做日志緩沖,主要是用來實現數據恢復的。而Redis
也有個有相同作用的日志:AOF
日志。全稱為Append Only File
。不過,和Mysql
不同的是,AOF
機制是先將數據寫入內存,再記錄日志。
如圖:AOF
日志主要記錄著Redis
接收到的每一條指令,以文本形式保存。當Redis
宕機時,可以根據AOF
日志來恢復內存中的數據。 舉個例子:
set title Hello
那么上述命令對應的AOF
日志內容就是:
# 表示該命令由3個部分組成,其中每個部分都以$+數字開頭
*3
# 代表3個字節,后面的同理
$3
set
$5
title
$6
Hello
AOF
的優點:
- 為了避免額外的檢查開銷,
Redis
在AOF
做日志記錄的時候,并不會先對命令做語法檢查。而是直接記錄執行成功的命令。 - 由于后寫日志,因此并不會阻塞當前的寫操作。
AOF
的缺點:
- 若執行完一個命令,但在記錄
AOF
日志之前就發生了宕機,那么這個命令和對應的數據就有丟失的風險。 - 寫
AOF
日志時的主線程阻塞問題。
2.1.1 AOF 寫回策略
為了解決上述的AOF
日志缺點,AOF
機制提供了三個選項用來控制AOF
日志的寫到磁盤的時機:
appendfsync always
appendfsync everysec
appendfsync no
-
always
:同步寫回。每個寫命令執行完,立馬同步地將日志寫回磁盤。 -
everysec
:每秒寫回。每個寫命令執行完,只是先把日志寫到AOF
文件的內存緩沖區,每隔一秒把緩沖區中的內容寫入磁盤。 -
no
:操作系統控制。每個寫命令執行完,同樣先把日志寫到AOF
文件的內存緩沖區,由操作系統決定何時將緩沖區內容寫回磁盤。
三種寫回策略的優劣勢:
策略 | 寫回的時機 | 優點 | 缺點 | 選擇 | 阻塞問題 |
---|---|---|---|---|---|
always |
同步寫回,每執行一個命令就寫。 | 高可靠,數據基本不會丟失 | 每寫一個命令就落盤,性能影響較大 | 若追求高可靠性保證,選擇它 | 同步操作是在主進程的主線程中進行的 |
everysec |
每秒寫回。 | 性能折中 | 若發生宕機,會丟失1秒內的數據 | 折中 | 同步操作是通過后臺I/O線程進行的 |
no |
操作系統控制寫回 | 性能好 | 若發生宕機,丟失的數據較多 | 若追求高性能,就選擇它 | 同步操作的控制權交由操作系統,不阻塞主線程 |
最后,既然AOF
是一種日志的機制,那么不可避免的性能問題就來了:
-
AOF
日志的內容越來越多怎么辦?畢竟存儲空間有限。 - 若文件太大,后面追加命令記錄的時候,效率也會變低。
- 若發生宕機,難道要對
AOF
里面的記錄都一條條的執行嗎?效率太低了。
上面歸根到底就是:日志文件太大了怎么辦? 通過AOF
重寫機制來解決。
2.1.2 AOF 重寫機制
AOF
重寫機制指的是對于過大的AOF
文件進行重寫,即壓縮AOF
文件的大小。 檢查當前鍵值數據庫中的鍵值對,記錄鍵值對的最終狀態,從而實現對某個鍵值對重復操作后產生的多條操作記錄壓縮成一條的效果。進而實現壓縮AOF
文件的大小。
舉個例子:
set title name1;
set title name2;
set title name3;
那么AOF
重寫后,對于Key
為title
的這個鍵值對,只會記錄最終的結果,即set title name3;
AOF
重寫的觸發條件(同時滿足):
-
auto-aof-rewrite-min-size
: 表示運行AOF
重寫時文件的最小大小,默認為64MB
。 -
auto-aof-rewrite-percentage
:重寫的一個閾值,公式在下面。
2.1.3 AOF 阻塞問題
首先,根據上文我們得知,寫AOF
日志的時候,有三種寫回機制,總的來說對應兩種情況:
-
always
:由主線程來寫,會阻塞。 -
everysec
和no
:一個是IO
線程,一個是系統控制,歸于子進程來執行,不會阻塞主線程。
而AOF
重寫過程和寫AOF
日志過程又不同,重寫過程是由后臺子進程bgrewriteaof
來完成的。(注意:AOF
重寫和寫AOF
日志是兩個東西,不要搞混了)
AOF
重寫過程總結為:一個拷貝,兩處日志。
一個拷貝:每次執行重寫的時候,主線程就 fork
出一個后臺 bgrewriteaof
線程,簡稱子進程。子進程會拷貝父進程的頁表,即虛實映射關系,從而共享訪問父進程的內存數據了。
兩處日志:
- 第一處
日志A
:當前正在使用的AOF
日志:在AOF
重寫階段,倘若有新的寫操作,那么Redis
就講這個操作寫到日志A
的緩沖區。這樣一來即使宕機,該AOF
日志的操作依舊是完整的,可以用于恢復。 - 第二處
日志B
:新的AOF
重寫日志。倘若有新的操作也會被寫到該新重寫日志B
的緩沖區
中(注意這里不是寫入日志,而是寫入緩沖區)。這樣一來,日志B
也不會丟失最新的操作,重寫完成后,就可以用新的AOF
文件代替舊文件了。
AOF
工作原理:
-
Redis
執行fork()
,現在同時擁有父進程和子進程bgrewriteaof
。 - 子進程開始將新
AOF
文件的內容寫入到臨時文件。 - 對于所有新執行的寫入命令,父進程一邊將它們累積到一個內存緩存中,一邊將這些改動追加到現有
AOF
文件的末尾。這樣樣即使在重寫的中途發生停機,現有的AOF
文件也還是安全的。 - 當子進程完成重寫工作時,它給父進程發送一個信號,父進程在接收到信號之后,將內存緩存中的所有數據追加到新
AOF
文件的末尾。 - 最后
Redis
用新文件替換舊文件,之后所有命令都會直接追加到新AOF
文件的末尾。
流程圖大概如下:
總的來說就是:
- 用子進程拷貝內存頁表,從而實現父子進程的數據共享。再進行日志的重寫操作。
- 重寫階段用兩個
AOF
日志做記錄,重寫完成后,用新創建的AOF
日志替代老的。
問題1:為什么AOF
重寫需要用到兩個AOF
日志,不能復用AOF
日志本身嗎?
回答:
- 父子進程寫同一個文件必然會產生競爭問題,控制競爭就意味著會影響父進程的性能。
-
若
AOF
重寫過程中失敗了,那么原本的AOF
文件相當于被污染了,無法做恢復使用。所以Redis AOF
重寫一個新文件,重寫失敗的話,直接刪除這個文件就好了,不會對原先的AOF
文件產生影響。等重寫完成之后,直接替換舊文件即可。
問題2:AOF
日志重寫的時候,雖然有個子進程,其執行不會阻塞主線程,但是重寫過程就一定不會發生阻塞嗎?
回答:AOF
重寫過程中父進程進行寫操作的時候可能會發生阻塞。
從兩個角度來考慮:fork
角度:
- 首先主線程
fork
子進程的時候,一定是阻塞主線程的。fork
采用操作系統提供的寫實復制(Copy On Write)
機制,拷貝進程必要的數據結構,包括內存頁表。在拷貝完成之前都是阻塞的。 - 因此,阻塞的時間取決于拷貝的內存大小,實例越大,內存頁表越大,
fork
時間也就越久。 - 拷貝完成后,子進程與父進程指向相同的內存地址空間,父子進程共享一塊數據,但是并沒有申請與父進程相同的內存大小。
- 而寫實復制的意思就是在寫操作發生的時候,才會真正拷貝內存真正的數據。
第二點:主進程的寫操作角度:
- 若父進程操作的是一個已經存在的
key
,那么這個時候父進程就會真正拷貝這個key
對應的內存數據,申請新的內存空間(以頁為單位,默認4K
),父子進程內存數據開始分離。 - 倘若父進程此時操作的是一個
bigkey
,根據文章上面的內容可以得知,申請大塊內存的耗時會邊長,從而增加阻塞風險。 - 若操作系統開啟了內存大頁機制(
Huge Page
,頁面大小2M
),那么父進程申請內存時阻塞的概率將會大大提高(因為申請大塊內存空間,會很耗時,從而阻塞)。
2.2 RDB 如何實現快速恢復
到這里,我們知道Redis
可以通過AOF
日志來實現數據的恢復,本質就是執行AOF
里面記錄的命令。雖然在命令行很多的情況下,AOF
有著重寫機制可以壓縮日志。但是還是得一條條去執行對應的命令,在操作種類繁多的情況下,Redis
的恢復速度還是比較慢的。因此又有一種內存快照的方式,所謂內存快照,就是指內存中的數據在某一個時刻的狀態記錄。即RDB
,來實現數據的恢復。
和AOF
相比,RDB
記錄的是某一個時刻的全量數據,并不是一條條具體的操作命令了,因此在數據恢復的時候,可以把RDB
文件讀入內存中,直接恢復整個數據狀態。不過做RDB
快照,也有幾個問題需要去思考:
- 快照的范圍。
- 快照過程中,數據是否允許被增刪改,期間
Redis
是否會被阻塞。
針對第一個問題:快照執行的是全量快照。
針對第二個問題,Redis
提供了兩個命令來生成RDB
文件:
-
save
:在主線程中執行,會導致阻塞; -
bgsave
(默認方式):創建一個子進程,專門用于寫入RDB
文件,避免了主線程的阻塞。
那么快照期間能夠修改數據嗎?答案是可以的。從 2.1 章節中我們得知AOF
重寫機制有個fork
的過程,子進程和父進程共享內存數據。那么RDB
快照的生成也是同理(使用bgsave
命令)。
當然,也可以通過配置來設置RDB功能:
# 意思是,如果在60s內,至少有1000個鍵值對的修改,就會觸發bgsave
save 60 1000
bgsave
子進程是由主線程 fork
生成的,可以共享主線程的所有內存數據。bgsave
子進程運行后,開始讀取主線程的內存數據,并把它們寫入 RDB
文件。同樣地,Redis
借助寫時復制技術,在執行快照的同時,正常處理寫操作。
那么主子進程之間就是相互獨立的。在主進程開始修改某個數據的時候,大概原理如下:
- 在
RDB
快照過程中,假設主進程修改了一塊數據,鍵值對M
。那么此時這塊數據就會被復制一份,生成對應的副本N
。 - 那么之后主進程主要在副本
N
上進行數據的操作和修改。 - 同時
bgsave
子進程可以將原來的鍵值對M
寫入到RDB
文件中。
如圖:
那么在了解完RDB
的作用以及 RDB
可以不阻塞主進程并且不影響讀寫操作之后,我們可以關注于RDB
功能的使用時機。雖然 bgsave
執行時不阻塞主線程,但是快照執行的時機卻是一個難題。
- 快照間隔過長會丟失數據。
- 快照時間過短會加大磁盤寫入壓力。
- 頻繁
fork
子進程 ,fork
的過程會導致主進程阻塞。
那么就是說,RDB
快照的頻率太高,就會有額外的開銷,太低又可能造成數據的丟失。那咋辦呢?
Redis4.0
中提出了一個混合使用 AOF
日志和內存快照的方法。簡單來說,內存快照以一定的頻率執行,在兩次快照之間,使用 AOF
日志記錄這期間的所有命令操作。 可以通過以下命令開啟:
aof-use-rdb-preamble yes
2.2.1 使用RDB案例分析
題目的搬運(主要這一塊有大佬講解的太好了):
一個 2 核 CPU
、4GB
內存、500GB
磁盤的云主機運行 Redis
,Redis
數據庫的數據量大小差不多是 2GB
,我們使用了 RDB
做持久化保證。同時Redis
主要以寫操作為主,讀寫比例為2:8
。那么此時做RDB
持久化有什么風險?
內存資源風險:
- 因為
RDB
是由fork
子進程做持久化的,而本篇文章提到好多次寫時復制這么個概念。那么在持久化的過程中,寫時復制就會重新分配整個實例80%的內存副本(讀寫比例為2:8
)。也就是2GB * 0.8 = 1.6GB
。那么此時系統一共就4GB
,接近飽和了。 - 如果此時父進程又有大量新
key
寫入,而Redis
中的數據又是保存到內存中的,所以機器的內存很容易被消耗殆盡。
而這里又可以考慮是否開啟Swap
機制:
-
開啟
Swap
機制,那么Redis
會有一部分數據被換到磁盤上,當Redis
訪問這部分在磁盤上的數據時,性能會急劇下降,已經達不到高性能的標準。 - 沒有開啟
Swap
機制,會直接觸發OOM
,父子進程會面臨被系統kill
掉的風險。
CPU資源風險:
- 子進程在做生成
RDB
快照的過程會消耗大量的CPU
資源。 - 雖然
Redis
處理處理請求是單線程的,但Redis Server
還有其他線程在后臺工作,例如AOF
每秒刷盤等這些操作。即其他工作線程還需要占用CPU
。 - 由于機器只有2核
CPU
,這也就意味著父進程占用了超過一半的CPU
資源,此時子進程做RDB
持久化,可能會產生CPU
競爭,導致的結果就是父進程處理請求延遲增大,子進程生成RDB
快照的時間也會變長,整個Redis Server
性能下降。
2.2.2 題外話 - 什么是Swap
swap
空間是硬盤上的一塊區域。虛擬內存是由可訪問的物理內存和swap space
組成,也即swap space
是虛擬內存的一部分。swap
存儲那些暫時不活躍的內存頁面。當操作系統決定要給活躍的進程分配物理內存空間并且可利用的物理內存不足時會用到swap space。
說白了,就是把一塊磁盤空間或者一個本地文件,當做內存來使用(重點)。 因此即使服務器的內存不足,也可以運行大內存的應用程序。
原文鏈接:https://blog.csdn.net/Zong_0915/article/details/125981885
相關推薦
- 2022-10-19 Python基礎之類的定義和使用詳解_python
- 2022-04-08 Python編程-封裝,繼承與多態_python
- 2022-10-02 Django與圖表的數據交互的實現_python
- 2022-06-14 Redis高并發情況下并發扣減庫存項目實戰_Redis
- 2022-07-31 ubuntu下常用apt命令介紹_linux shell
- 2022-07-01 C++中strlen函數的三種實現方法_C 語言
- 2022-06-28 python神經網絡學習利用PyTorch進行回歸運算_python
- 2023-04-12 Docker?login和logout的使用_docker
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支