成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Redis中萬(wàn)金油的String,為什么不好用了?

開發(fā) 前端
在這篇文章中,我們將顛覆以往對(duì) String 數(shù)據(jù)類型的傳統(tǒng)認(rèn)知。以前,String 被視為一種“萬(wàn)金油”,在各種場(chǎng)合都被廣泛使用。然而,當(dāng)存儲(chǔ)的鍵值對(duì)數(shù)據(jù)本身占用的內(nèi)存空間較小時(shí),String 類型的元數(shù)據(jù)開銷占據(jù)了主導(dǎo)地位。

今天,我們先了解下 String 類型的內(nèi)存空間消耗問(wèn)題,以及選擇節(jié)省內(nèi)存開銷的數(shù)據(jù)類型的解決方案。

我想和你分享一個(gè)之前我面臨的需求案例。

曾經(jīng),我們面臨著一個(gè)任務(wù),要?jiǎng)?chuàng)建一個(gè)高效的圖片存儲(chǔ)系統(tǒng),要求這個(gè)系統(tǒng)能夠快速記錄圖片 ID 和圖片在存儲(chǔ)系統(tǒng)中的唯一標(biāo)識(shí)(我們稱之為圖片存儲(chǔ)對(duì)象 ID)。此外,還需要能夠通過(guò)圖片 ID 快速檢索到相應(yīng)的圖片存儲(chǔ)對(duì)象 ID。

考慮到圖片數(shù)量龐大,我們決定使用 10 位數(shù)字來(lái)表示圖片 ID 和圖片存儲(chǔ)對(duì)象 ID。舉個(gè)例子,圖片 ID 可能是 1101000051,對(duì)應(yīng)的存儲(chǔ)對(duì)象 ID 則是 3301000051。

photo_id: 1101000051

photo_obj_id: 3301000051

這個(gè)案例很明顯地展現(xiàn)了“鍵 - 單值”模式。在這種模式中,每個(gè)鍵值對(duì)中的值都是一個(gè)單一的值,而不是一個(gè)值的集合,與 String 類型的數(shù)據(jù)存儲(chǔ)方式完美契合。

另外,String 類型的數(shù)據(jù)可以保存二進(jìn)制字節(jié)流,這使得它非常靈活,只需將數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制字節(jié)數(shù)組,就可以輕松地進(jìn)行存儲(chǔ)。

因此,我們的初始解決方案是使用 String 類型來(lái)存儲(chǔ)數(shù)據(jù)。我們將圖片 ID 和圖片存儲(chǔ)對(duì)象 ID 分別用作鍵值對(duì)中的鍵和值,其中圖片存儲(chǔ)對(duì)象 ID 使用了 String 類型。

最初,我們成功地存儲(chǔ)了一億張圖片,大約使用了 6.4GB 的內(nèi)存。但是,隨著圖片數(shù)據(jù)不斷增加,我們開始遇到了問(wèn)題,Redis 實(shí)例的內(nèi)存使用量不斷上升,導(dǎo)致生成 RDB 文件時(shí)出現(xiàn)延遲的情況。顯然,String 類型并不是一個(gè)適合大規(guī)模數(shù)據(jù)存儲(chǔ)的理想選擇,因此我們需要尋找更為節(jié)省內(nèi)存開銷的數(shù)據(jù)類型解決方案。

在這個(gè)過(guò)程中,我深入研究了 String 類型的底層結(jié)構(gòu),找出了它內(nèi)存開銷較大的原因。這讓我對(duì)這個(gè)“通用型”的 String 數(shù)據(jù)類型有了新的認(rèn)識(shí),它并不適用于所有情況,尤其在內(nèi)存空間消耗方面存在明顯短板。

與此同時(shí),我還仔細(xì)研究了集合類型的數(shù)據(jù)結(jié)構(gòu),發(fā)現(xiàn)它們具有非常高效的內(nèi)存管理結(jié)構(gòu)。但是,集合類型的數(shù)據(jù)結(jié)構(gòu)通常用于保存一鍵多值的數(shù)據(jù),不太適用于直接存儲(chǔ)單一鍵對(duì)應(yīng)的單一值。因此,我們采用了二級(jí)編碼的方法,成功地使用集合類型來(lái)存儲(chǔ)單一鍵值對(duì)。這種改變顯著降低了 Redis 實(shí)例的內(nèi)存開銷。

