精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

VLDB 頂會(huì)論文 Async-fork 解讀與 Redis 實(shí)踐

數(shù)據(jù)庫 其他數(shù)據(jù)庫
通過不同數(shù)據(jù)量下對(duì)比測試,我們可以看到,Async-fork 相比原生 fork,阻塞時(shí)間大大減少,性能提升非常明顯。而且阻塞時(shí)間非常穩(wěn)定,不會(huì)因?yàn)閿?shù)據(jù)量的增長出現(xiàn)倍數(shù)級(jí)增長。

1、背景

在 Redis 中,在 AOF 文件重寫、生成 RDB 備份文件以及主從全量同步過程中,都需要使用系統(tǒng)調(diào)用 fork 創(chuàng)建一個(gè)子進(jìn)程來獲取內(nèi)存數(shù)據(jù)快照,在 fork() 函數(shù)創(chuàng)建子進(jìn)程的時(shí)候,內(nèi)核會(huì)把父進(jìn)程的「頁表」復(fù)制一份給子進(jìn)程,如果頁表很大,復(fù)制頁表的過程耗時(shí)會(huì)非常長,那么在此期間,業(yè)務(wù)訪問 Redis 讀寫延遲會(huì)大幅增加。

最近,阿里云聯(lián)合上海交大,在數(shù)據(jù)庫頂級(jí)會(huì)議 VLDB 上發(fā)表了一篇文章《Async-fork: Mitigating Query Latency Spikes Incurred by the Fork-based Snapshot Mechanism from the OS Level》,文章介紹到,他們?cè)O(shè)計(jì)了一個(gè)新的 fork(稱為 Async-fork),將 fork 調(diào)用過程中最耗時(shí)的頁表拷貝部分從父進(jìn)程移動(dòng)到子進(jìn)程,父進(jìn)程因而可以快速返回用戶態(tài)處理用戶查詢,子進(jìn)程則在此期間完成頁表拷貝,從而減少  fork 期間到達(dá)請(qǐng)求的尾延遲。所以該特性在類似 Redis 類型的內(nèi)存數(shù)據(jù)庫上均能取得不錯(cuò)的效果。

2、基本概念

2.1   物理內(nèi)存地址

也即實(shí)際的物理內(nèi)存地址空間。

2.2   虛擬地址空間

虛擬地址空間(Virtual Address Space)是每一個(gè)程序被加載運(yùn)行起來后,操作系統(tǒng)為進(jìn)程分配的虛擬內(nèi)存,它為每個(gè)進(jìn)程提供了一個(gè)假象,即每個(gè)進(jìn)程都在獨(dú)占地使用主存。

每個(gè)進(jìn)程所能訪問的最大的虛擬地址空間由計(jì)算機(jī)的硬件平臺(tái)決定,具體地說是由 CPU 的位數(shù)決定的。比如 32 位的 CPU 就是我們常說的 4GB 虛擬內(nèi)存空間。

程序訪問內(nèi)存地址使用虛擬地址空間,然后由操作系統(tǒng)將這個(gè)虛擬地址映射到適當(dāng)?shù)奈锢韮?nèi)存地址上。這樣,只要操作系統(tǒng)處理好虛擬地址到物理內(nèi)存地址的映射,就可以保證不同的程序最終訪問的內(nèi)存地址位于不同的區(qū)域,彼此沒有重疊,就可以達(dá)到內(nèi)存地址空間隔離的效果。

當(dāng)進(jìn)程創(chuàng)建時(shí),每個(gè)進(jìn)程都會(huì)有一個(gè)自己的 4GB 虛擬地址空間。要注意的是這個(gè) 4GB 的地址空間是“虛擬”的,并不是真實(shí)存在的,而且每個(gè)進(jìn)程只能訪問自己虛擬地址空間中的數(shù)據(jù),無法訪問別的進(jìn)程中的數(shù)據(jù),通過這種方法實(shí)現(xiàn)了進(jìn)程間的地址隔離。

對(duì)于 Linux,4GB 的虛擬地址空間包含用戶態(tài)虛擬內(nèi)存空間和內(nèi)核態(tài)虛擬內(nèi)存空間兩部分,默認(rèn)分配狀態(tài)如下:

圖片

2.3   內(nèi)存頁表

「頁表」保存的是虛擬內(nèi)存地址與物理內(nèi)存地址的映射關(guān)系。

CPU 訪問數(shù)據(jù)的時(shí)候,CPU 發(fā)出的地址是虛擬地址,CPU 中內(nèi)存管理單元(MMU)通過查詢頁表,把虛擬地址轉(zhuǎn)換為物理地址,再去訪問物理內(nèi)存條。

2.3.1  內(nèi)存分頁

分頁是把整個(gè)虛擬和物理內(nèi)存空間切成一段段固定尺寸的大小,這樣一個(gè)連續(xù)并且尺寸固定的內(nèi)存空間,我們叫頁(Page)。在 Linux 下,每一頁的大小為 4KB。

在 32 位的環(huán)境下,虛擬地址空間共有 4GB,假設(shè)一個(gè)頁的大小是 4KB(2^12),那么就需要大約 100 萬(2^20)個(gè)頁,每個(gè)「頁表項(xiàng)」需要 4 個(gè)字節(jié)大小來存儲(chǔ),那么整個(gè) 4GB 空間的映射就需要有 4MB 的內(nèi)存來存儲(chǔ)頁表。

這 4MB 大小的頁表,看起來也不是很大。但是每個(gè)進(jìn)程都是有自己的虛擬地址空間,也就說都有自己的頁表。每個(gè)機(jī)器上同時(shí)運(yùn)行多個(gè)進(jìn)程,頁表將占用大量內(nèi)存。

2.3.2   多級(jí)頁表

要解決上面提到的存儲(chǔ)進(jìn)程頁表項(xiàng)占用大量內(nèi)存空間的問題,就需要采用一種叫作多級(jí)頁表(Multi-Level Page Table)的解決方案。

