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

Redis 內存優化在 vivo 的探索與實踐

開發
本文主要是通過分析 Redis內存結構、介紹內存優化手段,同時結合生產案例,幫助大家在優化內存使用,快速定位 Redis 相關內存異常問題。

作者:互聯網服務器團隊- Tang Wenjian

一、 背景

使用過 Redis 的同學應該都知道,它基于鍵值對(key-value)的內存數據庫,所有數據存放在內存中,內存在 Redis 中扮演一個核心角色,所有的操作都是圍繞它進行。

我們在實際維護過程中經常會被問到如下問題,比如數據怎么存儲在 Redis 里面能節約成本、提升性能?Redis內存告警是什么原因導致?

本文主要是通過分析 Redis內存結構、介紹內存優化手段,同時結合生產案例,幫助大家在優化內存使用,快速定位 Redis 相關內存異常問題。

二、 Redis 內存管理

本章詳細介紹 Redis 是怎么管理各內存結構的,然后主要介紹幾個占用內存可能比較多的內存結構。首先我們看下Redis 的內存模型。

內存模型如圖:

  • 【used_memory】:Redis內存占用中最主要的部分,Redis分配器分配的內存總量(單位是KB)(在編譯時指定編譯器,默認是jemalloc),主要包含自身內存(字典、元數據)、對象內存、緩存,lua內存。
  • 【自身內存】:自身維護的一些數據字典及元數據,一般占用內存很低。
  • 【對象內存】:所有對象都是Key-Value型,Key對象都是字符串,Value對象則包括5種類(String,List,Hash,Set,Zset),5.0還支持stream類型。
  • 【緩存】:客戶端緩沖區(普通 + 主從復制 + pubsub)以及aof緩沖區。
  • 【Lua內存】:主要是存儲加載的 Lua 腳本,內存使用量和加載的 Lua 腳本數量有關。
  • 【used_memory_rss】:Redis 主進程占據操作系統的內存(單位是KB),是從操作系統角度得到的值,如top、ps等命令。
  • 【內存碎片】:如果對數據的更改頻繁,可能導致redis釋放的空間在物理內存中并沒有釋放,但redis又無法有效利用,這就形成了內存碎片。
  • 【運行內存】:運行時消耗的內存,一般占用內存較低,在10M內。
  • 【子進程內存】:主要是在持久化的時候,aof rewrite或者rdb產生的子進程消耗的內存,一般也是比較小。

2.1 對象內存

對象內存存儲 Redis 所有的key-value型數據類型,key對象都是 string 類型,value對象主要有五種數據類型String、List、Hash、Set、Zset,不同類型的對象通過對應的編碼各種封裝,對外定義為RedisObject結構體,RedisObject都是由字典(Dict)保存的,而字典底層是通過哈希表來實現的。通過哈希表中的節點保存字典中的鍵值對,結構如下:

(來源:書籍《Redis設計與實現》)

為了達到極大的提高 Redis 的靈活性和效率,Redis 根據不同的使用場景來對一個對象設置不同的編碼,從而優化某一場景下的效率。

各類對象選擇編碼的規則如下:

string (字符串)

  • 【int】:(整數且數字長度小于20,直接記錄在ptr*里面)
  • 【embstr】: (連續分配的內存(字符串長度小于等于44字節的字符串))
  • 【raw】: 動態字符串(大于44個字節的字符串,同時字符長度小于 512M(512M是字符串的大小限制))

list (列表)

  • 【ziplist】:(元素個數小于hash-max-ziplist-entries配置(默認512個),同時所有值都小于hash-max-ziplist-value配置(默認64個字節))
  • 【linkedlist】:(當列表類型無法滿足ziplist的條件時,Redis會使用linkedlist作為列表的內部實現)
  • 【quicklist】:(Redis 3.2 版本引入了 quicklist 作為 list 的底層實現,不再使用 linkedlist 和 ziplist 實現)

set (集合)

  • 【intset 】:(元素都是整數且元素個數小于set-max-intset-entries配置(默認512個))
  • 【hashtable】:(集合類型無法滿足intset的條件時就會使用hashtable)