在本篇文章中,我將與你分享我在解決這一問(wèn)題過(guò)程中所獲得的經(jīng)驗(yàn)和方法,包括 String 類型的內(nèi)存開銷問(wèn)題,可節(jié)省內(nèi)存的數(shù)據(jù)結(jié)構(gòu)選擇,以及如何使用集合類型來(lái)存儲(chǔ)單一鍵值對(duì)。如果你在使用 String 類型時(shí)也遇到了內(nèi)存開銷較大的問(wèn)題,那么今天的解決方案可能會(huì)對(duì)你有所幫助。

接下來(lái),我們先來(lái)看看 String 類型的內(nèi)存都消耗在哪里了。

為什么 String 類型內(nèi)存開銷大?

在剛才的案例中,我們保存了 1 億張圖片的信息,用了約 6.4GB 的內(nèi)存,一個(gè)圖片 ID 和圖片存儲(chǔ)對(duì)象 ID 的記錄平均用了 64 字節(jié)。

但問(wèn)題是,一組圖片 ID 及其存儲(chǔ)對(duì)象 ID 的記錄,實(shí)際只需要 16 字節(jié)就可以了。

我們來(lái)分析一下。圖片 ID 和圖片存儲(chǔ)對(duì)象 ID 都是 10 位數(shù),我們可以用兩個(gè) 8 字節(jié)的 Long 類型表示這兩個(gè) ID。因?yàn)?8 字節(jié)的 Long 類型最大可以表示 2 的 64 次方的數(shù)值,所以肯定可以表示 10 位數(shù)。但是,為什么 String 類型卻用了 64 字節(jié)呢?

其實(shí),除了記錄實(shí)際數(shù)據(jù),String 類型還需要額外的內(nèi)存空間記錄數(shù)據(jù)長(zhǎng)度、空間使用等信息,這些信息也叫作元數(shù)據(jù)。當(dāng)實(shí)際保存的數(shù)據(jù)較小時(shí),元數(shù)據(jù)的空間開銷就顯得比較大了,有點(diǎn)“喧賓奪主”的意思。

那么,String 類型具體是怎么保存數(shù)據(jù)的呢?我來(lái)解釋一下。

當(dāng)你保存 64 位有符號(hào)整數(shù)時(shí),String 類型會(huì)把它保存為一個(gè) 8 字節(jié)的 Long 類型整數(shù),這種保存方式通常也叫作 int 編碼方式。

但是,當(dāng)你保存的數(shù)據(jù)中包含字符時(shí),String 類型就會(huì)用簡(jiǎn)單動(dòng)態(tài)字符串(Simple Dynamic String,SDS)結(jié)構(gòu)體來(lái)保存,如下圖所示:

圖片圖片

buf:字節(jié)數(shù)組,保存實(shí)際數(shù)據(jù)。為了表示字節(jié)數(shù)組的結(jié)束,Redis 會(huì)自動(dòng)在數(shù)組最后加一個(gè)“\0”,這就會(huì)額外占用 1 個(gè)字節(jié)的開銷。

len:占 4 個(gè)字節(jié),表示 buf 的已用長(zhǎng)度。

alloc:也占個(gè) 4 字節(jié),表示 buf 的實(shí)際分配長(zhǎng)度,一般大于 len。

可以看到,在 SDS 中,buf 保存實(shí)際數(shù)據(jù),而 len 和 alloc 本身其實(shí)是 SDS 結(jié)構(gòu)體的額外開銷。

另外,對(duì)于 String 類型來(lái)說(shuō),除了 SDS 的額外開銷,還有一個(gè)來(lái)自于 RedisObject 結(jié)構(gòu)體的開銷。

因?yàn)?Redis 的數(shù)據(jù)類型有很多,而且,不同數(shù)據(jù)類型都有些相同的元數(shù)據(jù)要記錄(比如最后一次訪問(wèn)的時(shí)間、被引用的次數(shù)等),所以,Redis 會(huì)用一個(gè) RedisObject 結(jié)構(gòu)體來(lái)統(tǒng)一記錄這些元數(shù)據(jù),同時(shí)指向?qū)嶋H數(shù)據(jù)。