我們把這個(gè) 100 多萬個(gè)「頁表項(xiàng)」的單級(jí)頁表再分頁,將頁表(一級(jí)頁表)分為 1024 個(gè)頁表(二級(jí)頁表),每個(gè)二級(jí)頁表中包含 1024 個(gè)「頁表項(xiàng)」,形成二級(jí)分頁。這樣,一級(jí)頁表就可以覆蓋整個(gè) 4GB 虛擬地址空間,但如果某個(gè)一級(jí)頁表的頁表項(xiàng)沒有被用到,也就不需要?jiǎng)?chuàng)建這個(gè)頁表項(xiàng)對(duì)應(yīng)的二級(jí)頁表了,即可以在需要時(shí)才創(chuàng)建二級(jí)頁表。也就是,內(nèi)存中只需要保存一級(jí)頁表以及使用到的二級(jí)頁表,大量的未被使用的二級(jí)頁表則不需要分配內(nèi)存并加載在內(nèi)存中,因此,達(dá)到節(jié)省頁表占用內(nèi)存空間的目的。

對(duì)于 64 位的系統(tǒng),使用四級(jí)分頁目錄,分別是:

  • 頁全局目錄項(xiàng) PGD(Page Global Directory);
  • 頁上級(jí)目錄項(xiàng) PUD(Page Upper Directory);
  • 頁中間目錄項(xiàng) PMD(Page Middle Directory);
  • 頁表項(xiàng) PTE(Page Table Entry);

圖片

2.4   虛擬內(nèi)存區(qū)域(VMA)

進(jìn)程的虛擬內(nèi)存空間包含一段一段的虛擬內(nèi)存區(qū)域(Virtual memory area, 簡稱 VMA),每個(gè) VMA 描述虛擬內(nèi)存空間中一段連續(xù)的區(qū)域,每個(gè) VMA 由許多虛擬頁組成,即每個(gè) VMA 包含許多頁表項(xiàng) PTE。

3、Fork 原理

在默認(rèn) fork 的調(diào)用過程中,父進(jìn)程需要將許多進(jìn)程元數(shù)據(jù)(例如文件描述符、信號(hào)量、頁表等)復(fù)制到子進(jìn)程,而頁表的復(fù)制是其中最耗時(shí)的部分(占據(jù) fork 調(diào)用耗時(shí)的 97% 以上)。

Linux 的 fork() 使用寫時(shí)拷貝 (copy-on-write) 頁的方式實(shí)現(xiàn)。寫時(shí)拷貝是一種可以推遲甚至避免拷貝數(shù)據(jù)的技術(shù)。在創(chuàng)建子進(jìn)程的過程中,操作系統(tǒng)會(huì)把父進(jìn)程的「頁表」復(fù)制一份給子進(jìn)程,這個(gè)頁表記錄著虛擬地址和物理地址映射關(guān)系,此時(shí),操作系統(tǒng)并不復(fù)制整個(gè)進(jìn)程的物理內(nèi)存,而是讓父子進(jìn)程共享同一個(gè)物理內(nèi)存。同時(shí),操作系統(tǒng)內(nèi)核會(huì)把共享的所有的內(nèi)存頁的權(quán)限都設(shè)為 read-only。

那什么時(shí)候會(huì)發(fā)生物理內(nèi)存的復(fù)制呢?

當(dāng)父進(jìn)程或者子進(jìn)程在向共享內(nèi)存發(fā)起寫操作時(shí),內(nèi)存管理單元 MMU 檢測到內(nèi)存頁是 read-only 的,于是觸發(fā)缺頁中斷異常(page-fault),處理器會(huì)從中斷描述符表(IDT)中獲取到對(duì)應(yīng)的處理程序。在中斷程序中,內(nèi)核就會(huì)把觸發(fā)異常的物理內(nèi)存頁復(fù)制一份,并重新設(shè)置其內(nèi)存映射關(guān)系,將父子進(jìn)程的內(nèi)存讀寫權(quán)限設(shè)置為可讀寫,于是父子進(jìn)程各自持有獨(dú)立的一份,之后進(jìn)程才會(huì)對(duì)內(nèi)存進(jìn)行寫操作,這個(gè)過程也被稱為寫時(shí)復(fù)制(Copy On Write)。

圖片

4、Fork 的痛點(diǎn)

在原生 fork 下,在父進(jìn)程調(diào)用 fork() 創(chuàng)建子進(jìn)程的過程中,雖然使用了寫時(shí)復(fù)制頁表的方式進(jìn)行優(yōu)化,但由于要復(fù)制父進(jìn)程的頁表,還是會(huì)造成父進(jìn)程出現(xiàn)短時(shí)間阻塞,阻塞的時(shí)間跟頁表的大小有關(guān),頁表越大,阻塞的時(shí)間也越長。

我們?cè)跍y試中很容易觀察到 fork 產(chǎn)生的阻塞現(xiàn)象,以及 fork 造成的 Redis 訪問抖動(dòng)現(xiàn)象。

4.1   測試環(huán)境

Redis 版本:優(yōu)化前 Redis-server

機(jī)器操作系統(tǒng):無 Async-fork 特性的系統(tǒng)

測試數(shù)據(jù)量:21.63G

127.0.0.1:6380> info memory
# Memory
used_memory:23220597688
used_memory_human:21.63G

4.2   阻塞現(xiàn)象復(fù)現(xiàn)

在使用 Redis-benchmark 壓測的過程中,手動(dòng)執(zhí)行 bgsave 命令,觀察 fork 耗時(shí)和壓測指標(biāo) TP100。

使用 info stats 返回上次 fork 耗時(shí):latest_fork_usec:183632,可以看到 fork 耗時(shí) 183 毫秒。

在壓測過程中分別不執(zhí)行 bgsave 和執(zhí)行 bgsave,結(jié)果如下:

# 壓測過程中未執(zhí)行 bgsave
[root@xxx bin]# Redis-benchmark -d 256 -t set -n 1000000 -a xxxxxx -p 6380
====== SET ======
1000000 requests completed in 8.15 seconds
50 parallel clients
256 bytes payload
keep alive: 1


99.90% <= 1 milliseconds
100.00% <= 1 milliseconds
122669.27 requests per second


# 壓測過程中執(zhí)行 bgsave
[root@xxx bin]# Redis-benchmark -d 256 -t set -n 1000000 -a xxxxxx -p 6380
====== SET ======
1000000 requests completed in 13.97 seconds
50 parallel clients
256 bytes payload
keep alive: 1


86.41% <= 1 milliseconds
86.42% <= 2 milliseconds
99.95% <= 3 milliseconds
99.99% <= 4 milliseconds
99.99% <= 10 milliseconds
99.99% <= 11 milliseconds
99.99% <= 12 milliseconds
100.00% <= 187 milliseconds
100.00% <= 187 milliseconds
71561.47 requests per second