hash (hash列表)

  • 【ziplist】:(元素個數小于hash-max-ziplist-entries配置(默認512個),同時任意一個value的長度都小于hash-max-ziplist-value配置(默認64個字節))
  • 【hashtable】:(hash類型無法滿足intset的條件時就會使用hashtable

zset(有序集合)

  • 【ziplist】:(元素個數小于zset-max-ziplist-entries配置(默認128個)同時每個元素的value小于zset-max-ziplist-value配置(默認64個字節))
  • 【skiplist】:(當ziplist條件不滿足時,有序集合會使用skiplist作為內部實現)

2.2 緩沖內存

2.2 1 客戶端緩存

客戶端緩沖指的是所有接入 Redis 服務的 TCP 連接的輸入輸出緩沖。有普通客戶端緩沖、主從復制緩沖、訂閱緩沖,這些都由對應的參數緩沖控制大小(輸入緩沖無參數控制,最大空間為1G),若達到設定的最大值,客戶端將斷開。

【client-output-buffer-limit】: 限制客戶端輸出緩存的大小,后面接客戶端種類(normal、slave、pubsub)及限制大小,默認是0,不做限制,如果做了限制,達到閾值之后,會斷開鏈接,釋放內存。

【repl-backlog-size】:默認是1M,backlog是一個主從復制的緩沖區,是一個環形buffer,假設達到設置的閾值,不存在溢出的問題,會循環覆蓋,比如slave中斷過程中同步數據沒有被覆蓋,執行增量同步就可以。backlog設置的越大,slave可以失連的時間就越長,受參數maxmemory限制,正常不要設置太大。

2.2 2 AOF 緩沖

當我們開啟了 AOF 的時候,先將客戶端傳來的命令存放在AOF緩沖區,再去根據具體的策略(always、everysec、no)去寫入磁盤中的 AOF 文件中,同時記錄刷盤時間。

AOF 緩沖沒法限制,也不需要限制,因為主線程每次進行 AOF會對比上次刷盤成功的時間;如果超過2s,則主線程阻塞直到fsync同步完成,主線程被阻塞的時候,aof_delayed_fsync狀態變量記錄會增加。因此 AOF 緩存只會存幾秒時間的數據,消耗內存比較小。

2.3 內存碎片

程序出現內存碎片是個很常見的問題,Redis的默認分配器是jemalloc ,它的策略是按照一系列固定的大小劃分內存空間,例如 8 字節、16 字節、32 字節、…, 4KB、8KB 等。當程序申請的內存最接近某個固定值時,jemalloc 會給它分配比它大一點的固定大小的空間,所以會產生一些碎片,另外在刪除數據的時候,釋放的內存不會立刻返回給操作系統,但redis自己又無法有效利用,就形成碎片。

內存碎片不會被統計在used_memory中,內存碎片比率在redis info里面記錄了一個動態值mem_fragmentation_ratio,該值是used_memory_rss / used_memory的比值, mem_fragmentation_ratio越接近1,碎片率越低,正常值在1~1.5內,超過了說明碎片很多。

2.4 子進程內存

前面提到子進程主要是為了生成 RDB 和 AOF rewrite產生的子進程,也會占用一定的內存,但是在這個過程中寫操作不頻繁的情況下內存占用較少,寫操作很頻繁會導致占用內存較多。

三、Redis 內存優化

內存優化的對象主要是對象內存、客戶端緩沖、內存碎片、子進程內存等幾個方面,因為這幾個內存消耗比較大或者有的時候不穩定,我們優化內存的方向分為如:減少內存使用、提高性能、減少內存異常發生。

3.1 對象內存優化

對象內存的優化可以降低內存使用率,提高性能,優化點主要針對不同對象不同編碼的選擇上做優化。

在優化前,我們可以了解下如下的一些知識點:

(1)首先是字符串類型的3種編碼,int編碼除了自身object無需分配內存,object 的指針不需要指向其他內存空間,無論是從性能還是內存使用都是最優的,embstr是會分配一塊連續的內存空間,但是假設這個value有任何變化,那么value對象會變成raw編碼,而且是不可逆的。

(2)ziplist 存儲 list 時每個元素會作為一個 entry; 存儲 hash 時 key 和 value 會作為相鄰的兩個 entry; 存儲 zset 時 member 和 score 會作為相鄰的兩個entry,當不滿足上述條件時,ziplist 會升級為 linkedlist, hashtable 或 skiplist 編碼。

(3)在任何情況下大內存的編碼都不會降級為 ziplist。

(4)linkedlist 、hashtable 便于進行增刪改操作但是內存占用較大。

(5)ziplist 內存占用較少,但是因為每次修改都可能觸發 realloc 和 memcopy, 可能導致連鎖更新(數據可能需要挪動)。因此修改操作的效率較低,在 ziplist 的條目很多時這個問題更加突出。

(6)由于目前大部分redis運行的版本都是在3.2以上,所以 List 類型的編碼都是quicklist,它是 ziplist 組成的雙向鏈表linkedlist ,它的每個節點都是一個ziplist,考慮了綜合平衡空間碎片和讀寫性能兩個維度所以使用了個新編碼quicklist,quicklist有個比較重要的參數list-max-ziplist-size,當它取正數的時候,正數表示限制每個節點ziplist中的entry數量,如果是負數則只能為-1~-5,限制ziplist大小,從-1~-5的限制分別為4kb、8kb、16kb、32kb、64kb,默認是-2,也就是限制不超過8kb。

(7)【rehash】: redis存儲底層很多是hashtable,客戶端可以根據key計算的hash值找到對應的對象,但是當數據量越來越大的時候,可能就會存在多個key計算的hash值相同,這個時候這些相同的hash值就會以鏈表的形式存放,如果這個鏈表過大,那么遍歷的時候性能就會下降,所以Redis定義了一個閾值(負載因子 loader_factor = 哈希表中鍵值對數量 / 哈希表長度),會觸發漸進式的rehash,過程是新建一個更大的新hashtable,然后把數據逐步移動到新hashtable中。

(8)【bigkey】:bigkey一般指的是value的值占用內存空間很大,但是這個大小其實沒有一個固定的標準,我們自己定義超過10M就可以稱之為bigkey。

優化建議:

(1)key盡量控制在44個字節數內,走embstr編碼,embstr比raw編碼減少一次內存分配,同時因為是連續內存存儲,性能會更好。

(2)多個string類型可以合并成小段hash類型去維護,小的hash類型走ziplist是有很好的壓縮效果,節約內存。

(3)非string的類型的value對象的元素個數盡量不要太多,避免產生大key。

(4)在value的元素較多且頻繁變動,不要使用ziplist編碼,因為ziplist是連續的內存分配,對頻繁更新的對象并不友好,性能損耗反而大。

(5)hash類型對象包含的元素不要太多,避免在rehash的時候消耗過多內存。

(6)盡量不要修改ziplist限制的參數值,因為ziplist編碼雖然可以對內存有很好的壓縮,但是如果元素太多使用ziplist的話,性能可能會有所下降。

3.2 客戶端緩沖優化

客戶端緩存是很多內存異常增長的罪魁禍首,大部分都是普通客戶端輸出緩沖區異常增長導致,我們先了解下執行命令的過程,客戶端發送一個或者通過piplie發送一組請求命令給服務端,然后等待服務端的響應,一般客戶端使用阻塞模式來等待服務端響應,數據在被客戶端讀取前,數據是存放在客戶端緩存區,命令執行的簡易流程圖如下:

異常增長原因可能如下幾種:

  • 客戶端訪問大key 導致客戶端輸出緩存異常增長。
  • 客戶端使用monitor命令訪問Redis,monitor命令會把所有訪問redis的命令持續存放到輸出緩沖區,導致輸出緩沖區異常增長。
  • 客戶端為了加快訪問效率,使用pipline封裝了大量命令,導致返回的結果集異常大(pipline的特性是等所有命令全部執行完才返回,返回前都是暫存在輸出緩存區)。
  • 從節點應用數據較慢,導致輸出主從復制輸出緩存有很多數據積壓,最后導致緩沖區異常增長。

異常表現:

  • 在Redis的info命令返回的結果里面,client部分client_recent_max_output_buffer的值很大。
  • 在執行client list命令返回的結果集里面,omem不為0且很大,omem代表該客戶端的輸出代表緩存使用的字節數。
  • 在集群中,可能少部分used_memory在監控顯示存在異常增長,因為不管是monitor或者pipeline都是針對單個實例的下發的命令。

優化建議:

  • 應用不要設計大key,大key盡量拆分。
  • 服務端的普通客戶端輸出緩存區通過參數設置,因為內存告警的閾值大部分是使用率80%開始,實際建議參數可以設置為實例內存的5%~15%左右,最好不要超過20%,避免OOM。
  • 非特殊情況下避免使用monitor命令或者rename該命令。
  • 在使用pipline的時候,pipeline不能封裝過多的命令,特別是一些返回結果集較多的命令更應該少封裝。
  • 主從復制輸出緩沖區大小設置參考: 緩沖區大小=(主庫寫入命令速度 * 操作大小 - 主從庫間網絡傳輸命令速度 * 操作大小)* 2。

3.3 碎片優化

碎片優化可以降低內存使用率,提高訪問效率,在4.0以下版本,我們只能使用重啟恢復,重啟加載rdb或者重啟通過高可用主從切換實現數據的重新加載可以減少碎片,在4.0以上版本,Redis提供了自動和手動的碎片整理功能,原理大致是把數據拷貝到新的內存空間,然后把老的空間釋放掉,這個是有一定的性能損耗的。

  • 【a. redis手動整理碎片】:執行memory purge命令即可。
  • 【b.redis自動整理碎片】:通過如下幾個參數控制
  • 【activedefrag yes 】:啟用自動碎片清理開關
  • 【active-defrag-ignore-bytes 100mb】:內存碎片空間達到多少才開啟碎片整理
  • 【active-defrag-threshold-lower 10】:碎片率達到百分之多少才開啟碎片整理
  • 【active-defrag-threshold-upper 100 】:內存碎片率超過多少,則盡最大努力整理(占用最大資源去做碎片整理)
  • 【active-defrag-cycle-min 25 】:內存自動整理占用資源最小百分比
  • 【active-defrag-cycle-max 75】:內存自動整理占用資源最大百分比

3.4 子進程內存優化

前面談到 AOF rewrite和 RDB 生成動作會產生子進程,正常在兩個動作執行的過程中,Redis 寫操作沒有那么頻繁的情況下fork出來的子進程是不會消耗很多內存的,這個主要是因為 Redis 子進程使用了 Linux 的 copy on write 機制,簡稱COW。

COW的核心是在fork出子進程后,與父進程共享內存空間,只有在父進程發生寫操作修改內存數據時,才會真正去分配內存空間,并復制內存數據。

但是有一點需要注意,不要開啟操作系統的大頁THP(Transparent Huge Pages),開啟 THP 機制后,本來頁的大小由4KB變為 2MB了。它雖然可以加快 fork 完成的速度( 因為要拷貝的頁的數量減少 ),但是會導致 copy-on-write 復制內存頁的單位從 4KB 增大為 2MB,如果父進程有大量寫命令,會加重內存拷貝量,從而造成過度內存消耗。

四、內存優化案例

4.1 緩沖區異常優化案例

線上業務 Redis 集群出現內存告警,內存使用率增長很快達到100%,值班人員先進行了緊急擴容,同時反饋至業務群是否有大量新數據寫入,業務反饋并無大量新數據寫入,且同時擴容后的內存還在漲,很快又要觸發告警了,業務 DBA 去查監控看看具體原因。

首先我們看used_memory增長只是集群的少數幾個實例,同時內存異常的實例的key的數量并沒有異常增長,說明沒有寫入大批量數據導致。

我們再往下分析,可能是客戶端的內存占用異常比較大,查看實例 info 里面的客戶端相關指標,觀察發現output_list的增長曲線和used_memory一致,可以判定是客戶端的輸出緩沖異常導致。

接下來我們再去通過client list查看是什么客戶端導致output增長,客戶端在執行什么命令,同時去分析是否訪問大key。

執行 client list |grep -i omem=0 發現如下:

id=12593807 addr=192.168.101.1:52086 fd=10767 name= age=15301 idle=0 flags=N 
db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=16173 oll=341101
omem=5259227504 events=rw cmd=get

說明下相關的幾個重點的字段的含義:

  • 【id】:就是客戶端的唯一標識,經常用于我們kill客戶端用到id;
  • 【addr】:客戶端信息;
  • 【obl】:固定緩沖區大小(字節),默認是16K;
  • 【oll】:動態緩沖區大小(對象個數),客戶端如果每條命令的響應結果超過16k或者固定緩沖區寫滿了會寫動態緩沖區;
  • 【omem】: 指緩沖區的總字節數;
  • 【cmd】: 最近一次的操作命令。

可以看到緩沖區內存占用很大,最近的操作命令也是get,所以我們先看看是否大key導致(我們是直接分析RDB發現并沒有大key),但是發現并沒有大key,而且get對應的肯定是string類型,string類型的value最大是512M,所以單個key也不太可能產生這么大的緩存,所以斷定是客戶端緩存了多個key。

這個時候為了盡快恢復,和業務溝通臨時kill該連接,內存釋放,然后為了避免防止后面還產生異常,和業務方

  • 【int:】 (整數且數字長度小于20,直接記錄在ptr*里面)
  • 【embstr】: (連續分配的內存(字符串長度小于等于44字節的字符串))
  • 【raw】: 動態字符串(大于44個字節的字符串,同時字符長度小于 512M(512M是字符串的大小限制))

溝通設置普通客戶端緩存限制,因為最大內存是25G,我們把緩存設置了2G-4G, 動態設置參數如下:

config set client-output-buffer-limit normal
4096mb 2048mb 120

因為參數限制也只是針對單個client的輸出緩沖這么大,所以還需要檢查客戶端使用使用 pipline 這種管道命令或者類似實現了封裝大批量命令導致結果統一返回之前被阻塞,后面確定確實會有這個操作,業務層就需要去逐步優化,不然我們限制了輸出緩沖,達到了上限,會話會被kill, 所以業務不改的話還是會有拋錯。

業務方反饋用的是 C++ 語言 brpc 自帶的 Redis客戶端,第一次直接搜索沒有pipline的關鍵字,但是現象又指向使用的管道,所以繼續仔細看了下代碼,發現其內部是實現了pipline類似的功能,也是會對多個命令進行封裝去請求redis,然后統一返回結果,客戶端GitHub鏈接如下:

??https://github.com/apache/incubator-brpc/blob/master/docs/cn/redis_client.md??

總結:

pipline 在 Redis 客戶端中使用的挺多的,因為確實可以提供訪問效率,但是使用不當反而會影響訪問,應該控制好訪問,生產環境也盡量加這些內存限制,避免部分客戶端的異常訪問影響全局使用。

4.2 從節點內存異常增長案例

線上 Redis 集群出現內存使用率超過 95% 的災難告警,但是該集群是有190個節點的集群觸發異常內存告警的只有3個節點。所以查看集群對應信息以及監控指標發現如下有用信息:

  1. 3個從節點對應的主節點內存沒有變化,從節點的內存是逐步增長的。
  2. 發現集群整體ops比較低,說明業務變化并不大,沒有發現有效命令突增。
  3. 主從節點的最大內存不一致,主節點是6G,從節點是5G,這個是導致災難告警的重要原因。
  4. 在出問題前,主節點比從節點的內存大概多出1.3G,后面從節點used_memory逐步增長到超過主節點內存,但是rss內存是最后保持了一樣。
  5. 主從復制出現延遲也內存增長的那個時間段。

處理過程:

首先想到的應該是保持主從節點最大內存一致,但是因為主機內存使用率比較高暫時沒法擴容,因為想到的是從節點可能什么原因阻塞,所以和業務方溝通是重啟下2從節點緩解下,重啟后從節點內存釋放,降到發生問題前的水平,如上圖,后面主機空出了內存資源,所以優先把內存調整一致。

內存調整好了一周后,這3個從節點內存又告警了,因為現在主從內存是一致的,所以觸發的是嚴重告警(>85%),查看監控發現情況是和之前一樣,猜測這個是某些操作觸發的,所以還是決定問問業務方這 兩個時間段都有哪些操作,業務反饋這段時間就是在寫業務,那2個時間段都是在寫入,也看了寫redis的那段代碼,用了一個比較少見的命令append,append是對string類型的value進行追加。

這里就得提下string類型在 Redis 里面是怎么分配內存的:string類型都是都是sds存儲,當前分配的sds內存空間不足存儲且小于1M時候,Redis會重新分配一個2倍之前內存大小的內存空間。

根據上面到知識點,所以可以大致可以解析上述一系列的問題,大概是當時做 append 操作,從節點需要分配空間從而發生內存膨脹,而主節點不需要分配空間,因為內存重新分配設計malloc和free操作,所以當時有lag也是正常的。

Redis的主從本身是一個邏輯復制,加載 RDB 的過程其實也是拿到kv不斷的寫入到從節點,所以主從到內存大小也經常存在不相同的情況,特別是這種values大小經常改變的場景,主從存儲的kv所用的空間很多可能是不一樣的。

為了證明這一猜測,我們可以通過獲取一個key(value大小要比較大)在主從節點占用空間的大小,因為是4.0以上版本,所以我們可以使用memory USAGE 去獲取大小,看看差異有多少,我們隨機找了幾個稍微大點的key去查看,發現在有些key從庫占用空間是主庫的近2倍,有的差不多,有的也是1倍多,rdb解析出來的這個key空間更小,說明從節點重啟后加載rdb進行存放是最小的,然后因為某段時間大批量key操作,導致從節點的大批量的key分配的空間不足,需要擴容1倍空間,導致內存出現增長。

到這就分析的其實差不多了,因為append的特性,為了避免內存再次出現內存告警,決定把該集群的內存進行擴容,控制內存使用率在70%以下(避免可能發生的大量key使用內存翻倍的情況)。

最后還有1個問題:上面的used_memory為什么會比memory_rss的值還大呢?(swap是關閉的)。

這是因為jemalloc內存分配一開始其實分配的是虛擬內存,只有往分配的page頁里面寫數據的時候才會真正分配內存,memory_rss是實際內存占用,used_memory其實是一個計數器,在 Redis做內存的malloc/free的時候,對這個used_memory做加減法。

關于used_memory大于memory_rss的問題,redis作者也做了回答:

??https://github.com/redis/redis/issues/946#issuecomment-13599772??

總結:

在知曉 Redis內存分配原理的情況下,數據庫的內存異常問題進行分析會比較快速定位,另外可能某個問題看起來和業務沒什么關聯,但是我們還是應該多和業務方溝通獲取一些線索排查問題,最后主從內存一定按照規范保持一致。

五、總結

Redis在數據存儲、緩存都是做了很巧妙的設計和優化,我們在了解了它的內部結構、存儲方式之后,我們可以提前在key的設計上做優化。我們在遇到內存異常或者性能優化的時候,可以不再局限于表面的一些分析如:資源消耗、命令的復雜度、key的大小,還可以結合根據Redis的一些內部運行機制和內存管理方式去深入發現是否還有可能哪些方面導致異常或者性能下降。

責任編輯:未麗燕 來源: vivo互聯網技術
相關推薦

2024-02-29 09:17:43

數據中心

2023-01-05 07:54:49

vivo故障定位

2022-12-22 08:51:40

vivo代碼

2022-12-15 11:26:44

云原生

2022-06-07 15:33:51

Android優化實踐

2024-11-13 21:18:02

2022-08-10 21:43:29

HttpClientHttp工具網絡

2023-10-31 12:50:35

智能優化探索

2024-12-26 09:27:51

2024-12-18 10:03:30

2022-08-12 12:23:28

神經網絡優化

2025-01-15 09:16:10

2024-04-17 07:21:52

物化視圖查詢加速器數據倉庫

2024-12-05 12:01:09

2022-06-01 09:04:58

Kafka運維副本遷移

2023-03-15 21:38:43

短視頻服務器

2025-02-20 08:00:00

2022-09-14 23:14:10

vivoPulsar大數據

2023-09-14 10:04:31

vivo數據中心網絡

2023-12-06 21:44:28

RocksDBvivo
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 婷婷色国产偷v国产偷v小说 | 一区二区三区网站 | 欧美日韩精品一区二区三区蜜桃 | 国产露脸国语对白在线 | 视频一区二区在线观看 | 91精品国产乱码久久久久久 | 91大神xh98xh系列全部 | 91久久精品国产91久久 | 成人免费看黄网站在线观看 | 日本午夜一区二区三区 | 日韩一区精品 | 精产国产伦理一二三区 | 美国黄色毛片 | 综合一区| 国产成人在线一区二区 | av日韩高清 | 国产精品视频专区 | 日本午夜一区二区三区 | 精品国产一区二区三区免费 | 婷婷综合 | 日日摸夜夜添夜夜添特色大片 | 黄色免费在线观看 | 精品国产精品一区二区夜夜嗨 | 国产精品久久久一区二区三区 | 国产美女视频黄a视频免费 国产精品福利视频 | 日韩欧美操 | 国产美女视频黄a视频免费 国产精品福利视频 | 三级在线视频 | 国产精品久久久久久久久久尿 | 午夜视频网站 | 狠狠久| 男人av的天堂| 亚洲精品久久久久久宅男 | 日韩影院在线观看 | 国产韩国精品一区二区三区 | 黄色一级毛片免费看 | 99在线免费视频 | 在线看片福利 | 久草资源| 亚洲欧美日韩精品久久亚洲区 | 99精品在线 |