一個(gè) RedisObject 包含了 8 字節(jié)的元數(shù)據(jù)和一個(gè) 8 字節(jié)指針,這個(gè)指針再進(jìn)一步指向具體數(shù)據(jù)類型的實(shí)際數(shù)據(jù)所在,例如指向 String 類型的 SDS 結(jié)構(gòu)所在的內(nèi)存地址,可以看一下下面的示意圖。關(guān)于 RedisObject 的具體結(jié)構(gòu)細(xì)節(jié),我會(huì)在后面的課程中詳細(xì)介紹,現(xiàn)在你只要了解它的基本結(jié)構(gòu)和元數(shù)據(jù)開銷就行了。

圖片圖片

為了節(jié)省內(nèi)存空間,Redis 還對(duì) Long 類型整數(shù)和 SDS 的內(nèi)存布局做了專門的設(shè)計(jì)。

一方面,當(dāng)保存的是 Long 類型整數(shù)時(shí),RedisObject 中的指針就直接賦值為整數(shù)數(shù)據(jù)了,這樣就不用額外的指針再指向整數(shù)了,節(jié)省了指針的空間開銷。

另一方面,當(dāng)保存的是字符串?dāng)?shù)據(jù),并且字符串小于等于 44 字節(jié)時(shí),RedisObject 中的元數(shù)據(jù)、指針和 SDS 是一塊連續(xù)的內(nèi)存區(qū)域,這樣就可以避免內(nèi)存碎片。這種布局方式也被稱為 embstr 編碼方式。

當(dāng)然,當(dāng)字符串大于 44 字節(jié)時(shí),SDS 的數(shù)據(jù)量就開始變多了,Redis 就不再把 SDS 和 RedisObject 布局在一起了,而是會(huì)給 SDS 分配獨(dú)立的空間,并用指針指向 SDS 結(jié)構(gòu)。這種布局方式被稱為 raw 編碼模式。

為了幫助你理解 int、embstr 和 raw 這三種編碼模式,我畫了一張示意圖,如下所示:

圖片圖片

好了,知道了 RedisObject 所包含的額外元數(shù)據(jù)開銷,現(xiàn)在,我們就可以計(jì)算 String 類型的內(nèi)存使用量了。

因?yàn)?10 位數(shù)的圖片 ID 和圖片存儲(chǔ)對(duì)象 ID 是 Long 類型整數(shù),所以可以直接用 int 編碼的 RedisObject 保存。每個(gè) int 編碼的 RedisObject 元數(shù)據(jù)部分占 8 字節(jié),指針部分被直接賦值為 8 字節(jié)的整數(shù)了。此時(shí),每個(gè) ID 會(huì)使用 16 字節(jié),加起來(lái)一共是 32 字節(jié)。但是,另外的 32 字節(jié)去哪兒了呢?

Redis 會(huì)使用一個(gè)全局哈希表保存所有鍵值對(duì),哈希表的每一項(xiàng)是一個(gè) dictEntry 的結(jié)構(gòu)體,用來(lái)指向一個(gè)鍵值對(duì)。dictEntry 結(jié)構(gòu)中有三個(gè) 8 字節(jié)的指針,分別指向 key、value 以及下一個(gè) dictEntry,三個(gè)指針共 24 字節(jié),如下圖所示:

圖片圖片

但是,這三個(gè)指針只有 24 字節(jié),為什么會(huì)占用了 32 字節(jié)呢?這就要提到 Redis 使用的內(nèi)存分配庫(kù) jemalloc 了。

jemalloc 在分配內(nèi)存時(shí),會(huì)根據(jù)我們申請(qǐng)的字節(jié)數(shù) N,找一個(gè)比 N 大,但是最接近 N 的 2 的冪次數(shù)作為分配的空間,這樣可以減少頻繁分配的次數(shù)。

舉個(gè)例子。如果你申請(qǐng) 6 字節(jié)空間,jemalloc 實(shí)際會(huì)分配 8 字節(jié)空間;如果你申請(qǐng) 24 字節(jié)空間,jemalloc 則會(huì)分配 32 字節(jié)。所以,在我們剛剛說(shuō)的場(chǎng)景里,dictEntry 結(jié)構(gòu)就占用了 32 字節(jié)。

好了,到這兒,你應(yīng)該就能理解,為什么用 String 類型保存圖片 ID 和圖片存儲(chǔ)對(duì)象 ID 時(shí)需要用 64 個(gè)字節(jié)了。