從壓測數(shù)據(jù)可以看到,單機(jī)環(huán)境下壓測,壓測時(shí)未執(zhí)行 bgsave,TP100 約 1 毫秒;如果壓測過程中,手動(dòng)執(zhí)行 bgsave 命令,觸發(fā) fork 操作,TP100 達(dá)到 187 毫秒。

4.3   Strace 跟蹤 fork 過程耗時(shí)

strace 常用來跟蹤進(jìn)程執(zhí)行時(shí)的系統(tǒng)調(diào)用和所接收的信號(hào)。

$ strace -p 32088 -T -tt -o strace00.out
14:01:33.623495 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fbe5242fa50) = 37513 <0.183533>
14:01:33.807142 open("/data1/6380/6380.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = 60 <0.000018>
14:01:33.807644 lseek(60, 0, SEEK_END) = 8512 <0.000017>
14:01:33.807690 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=528, ...}) = 0 <0.000010>
14:01:33.807732 fstat(60, {st_mode=S_IFREG|0644, st_size=8512, ...}) = 0 <0.000007>
14:01:33.807756 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbe52437000 <0.000009>
14:01:33.807787 write(60, "35994:M 21 Mar 14:01:33.807 * Ba"..., 69) = 69 <0.000015>
14:01:33.807819 close(60) = 0 <0.000008>
14:01:33.807845 munmap(0x7fbe52437000, 4096) = 0 <0.000013>

由于 Linux 中通過 clone() 系統(tǒng)調(diào)用實(shí)現(xiàn) fork();我們可以看到追蹤到 clone 系統(tǒng)調(diào)用,并且耗時(shí) 183 毫秒,與 info stats統(tǒng)計(jì)的 fork 耗時(shí)一致。

5、Async-fork

鑒于以上 linux 原生 fork 系統(tǒng)調(diào)用的痛點(diǎn),對(duì)于像 Redis 這樣的高性能內(nèi)存數(shù)據(jù)庫,將會(huì)增加 fork 期間的用戶訪問延遲,論文中設(shè)計(jì)了一個(gè)新的 fork(稱為 Async-fork)來解決上述問題。

Async-fork 設(shè)計(jì)的核心思想是將 fork 調(diào)用過程中最耗時(shí)的頁表拷貝工作從父進(jìn)程移動(dòng)到子進(jìn)程,縮短父進(jìn)程調(diào)用 fork 時(shí)陷入內(nèi)核態(tài)的時(shí)間,父進(jìn)程因而可以快速返回用戶態(tài)處理用戶查詢,子進(jìn)程則在此期間完成頁表拷貝。與 Linux 中的默認(rèn)原生 fork 相比,Async-fork 顯著減少了 Redis 快照期間到達(dá)請(qǐng)求的尾延遲。

5.1   Async-fork 的挑戰(zhàn)

然而,Async-fork 的實(shí)現(xiàn)過程中,實(shí)際工作并非描述的這么簡單。頁表的異步復(fù)制操作可能導(dǎo)致快照不一致。以下圖為例,Redis 在 T0 時(shí)刻保存內(nèi)存快照,而某個(gè)用戶請(qǐng)求在 T2 時(shí)刻向  Redis 插入了新的鍵值對(duì)(k2, v2),這將導(dǎo)致父進(jìn)程修改它的頁表項(xiàng)(PTE2)。假如 T2 時(shí)刻這個(gè)被修改的頁表項(xiàng)(PTE2)還沒有被子進(jìn)程復(fù)制完成, 這個(gè)修改后的內(nèi)存頁表項(xiàng)及對(duì)應(yīng)內(nèi)存頁后續(xù)將被復(fù)制到子進(jìn)程,這個(gè)新插入的鍵值對(duì)將被子進(jìn)程最終寫入硬盤,破壞了快照一致性。(快照文件應(yīng)該記錄的是保存拍攝內(nèi)存快照那一刻的內(nèi)存數(shù)據(jù))

圖片來源于:參考資料[1] 第 8 頁

5.2   Async-fork 詳解

前面提到,每個(gè)進(jìn)程都有自己的虛擬內(nèi)存空間,Linux 使用一組虛擬內(nèi)存區(qū)域 VMA 來描述進(jìn)程的虛擬內(nèi)存空間,每個(gè) VMA 包含許多頁表項(xiàng)。

在默認(rèn) fork 中,父進(jìn)程遍歷每個(gè) VMA,將每個(gè) VMA 復(fù)制到子進(jìn)程,并自上而下地復(fù)制該 VMA 對(duì)應(yīng)的頁表項(xiàng)到子進(jìn)程,對(duì)于 64 位的系統(tǒng),使用四級(jí)分頁目錄,每個(gè) VMA 包括 PGD、PUD、PMD、PTE,都將由父進(jìn)程逐級(jí)復(fù)制完成。在 Async-fork 中,父進(jìn)程同樣遍歷每個(gè) VMA,但只負(fù)責(zé)將 PGD、PUD 這兩級(jí)頁表項(xiàng)復(fù)制到子進(jìn)程。

隨后,父進(jìn)程將子進(jìn)程放置到某個(gè) CPU 上使子進(jìn)程開始運(yùn)行,父進(jìn)程返回到用戶態(tài),繼續(xù)響應(yīng)用戶請(qǐng)求。由子進(jìn)程負(fù)責(zé)每個(gè) VMA 剩下的 PMD 和 PTE 兩級(jí)頁表的復(fù)制工作。

如果在父進(jìn)程返回用戶態(tài)后,子進(jìn)程復(fù)制內(nèi)存頁表期間,父進(jìn)程需要修改還未完成復(fù)制的頁表項(xiàng),怎樣避免上述提到的破壞快照一致性問題呢?

圖片來源于:參考資料[1] 第 7 頁

5.2.1  主動(dòng)同步機(jī)制

父進(jìn)程返回用戶態(tài)后,父進(jìn)程的 PTE 可能被修改。如果在子進(jìn)程復(fù)制內(nèi)存頁表期間,父進(jìn)程檢測到了 PTE 修改,則會(huì)觸發(fā)主動(dòng)同步機(jī)制,也就是父進(jìn)程也加入頁表復(fù)制工作,來主動(dòng)完成被修改的相關(guān)頁表復(fù)制,該機(jī)制用來確保 PTE 在修改前被復(fù)制到子進(jìn)程。

當(dāng)一個(gè) PTE 將被修改時(shí),父進(jìn)程不僅復(fù)制這一個(gè) PTE,還同時(shí)將位于同一個(gè)頁表上的所有 PTE(一共 512 個(gè) PTE),連同它的父級(jí) PMD 項(xiàng)復(fù)制到子進(jìn)程。

父進(jìn)程中的 PTE 發(fā)生修改時(shí),如果子進(jìn)程已經(jīng)復(fù)制過了這個(gè) PTE,父進(jìn)程就不需要復(fù)制了,否則會(huì)發(fā)生重復(fù)復(fù)制。怎么區(qū)分 PTE 是否已經(jīng)復(fù)制過?

Async-fork 使用 PMD 項(xiàng)上的 RW 位來標(biāo)記是否被復(fù)制。具體而言,當(dāng)父進(jìn)程第一次返回用戶態(tài)時(shí),它所有 PMD 項(xiàng)被設(shè)置為寫保護(hù)(RW=0),代表這個(gè) PMD 項(xiàng)以及它指向的 512 個(gè) PTE 還沒有被復(fù)制到子進(jìn)程。當(dāng)子進(jìn)程復(fù)制一個(gè) PMD 項(xiàng)時(shí),通過檢查這個(gè) PMD 是否為寫保護(hù),即可判斷該 PMD 是否已經(jīng)被復(fù)制到子進(jìn)程。如果還沒有被復(fù)制,子進(jìn)程將復(fù)制這個(gè) PMD,以及它指向的 512 個(gè) PTE。

在完成 PMD 及其指向的 512 個(gè) PTE 復(fù)制后,子進(jìn)程將父進(jìn)程中的該 PMD 設(shè)置為可寫(RW=1),代表這個(gè) PMD 項(xiàng)以及它指向的 512 個(gè) PTE 已經(jīng)被復(fù)制到子進(jìn)程。當(dāng)父進(jìn)程觸發(fā)主動(dòng)同步時(shí),也通過檢查 PMD 項(xiàng)是否為寫保護(hù)判斷是否被復(fù)制,并在完成復(fù)制后將 PMD 項(xiàng)設(shè)置為可寫。同時(shí),在復(fù)制 PMD 項(xiàng)和 PTE 時(shí),父進(jìn)程和子進(jìn)程都鎖定 PTE 表,因此它們不會(huì)出現(xiàn)同時(shí)復(fù)制同一 PMD 項(xiàng)指向的 PTE。

在操作系統(tǒng)中,PTE 的修改分為兩類:

1)VMA 級(jí)的修改。例如,創(chuàng)建、合并、刪除 VMA 等操作作用于特定 VMA 上,VMA 級(jí)的修改通常會(huì)導(dǎo)致大量的 PTE 修改,因此涉及大量的 PMD。

2)PMD 級(jí)的修改。PMD 級(jí)的修改僅涉及一個(gè) PMD。

5.2.2  錯(cuò)誤處理

Async-fork 在復(fù)制頁表時(shí)涉及到內(nèi)存分配,難免會(huì)發(fā)生錯(cuò)誤。例如,由于內(nèi)存不足,進(jìn)程可能無法申請(qǐng)到新的 PTE 表。當(dāng)錯(cuò)誤發(fā)生時(shí),應(yīng)該將父進(jìn)程恢復(fù)到它調(diào)用 Async-fork 之前的狀態(tài)。

在 Async-fork 中,父進(jìn)程 PMD 項(xiàng)目的 RW 位可能會(huì)被修改。因此,當(dāng)發(fā)生錯(cuò)誤時(shí),需要將 PMD 項(xiàng)全部回滾為可寫。

6、Redis 優(yōu)化實(shí)踐

6.1   Async-fork 阻塞現(xiàn)象

在支持 Async-fork 的操作系統(tǒng)(即 Tair 專屬操作系統(tǒng)鏡像)機(jī)器上測試,理論上來說,按照文章的預(yù)期,用戶不需要作任何修改(Async-fork 使用了原生 fork 相同的接口,沒有另外新增接口),就可以享受 Async-fork 優(yōu)化帶來的優(yōu)勢(shì),但是,使用 Redis 實(shí)際測試過程中,結(jié)果不符合預(yù)期,在 Redis 壓測過程中手動(dòng)執(zhí)行 bgsave 命令觸發(fā) fork 操作,還是觀察到了 TP100 抖動(dòng)現(xiàn)象。

測試環(huán)境

Redis 版本:優(yōu)化前 Redis-Server

機(jī)器操作系統(tǒng):Tair 專屬操作系統(tǒng)鏡像

測試數(shù)據(jù)量:54.38G

127.0.0.1:6679> info memory
# Memory
used_memory:58385641120
used_memory_human:54.38G

問題現(xiàn)象

現(xiàn)象:fork 耗時(shí)正常,但是壓測過程中執(zhí)行 bgsave,TP100 不正常

在壓測過程中執(zhí)行 bgsave,使用 info stats 返回上次 fork 耗時(shí):latest_fork_usec:426

TP100 結(jié)果如下:

# 壓測過程中執(zhí)行 bgsave
[root@xxx ~]# /usr/bin/Redis-benchmark -d 256 -t set -n 1000000 -a xxxxxx -p 6679
====== SET ======
1000000 requests completed in 7.88 seconds
50 parallel clients
256 bytes payload
keep alive: 1


100.00% <= 411 milliseconds
100.00% <= 412 milliseconds
100.00% <= 412 milliseconds
126871.35 requests per second

也就是說,觀察到的 fork 耗時(shí)正常,但是壓測過程中 Redis 依然出現(xiàn)了尾延遲,這顯然不符合預(yù)期。

追蹤過程

使用 strace 命令進(jìn)行分析,結(jié)果如下:

$ strace -p 32088 -T -tt -o strace00.out
14:18:12.933441 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f461c0daa50) = 13772 <0.000380>
14:18:12.933884 open("/data1/6679/6679.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = 60 <0.000019>
14:18:12.933948 lseek(60, 0, SEEK_END) = 11484 <0.000013>
14:18:12.933983 stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=556, ...}) = 0 <0.000016>
14:18:12.934032 fstat(60, {st_mode=S_IFREG|0644, st_size=11484, ...}) = 0 <0.000014>
14:18:12.934062 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f461c0e4000 <0.358768>
14:18:13.292883 write(60, "32088:M 21 Mar 14:18:12.933 * Ba"..., 69) = 69 <0.000032>
14:18:13.292951 close(60) = 0 <0.000014>
14:18:13.292980 munmap(0x7f461c0e4000, 4096) = 0 <0.000019>
$ strace -p 11559 -T -tt -e trace=memory -o trace00.out
14:18:12.934062 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f461c0e4000 <0.358768>
14:18:13.292980 munmap(0x7f461c0e4000, 4096) = 0 <0.000019>