你看,明明有效信息只有 16 字節(jié),使用 String 類型保存時(shí),卻需要 64 字節(jié)的內(nèi)存空間,有 48 字節(jié)都沒(méi)有用于保存實(shí)際的數(shù)據(jù)。我們來(lái)?yè)Q算下,如果要保存的圖片有 1 億張,那么 1 億條的圖片 ID 記錄就需要 6.4GB 內(nèi)存空間,其中有 4.8GB 的內(nèi)存空間都用來(lái)保存元數(shù)據(jù)了,額外的內(nèi)存空間開銷很大。那么,有沒(méi)有更加節(jié)省內(nèi)存的方法呢?

用什么數(shù)據(jù)結(jié)構(gòu)可以節(jié)省內(nèi)存?

Redis 有一種底層數(shù)據(jù)結(jié)構(gòu),叫壓縮列表(ziplist),這是一種非常節(jié)省內(nèi)存的結(jié)構(gòu)。

我們先回顧下壓縮列表的構(gòu)成。表頭有三個(gè)字段 zlbytes、zltail 和 zllen,分別表示列表長(zhǎng)度、列表尾的偏移量,以及列表中的 entry 個(gè)數(shù)。壓縮列表尾還有一個(gè) zlend,表示列表結(jié)束。

圖片圖片

壓縮列表之所以能節(jié)省內(nèi)存,就在于它是用一系列連續(xù)的 entry 保存數(shù)據(jù)。每個(gè) entry 的元數(shù)據(jù)包括下面幾部分。

prev_len,表示前一個(gè) entry 的長(zhǎng)度。prev_len 有兩種取值情況:1 字節(jié)或 5 字節(jié)。取值 1 字節(jié)時(shí),表示上一個(gè) entry 的長(zhǎng)度小于 254 字節(jié)。雖然 1 字節(jié)的值能表示的數(shù)值范圍是 0 到 255,但是壓縮列表中 zlend 的取值默認(rèn)是 255,因此,就默認(rèn)用 255 表示整個(gè)壓縮列表的結(jié)束,其他表示長(zhǎng)度的地方就不能再用 255 這個(gè)值了。所以,當(dāng)上一個(gè) entry 長(zhǎng)度小于 254 字節(jié)時(shí),prev_len 取值為 1 字節(jié),否則,就取值為 5 字節(jié)。

len:表示自身長(zhǎng)度,4 字節(jié);

encoding:表示編碼方式,1 字節(jié);

content:保存實(shí)際數(shù)據(jù)。

這些 entry 會(huì)挨個(gè)兒放置在內(nèi)存中,不需要再用額外的指針進(jìn)行連接,這樣就可以節(jié)省指針?biāo)加玫目臻g。

我們以保存圖片存儲(chǔ)對(duì)象 ID 為例,來(lái)分析一下壓縮列表是如何節(jié)省內(nèi)存空間的。

每個(gè) entry 保存一個(gè)圖片存儲(chǔ)對(duì)象 ID(8 字節(jié)),此時(shí),每個(gè) entry 的 prev_len 只需要 1 個(gè)字節(jié)就行,因?yàn)槊總€(gè) entry 的前一個(gè) entry 長(zhǎng)度都只有 8 字節(jié),小于 254 字節(jié)。這樣一來(lái),一個(gè)圖片的存儲(chǔ)對(duì)象 ID 所占用的內(nèi)存大小是 14 字節(jié)(1+4+1+8=14),實(shí)際分配 16 字節(jié)。

Redis 基于壓縮列表實(shí)現(xiàn)了 List、Hash 和 Sorted Set 這樣的集合類型,這樣做的最大好處就是節(jié)省了 dictEntry 的開銷。當(dāng)你用 String 類型時(shí),一個(gè)鍵值對(duì)就有一個(gè) dictEntry,要用 32 字節(jié)空間。但采用集合類型時(shí),一個(gè) key 就對(duì)應(yīng)一個(gè)集合的數(shù)據(jù),能保存的數(shù)據(jù)多了很多,但也只用了一個(gè) dictEntry,這樣就節(jié)省了內(nèi)存。

這個(gè)方案聽(tīng)起來(lái)很好,但還存在一個(gè)問(wèn)題:在用集合類型保存鍵值對(duì)時(shí),一個(gè)鍵對(duì)應(yīng)了一個(gè)集合的數(shù)據(jù),但是在我們的場(chǎng)景中,一個(gè)圖片 ID 只對(duì)應(yīng)一個(gè)圖片的存儲(chǔ)對(duì)象 ID,我們?cè)撛趺从眉项愋湍兀繐Q句話說(shuō),在一個(gè)鍵對(duì)應(yīng)一個(gè)值(也就是單值鍵值對(duì))的情況下,我們?cè)撛趺从眉项愋蛠?lái)保存這種單值鍵值對(duì)呢?

如何用集合類型保存單值的鍵值對(duì)?

在保存單值的鍵值對(duì)時(shí),可以采用基于 Hash 類型的二級(jí)編碼方法。這里說(shuō)的二級(jí)編碼,就是把一個(gè)單值的數(shù)據(jù)拆分成兩部分,前一部分作為 Hash 集合的 key,后一部分作為 Hash 集合的 value,這樣一來(lái),我們就可以把單值數(shù)據(jù)保存到 Hash 集合中了。

以圖片 ID 1101000060 和圖片存儲(chǔ)對(duì)象 ID 3302000080 為例,我們可以把圖片 ID 的前 7 位(1101000)作為 Hash 類型的鍵,把圖片 ID 的最后 3 位(060)和圖片存儲(chǔ)對(duì)象 ID 分別作為 Hash 類型值中的 key 和 value。

按照這種設(shè)計(jì)方法,我在 Redis 中插入了一組圖片 ID 及其存儲(chǔ)對(duì)象 ID 的記錄,并且用 info 命令查看了內(nèi)存開銷,我發(fā)現(xiàn),增加一條記錄后,內(nèi)存占用只增加了 16 字節(jié),如下所示:

127.0.0.1:6379> info memory
# Memory
used_memory:1039120
127.0.0.1:6379> hset 1101000 060 3302000080
(integer) 1
127.0.0.1:6379> info memory
# Memory
used_memory:1039136

在使用 String 類型時(shí),每個(gè)記錄需要消耗 64 字節(jié),這種方式卻只用了 16 字節(jié),所使用的內(nèi)存空間是原來(lái)的 1/4,滿足了我們節(jié)省內(nèi)存空間的需求。

不過(guò),你可能也會(huì)有疑惑:“二級(jí)編碼一定要把圖片 ID 的前 7 位作為 Hash 類型的鍵,把最后 3 位作為 Hash 類型值中的 key 嗎?”其實(shí),二級(jí)編碼方法中采用的 ID 長(zhǎng)度是有講究的

Redis Hash 類型的兩種底層實(shí)現(xiàn)結(jié)構(gòu),分別是壓縮列表和哈希表。

那么,Hash 類型底層結(jié)構(gòu)什么時(shí)候使用壓縮列表,什么時(shí)候使用哈希表呢?其實(shí),Hash 類型設(shè)置了用壓縮列表保存數(shù)據(jù)時(shí)的兩個(gè)閾值,一旦超過(guò)了閾值,Hash 類型就會(huì)用哈希表來(lái)保存數(shù)據(jù)了。

這兩個(gè)閾值分別對(duì)應(yīng)以下兩個(gè)配置項(xiàng):

hash-max-ziplist-entries:表示用壓縮列表保存時(shí)哈希集合中的最大元素個(gè)數(shù)。

hash-max-ziplist-value:表示用壓縮列表保存時(shí)哈希集合中單個(gè)元素的最大長(zhǎng)度。

如果我們往 Hash 集合中寫入的元素個(gè)數(shù)超過(guò)了 hash-max-ziplist-entries,或者寫入的單個(gè)元素大小超過(guò)了 hash-max-ziplist-value,Redis 就會(huì)自動(dòng)把 Hash 類型的實(shí)現(xiàn)結(jié)構(gòu)由壓縮列表轉(zhuǎn)為哈希表。

一旦從壓縮列表轉(zhuǎn)為了哈希表,Hash 類型就會(huì)一直用哈希表進(jìn)行保存,而不會(huì)再轉(zhuǎn)回壓縮列表了。在節(jié)省內(nèi)存空間方面,哈希表就沒(méi)有壓縮列表那么高效了。

為了能充分使用壓縮列表的精簡(jiǎn)內(nèi)存布局,我們一般要控制保存在 Hash 集合中的元素個(gè)數(shù)。所以,在剛才的二級(jí)編碼中,我們只用圖片 ID 最后 3 位作為 Hash 集合的 key,也就保證了 Hash 集合的元素個(gè)數(shù)不超過(guò) 1000,同時(shí),我們把 hash-max-ziplist-entries 設(shè)置為 1000,這樣一來(lái),Hash 集合就可以一直使用壓縮列表來(lái)節(jié)省內(nèi)存空間了。