可以觀察到,clone 耗時(shí) 380 微秒,已經(jīng)大幅降低,也就 fork 快速返回了用戶態(tài)響應(yīng)用戶請(qǐng)求。然而,注意到,緊接著出現(xiàn)了一個(gè) mmap 耗時(shí) 358 毫秒,與 TP100 數(shù)據(jù)接近。

由于 mmap 系統(tǒng)調(diào)用會(huì)在當(dāng)前進(jìn)程的虛擬地址空間中,尋找一段滿足大小要求的虛擬地址,并且為此虛擬地址分配一個(gè)虛擬內(nèi)存區(qū)域( vm_area_struct 結(jié)構(gòu)),也就是會(huì)觸發(fā) VMA 級(jí)虛擬頁表變化,也就觸發(fā)父進(jìn)程主動(dòng)同步機(jī)制,父進(jìn)程主動(dòng)幫助完成相應(yīng)頁表復(fù)制動(dòng)作。VMA 級(jí)虛擬頁表變化,需要將對(duì)應(yīng)的三級(jí)和四級(jí)所有頁目錄都復(fù)制到子進(jìn)程,因此,耗時(shí)比較高。

那么,這個(gè) mmap 調(diào)用又是哪里來的呢?

定位問題

perf 是 Linux下的一款性能分析工具,能夠進(jìn)行函數(shù)級(jí)與指令級(jí)的熱點(diǎn)查找。

通過 perf trace 可以看到響應(yīng)調(diào)用堆棧及耗時(shí),分析結(jié)果如下:

$ perf trace -p 11559 -o trace01.out --max-stack 15 -T
616821913.647 (358.740 ms): Redis-server_4/32088 mmap(len: 4096, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS ) = 0x7f461c0e4000
__mmap64 (/usr/lib64/libc-2.17.so)
__GI__IO_file_doallocate (inlined)
__GI__IO_doallocbuf (inlined)
__GI__IO_file_overflow (inlined)
_IO_new_file_xsputn (inlined)
_IO_vfprintf_internal (inlined)
__GI_fprintf (inlined)
serverLogRaw (/usr/local/Redis/Redis-server)
serverLog (/usr/local/Redis/Redis-server)
rdbSaveBackground (/usr/local/Redis/Redis-server)
bgsaveCommand (/usr/local/Redis/Redis-server)
call (/usr/local/Redis/Redis-server)
processCommand (/usr/local/Redis/Redis-server)
processInputBuffer (/usr/local/Redis/Redis-server)
aeProcessEvents (/usr/local/Redis/Redis-server)


616822272.562 ( 0.010 ms): Redis-server_4/32088 munmap(addr: 0x7f461c0e4000, len: 4096 ) = 0
__munmap (inlined)
__GI__IO_setb (inlined)
_IO_new_file_close_it (inlined)
_IO_new_fclose (inlined)
serverLogRaw (/usr/local/Redis/Redis-server)
serverLog (/usr/local/Redis/Redis-server)
rdbSaveBackground (/usr/local/Redis/Redis-server)
bgsaveCommand (/usr/local/Redis/Redis-server)
call (/usr/local/Redis/Redis-server)
processCommand (/usr/local/Redis/Redis-server)
processInputBuffer (/usr/local/Redis/Redis-server)
aeProcessEvents (/usr/local/Redis/Redis-server)
aeMain (/usr/local/Redis/Redis-server)
main (/usr/local/Redis/Redis-server)

也就可以看到,在 bgsave 執(zhí)行邏輯中,有一處打印日志中的 fprintf 調(diào)用了 mmap,很顯然這應(yīng)該是 fork 返回父進(jìn)程后,父進(jìn)程中某處調(diào)用。

6.2   Async-fork 適配優(yōu)化

針對(duì)找出來的代碼位置,可以進(jìn)行相應(yīng)優(yōu)化,針對(duì)此處的日志影響,我們可以屏蔽日志或者將日志移動(dòng)到子進(jìn)程進(jìn)行打印,通過同樣的分析手段,如果存在其他影響,均可進(jìn)行對(duì)應(yīng)優(yōu)化。進(jìn)行相應(yīng)適配優(yōu)化修改后,我們?cè)俅芜M(jìn)行測試。

測試環(huán)境

Redis 版本:優(yōu)化后 Redis-Server

機(jī)器操作系統(tǒng):Tair 專屬操作系統(tǒng)鏡像

測試數(shù)據(jù)量:54.38G

127.0.0.1:6680> info memory
# Memory
used_memory:58385641144
used_memory_human:54.38G

現(xiàn)象

在壓測過程中執(zhí)行 bgsave,fork 耗時(shí)和 TP100 均正常。

使用 info stats 返回上次 fork 耗時(shí):latest_fork_usec:414

TP100 結(jié)果如下:

# 壓測過程中執(zhí)行 bgsave
[root@xxx Redis]# /usr/bin/Redis-benchmark -d 256 -t set -n 1000000 -a dRedis123456 -p 6680
====== SET ======
1000000 requests completed in 7.50 seconds
50 parallel clients
256 bytes payload
keep alive: 1


99.99% <= 1 milliseconds
99.99% <= 2 milliseconds
100.00% <= 2 milliseconds
133386.69 requests per second

跟蹤驗(yàn)證

再次使用 strace 和 perf 工具跟蹤驗(yàn)證

strace 跟蹤父進(jìn)程只看到 clone,并且耗時(shí)只有 378 微秒,

# strace -p 14697 -T -tt -o strace04.out
14:42:00.723224 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fa5340d0a50) = 15470 <0.000378>

Perf trace 跟蹤父進(jìn)程也只看到 clone 調(diào)用

# perf trace -p 14697 -o trace04.out --max-stack 15 -T
618249694.830 ( 0.423 ms): Redis-server/14697 ... [continued]: clone()) = 15470 (Redis-server)
__GI___fork (inlined)
rdbSaveBackground (/usr/local/Redis/Redis-server)
bgsaveCommand (/usr/local/Redis/Redis-server)
call (/usr/local/Redis/Redis-server)
processCommand (/usr/local/Redis/Redis-server)
processInputBuffer (/usr/local/Redis/Redis-server)
aeProcessEvents (/usr/local/Redis/Redis-server)
aeMain (/usr/local/Redis/Redis-server)
main (/usr/local/Redis/Redis-server)

由于我們的優(yōu)化是將觸發(fā) mmap 的相關(guān)日志修改到子進(jìn)程中,使用 Perf trace 跟蹤 fork 產(chǎn)生的子進(jìn)程,命令為:

strace -p 14697 -T -tt -f -ff -o strace05.out

通過 Redis 日志文件找到子進(jìn)程 pid 為 15931;打開對(duì)應(yīng)生成的保存子進(jìn)程 strace 信息的文件strace05.out.15931(父進(jìn)程 strace 信息保存在文件strace05.out.14697)

# 以下為子進(jìn)程 strace 信息
14:47:40.878387 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5340da000 <0.000008>
14:47:40.878415 write(6, "15931:C 21 Mar 14:47:40.878 * Ba"..., 69) = 69 <0.000015>
14:47:40.878447 close(6) = 0 <0.000006>
14:47:40.878467 munmap(0x7fa5340da000, 4096) = 0 <0.000010>
14:47:40.878494 open("temp-15931.rdb", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6 <0.000020>
14:47:40.878563 fstat(6, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 <0.000006>
14:47:40.878584 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa5340da000 <0.000006>

在子進(jìn)程中看到了 mmap 調(diào)用,子進(jìn)程中調(diào)用不會(huì)影響父進(jìn)程對(duì)業(yè)務(wù)訪問的響應(yīng)。

7性能測試

修改 Redis 代碼,針對(duì) Async-fork 適配優(yōu)化后,我們針對(duì) fork 與 Async-fork 進(jìn)行了性能對(duì)比測試;測試包含不同數(shù)據(jù)量下 fork() 命令耗時(shí)與 fork() 操作對(duì)壓測過程中 TP100 的影響。

7.1   fork() 命令耗時(shí)

fork() 命令耗時(shí),即針對(duì) Redis 執(zhí)行 bgsave 命令后,通過 Redis 提供的 info stats命令觀察到的latest_fork_usec用時(shí)。

圖片

注:由于 fork 與 Async-fork 系統(tǒng)下,fork() 操作產(chǎn)生的latest_fork_usec數(shù)據(jù)差距懸殊非常大,使用單縱軸會(huì)導(dǎo)致 Async-fork 的數(shù)據(jù)在圖表中顯示不明顯,不方便查看,因此,該圖表使用了雙縱軸;雖然 Async-fork 的圖表看起來比較高,但是實(shí)際右縱軸范圍小,所以數(shù)據(jù)小

從圖表可以看出,使用支持 Async-fork 的操作系統(tǒng),fork() 操作產(chǎn)生的耗時(shí)非常小,不管數(shù)據(jù)量多大,耗時(shí)都非常穩(wěn)定,基本在 200 微秒左右;而原生 fork 產(chǎn)生的耗時(shí)會(huì)隨著數(shù)據(jù)量增長而增長,而且是從幾十毫秒增長到幾百毫秒。

7.2   TP100 抖動(dòng)

在使用 Redis-benchmark 壓測過程中,手動(dòng)執(zhí)行 bgsave 命令,觸發(fā)操作系統(tǒng) fork() 操作,觀察不同數(shù)據(jù)量下,fork 與 Async-fork 對(duì) Redis 壓測時(shí) TP100 的影響。

圖片

從圖上可以看出,使用支持 Async-fork 的操作系統(tǒng),fork() 操作對(duì) Redis 壓測產(chǎn)生的性能影響非常小,性能提升非常明顯,不管數(shù)據(jù)量多大,耗時(shí)都非常穩(wěn)定,基本在 1-2 毫秒左右;而原生 fork 產(chǎn)生的抖動(dòng)影響時(shí)間會(huì)隨著數(shù)據(jù)量增長而增長, TP100 從幾十毫秒增長到幾百毫秒。

8、總結(jié)

通過不同數(shù)據(jù)量下對(duì)比測試,我們可以看到,Async-fork 相比原生 fork,阻塞時(shí)間大大減少,性能提升非常明顯。而且阻塞時(shí)間非常穩(wěn)定,不會(huì)因?yàn)閿?shù)據(jù)量的增長出現(xiàn)倍數(shù)級(jí)增長。

在單機(jī)測試場景下,8G 數(shù)據(jù)量大小下,TP100 和latest_fork_usec 耗時(shí)均減少 98% 以上。

基于論文中 Async-fork 的設(shè)計(jì)思想,Tair 專屬操作系統(tǒng)鏡像已支持該特性,并且將該特性集成在原生 fork 中,沒有新增系統(tǒng)調(diào)用接口,理論上用戶只需要使用支持 Async-fork 的操作系統(tǒng),程序無需做任何修改,就可以享受到 Async-fork 特性帶來的性能提升。對(duì)于 Redis 而言,我們也只需要對(duì) Redis 稍加適配就可以獲得該技術(shù)帶來的紅利。

在 Redis 應(yīng)用場景中,在添加從節(jié)點(diǎn)、RDB 文件備份、AOF 持久化文件重寫等場景下,應(yīng)用支持 Async-fork 的操作系統(tǒng),都將極大的減少對(duì)業(yè)務(wù)的影響。

責(zé)任編輯:武曉燕 來源: 得物技術(shù)
相關(guān)推薦

2021-09-02 10:15:50

計(jì)算平臺(tái)MaxCompute 阿里云

2024-09-19 19:08:46

2020-06-28 10:16:53

PyTorchTensorFlow機(jī)器學(xué)習(xí)

2022-05-17 10:37:36

阿里云數(shù)據(jù)庫PolarDB-X

2022-07-12 10:37:08

阿里巴巴達(dá)摩院機(jī)器學(xué)習(xí)

2025-11-03 09:06:00

2021-10-13 17:53:14

AI 數(shù)據(jù)人工智能

2020-05-06 09:11:50

DevOps

2019-07-03 09:01:29

博士生頂會(huì)計(jì)算機(jī)

2025-11-03 09:02:00