小結(jié)

在這篇文章中,我們將顛覆以往對(duì) String 數(shù)據(jù)類型的傳統(tǒng)認(rèn)知。以前,String 被視為一種“萬(wàn)金油”,在各種場(chǎng)合都被廣泛使用。然而,當(dāng)存儲(chǔ)的鍵值對(duì)數(shù)據(jù)本身占用的內(nèi)存空間較小時(shí),String 類型的元數(shù)據(jù)開銷占據(jù)了主導(dǎo)地位。這些開銷包括 RedisObject 結(jié)構(gòu)、SDS 結(jié)構(gòu)以及dictEntry 結(jié)構(gòu)的內(nèi)存消耗。

為了應(yīng)對(duì)這種情況,我們可以采用壓縮列表(ziplist)來(lái)存儲(chǔ)數(shù)據(jù)。當(dāng)然,當(dāng)使用 Hash 這種集合類型來(lái)保存單一鍵值對(duì)數(shù)據(jù)時(shí),我們需要將單一值數(shù)據(jù)分割成兩部分,分別作為 Hash 集合的鍵和值。就像之前案例中使用了二級(jí)編碼來(lái)表示圖片 ID那樣,我們鼓勵(lì)你將這一方法應(yīng)用到你的具體場(chǎng)景中。這不僅可以減少內(nèi)存開銷,還能提高 Redis 的性能。希望這個(gè)解決方案對(duì)你的應(yīng)用有所幫助。

責(zé)任編輯:武曉燕 來(lái)源: 碼農(nóng)本農(nóng)
相關(guān)推薦

2020-04-28 17:13:12

箭頭函數(shù)ES6函數(shù)

2020-11-02 17:34:22

數(shù)據(jù)分析人工智能技術(shù)

2023-06-30 07:19:25

電源供電顯卡

2021-06-29 07:19:06

Redis容器化K8S

2021-06-29 15:39:16

容器技術(shù)Redis

2014-10-20 10:53:13

ArubaWi-Fi無(wú)線網(wǎng)絡(luò)

2023-03-13 00:21:21

調(diào)試器斷點(diǎn)開發(fā)者

2024-12-26 09:58:18

2025-04-24 08:25:00

2023-10-25 16:36:06

數(shù)字化轉(zhuǎn)型IT系統(tǒng)

2021-01-28 14:41:08

麥肯錫數(shù)字化項(xiàng)目

2021-12-15 10:20:08

緩存架構(gòu)開發(fā)

2021-08-16 13:44:37

手機(jī)電子日本

2021-11-08 11:21:18

redis 淘汰算法

2018-07-01 08:34:09

緩存數(shù)據(jù)服務(wù)

2022-06-07 17:01:31

UI框架前端

2013-02-22 09:43:41

面向?qū)ο?/a>面向?qū)ο缶幊?/a>

2019-10-15 09:46:46

機(jī)器學(xué)習(xí)人工智能計(jì)算機(jī)

2025-01-20 08:10:00

AI模型研究

2021-05-13 09:27:13

JavaThreadLocal線程
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 欧美视频一区二区三区 | 午夜99| www.伊人.com| 99视频免费在线 | 精品国产乱码久久久久久丨区2区 | 国产精品久久久久久久久久免费看 | 亚洲日韩中文字幕一区 | 91在线精品视频 | 日韩伦理一区二区 | 日韩精品一区二区三区在线观看 | 少妇诱惑av | 蜜桃一区二区三区 | 国产综合精品 | 91免费视频| 久久久久资源 | a级片在线观看 | 美女三区 | 午夜视频一区 | 日韩欧美在线一区 | 日韩欧美亚洲 | 亚洲精品久久久一区二区三区 | 国产一级一片免费播放 | 国产天堂 | 免费成人在线网站 | 久久久高清 | 91视在线国内在线播放酒店 | 国产又爽又黄的视频 | 黄色在线免费观看 | 国产精品久久久久久52avav | 九九视频网 | 欧美成人免费在线 | 久久久青草婷婷精品综合日韩 | 亚洲综合一区二区三区 | 一级片免费视频 | 久草视 | 成人深夜福利 | 国产线视频精品免费观看视频 | 黄色av网站免费看 | 色吊丝2288sds中文字幕 | 日本在线视频一区二区 | 国产精品福利在线 |