AI模型論文

2024-07-18 21:21:29

2025-06-04 09:03:00

2025-07-01 13:52:19

2022-12-19 14:39:29

機(jī)器人論文

2025-07-03 01:45:00

LLMCoT思維鏈

2024-05-10 11:35:22

Redis延時(shí)隊(duì)列數(shù)據(jù)庫

2023-10-09 18:35:37

得物Redis架構(gòu)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

久久午夜精品视频| www.cao超碰| 婷婷丁香一区二区三区| 国产欧美日韩一区二区三区在线| 亚洲精品在线观| 日本韩国欧美在线观看| 黄色片在线看| 免费精品99久久国产综合精品| 中文字幕日韩av| 免费看三级黄色片| 惠美惠精品网| 国产精品对白交换视频| 亚洲一区亚洲二区亚洲三区| 日本少妇性高潮| 亚洲人成网www| 欧美日韩亚洲高清一区二区| 日本一区二区三区四区五区六区| 三级小视频在线观看| 日本伊人色综合网| 欧美疯狂做受xxxx高潮| 大黑人交xxx极品hd| 欧美综合影院| 精品久久久久久久久中文字幕| 欧美午夜精品久久久久久蜜| 国产av精国产传媒| 久久先锋影音| 欧美精品久久久久久久久| 性猛交娇小69hd| 亚洲午夜精品| 欧美日韩免费不卡视频一区二区三区 | 久久免费大视频| 日韩丝袜情趣美女图片| 中文字幕在线导航| 国产高清视频色在线www| 中文字幕一区在线观看视频| 鲁鲁视频www一区二区| www.国产三级| 蜜臀久久久99精品久久久久久| 欧美劲爆第一页| 你懂得视频在线观看| 一区二区美女| 亚洲电影成人av99爱色| 99999精品| 黑人一区二区三区| 在线亚洲一区观看| 亚洲国产精品久久久久爰色欲| 50度灰在线| 国产精品卡一卡二| 日本精品一区二区三区视频 | 日本在线啊啊| 亚洲综合网站在线观看| 在线免费观看一区二区三区| 国产中文字幕在线播放| 99久久久久久| 国产精品久久久久久久免费大片| 国产乱码一区二区| 捆绑调教一区二区三区| 国产精品成人国产乱一区| 91精品国产乱码在线观看| 精品91视频| 欧美激情一二区| 日本天堂中文字幕| 欧美在线亚洲| 色综合老司机第九色激情| 国产盗摄一区二区三区在线| 久久久久久久久99精品大| xxxx欧美18另类的高清| 日韩精品一区二区三区在线视频| 日韩欧美精品一区| 色噜噜狠狠色综合网图区| 色噜噜噜噜噜噜| 波多野结衣的一区二区三区| 伊人久久久久久久久久久| 日本乱子伦xxxx| 成久久久网站| 精品国产一区二区三区四区在线观看 | 91视频国产高清| 一级特黄色大片| 精品亚洲成a人在线观看| 国产精品香蕉在线观看| 在线观看国产小视频| 久久国产精品一区二区| 亚洲free性xxxx护士hd| 亚洲黄色在线播放| 99re这里只有精品首页| 区一区二区三区中文字幕 | 在线电影欧美日韩一区二区私密| a级大片在线观看| 精品久久精品| 久久视频中文字幕| 国产精彩视频在线| 日韩午夜在线电影| 国产精品99久久久久久人 | 亚洲一区亚洲| 国产97在线观看| 中文字幕在线播放不卡| 国模大尺度一区二区三区| 91文字幕巨乱亚洲香蕉| 香港一级纯黄大片| 国产精品理伦片| 久久国产精品网| 国产综合色区在线观看| 91精品国产高清一区二区三区| 国产伦理在线观看| 国产欧美日韩在线观看视频| 久久精品在线视频| 在线观看精品国产| 久久99最新地址| 国产精品免费一区二区三区| 国产免费av高清在线| 亚洲欧美福利一区二区| 99福利在线观看| 久久国产精品美女| 亚洲欧洲视频在线| 青青草国产在线观看| 久久国产直播| 高清不卡一区二区三区| av国产在线观看| 亚洲超碰97人人做人人爱| 91精品无人成人www| 成人盗摄视频| 久久久国产成人精品| 久久国产视频一区| 国产91精品久久久久久久网曝门| 日韩欧美国产二区| heyzo高清在线| 欧美亚洲自拍偷拍| 欧美肉大捧一进一出免费视频| 日韩中文在线电影| 91chinesevideo永久地址| 国产欧美一区二区三区视频在线观看| 91麻豆.com| av在线com| 午夜不卡一区| 国产亚洲精品美女| 国产69精品久久久久久久久久| 久久精品国产精品亚洲红杏 | 日本人视频jizz页码69| 欧美重口另类| 欧美华人在线视频| 国产露脸91国语对白| 久久九九久久九九| 久久网站免费视频| 精品久久ai| 欧美肥婆姓交大片| wwwav在线播放| 日韩一区欧美一区| 污污网站免费看| 精品freesex老太交| 欧美最猛性xxxx| 天堂在线资源网| 亚洲福利视频导航| 成人做爰69片免费| 亚洲视频福利| 国产精品美女久久久久av福利| 中国av在线播放| 欧美一区二区视频在线观看| 东方伊人免费在线观看| 日本va欧美va精品| 亚洲国产欧美日韩| 久久久久久久性潮| 久久精品小视频| 国产情侣在线播放| 亚洲美腿欧美偷拍| 男生和女生一起差差差视频| 综合一区av| 3d精品h动漫啪啪一区二区| 91精品久久| 日韩一级片在线观看| 18岁成人毛片| 成人视屏免费看| 黄页网站大全在线观看| 琪琪久久久久日韩精品| 青青久久av北条麻妃黑人 | 日韩亚洲欧美中文在线| 亚洲香蕉在线视频| 亚洲日本在线观看| 亚洲av无码成人精品区| 精品福利av| 蜜桃视频日韩| 成人国产一区| 久久av资源网站| 黄色福利在线观看| 懂色av影视一区二区三区| av黄色在线免费观看| 久久se这里有精品| 欧美高清中文字幕| 亚洲a级精品| 国产精品第一视频| 成人国产免费电影| 日韩高清av一区二区三区| 日本一本在线观看| 亚洲男同1069视频| 亚洲第一页av| 极品少妇一区二区| 蜜臀av无码一区二区三区| 国产探花在线精品| 亚洲最大的av网站| 三级在线看中文字幕完整版| 中文字幕久久亚洲| 精品国精品国产自在久不卡| 狠狠干狠狠久久| 亚洲精品天堂网| 丁香啪啪综合成人亚洲小说| 欧美综合在线观看视频| 91精品啪在线观看国产18 | 亚洲精品久久久久久久久久久久久久 | 日本黄色动态图| 日韩激情视频在线观看| 青青草综合视频| 自拍偷拍精品| 99国产在线| 成人性片免费| 性欧美xxxx交| 成人在线免费看黄| 亚洲欧美在线看| 黄频网站在线观看| 欧美日韩一卡二卡| 久久艹免费视频| 亚洲精品欧美专区| 欧美人妻一区二区三区| 成人精品视频一区二区三区 | 亚洲福利精品在线| 中文字幕a级片| 欧美日韩国产精品专区 | 亚洲一区二区三区激情| 在线观看亚洲大片短视频| 白白色亚洲国产精品| 中文字幕 欧美日韩| 老司机精品福利视频| 99热亚洲精品| 综合日韩在线| 在线观看成人av电影| 国产精品欧美日韩一区| 精品免费二区三区三区高中清不卡| 97久久中文字幕| 国产精品日日做人人爱| 麻豆成全视频免费观看在线看| 欧美精品免费在线| 麻豆视频在线| 中国日韩欧美久久久久久久久| 视频福利在线| 亚洲国产精品久久精品怡红院| av天堂一区二区三区| 欧美乱妇一区二区三区不卡视频| 久久国产乱子伦精品| 一本一道久久a久久精品综合蜜臀| 日本系列第一页| 亚洲午夜免费福利视频| 欧美精品99久久久| 亚洲免费观看高清| 福利所第一导航| 亚洲免费观看高清完整版在线 | 午夜精品一区二区三区在线播放 | 欧美日韩在线视频一区二区三区| 狠狠色狠狠色综合日日tαg| 9191国产视频| 午夜精品偷拍| 男人天堂a在线| 激情久久婷婷| 日韩av综合在线观看| 一本久道综合久久精品| 波多野结衣乳巨码无在线| 国产亚洲激情| 国产真实乱子伦| 日本在线不卡视频一二三区| 久久国产精品国产精品| 久久er99热精品一区二区| 91网址在线观看精品| 国产福利一区在线| 亚洲天堂av网站| 99国产欧美另类久久久精品| 久久人人爽人人爽人人片 | 性色国产成人久久久精品| 国产精品看片你懂得| 国产探花在线视频| 一区二区三区高清在线| 国产大片aaa| 色综合咪咪久久| 艳妇乳肉豪妇荡乳av无码福利 | 久久777国产线看观看精品| 日本动漫同人动漫在线观看| 久久免费视频这里只有精品| 高清在线视频不卡| 国产v综合ⅴ日韩v欧美大片 | 在线看国产日韩| 夜夜爽8888| 欧美大片免费久久精品三p| 天天操天天操天天| 国产一区二区三区毛片| 成人免费观看视频大全| 97视频在线观看网址| 另类中文字幕国产精品| 91久久久久久| 人妖一区二区三区| 图片区小说区区亚洲五月| 你懂的国产精品| 无码aⅴ精品一区二区三区浪潮 | 亚洲女性喷水在线观看一区| 久久精品欧美一区二区| 在线观看www91| av综合在线观看| 亚洲精品视频在线观看视频| 麻豆视频在线播放| 国产91精品久久久久| 欧美激情三区| 国产另类第一区| 水蜜桃精品av一区二区| 妞干网在线观看视频| 美国三级日本三级久久99| 激情综合激情五月| 国产欧美日韩亚州综合| 国产一级视频在线观看| 欧美丝袜丝nylons| 日本黄色不卡视频| 日韩视频在线免费| 不卡福利视频| 成人一区二区在线| 日韩在线二区| 国产精品69页| 成人免费毛片高清视频| 国产视频精品免费| 色综合久久中文字幕综合网| 亚洲精品视频91| 日韩一区二区久久久| 成人影院av| 国产视频在线观看一区| 亚洲精品97| 午夜免费福利在线| 久久亚区不卡日本| 久久久精品视频免费| 5566中文字幕一区二区电影| 激情福利在线| 欧美又大又粗又长| 国偷自产av一区二区三区| 国产激情在线看| 国产在线精品免费| 成人无码精品1区2区3区免费看| 日韩欧美中文在线| 手机看片1024国产| 欧美激情一区二区三区久久久| 2020国产精品小视频| 五月婷婷综合色| 久久尤物视频| 中出视频在线观看| 天天综合网天天综合色| 免费av一级片| 久久久久久久久国产精品| 天堂av一区| 黄色录像特级片| 国产高清久久久久| 欧美爱爱小视频| 欧美一卡二卡三卡| 中文av资源在线| 亚洲综合在线小说| 欧美日韩日本国产亚洲在线| 在线成人免费av| 一区二区三区 在线观看视频| 国产白浆在线观看| 欧美日韩福利视频| 大陆精大陆国产国语精品 | 黄色片免费在线观看| 国产在线观看91精品一区| 欧美激情欧美| 91 视频免费观看| 亚洲精品日韩综合观看成人91| 国产福利第一页| 欧美大片在线看| 六月丁香久久丫| 久热免费在线观看| 欧美激情资源网| 91成品人影院| 九九综合九九综合| 麻豆精品av| 日韩av在线综合| 中文字幕中文字幕一区二区| 国产精品久久欧美久久一区| 欧美成年人网站| 加勒比视频一区| 黄色免费观看视频网站| 国产午夜精品久久久久久免费视| 影音先锋国产资源| 久久99精品久久久久久琪琪| 麻豆一区二区| 欧美一级特黄a| 亚洲摸摸操操av| 无码国精品一区二区免费蜜桃| 国产成人高潮免费观看精品| 亚洲国产精品日韩专区av有中文| www.欧美com| 一本色道亚洲精品aⅴ| 香蕉视频在线看| 成人影片在线播放| 日韩不卡一区二区三区 | 久久神马影院| 国产麻豆剧传媒精品国产| 福利视频导航一区| 欧美私人网站| 国新精品乱码一区二区三区18| 日韩精品国产欧美|