日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何优雅的设计和使用缓存?

發布時間:2024/4/11 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何优雅的设计和使用缓存? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

在之前的文章中你應該知道的緩存進化史介紹了愛奇藝的緩存架構和緩存的進化歷史。俗話說得好,工欲善其事,必先利其器,有了好的工具肯定得知道如何用好這些工具,本篇將介紹如何利用好緩存。

1.確認是否需要緩存

在使用緩存之前,需要確認你的項目是否真的需要緩存。使用緩存會引入的一定的技術復雜度,后文也將會一一介紹這些復雜度。一般來說從兩個方面來個是否需要使用緩存:

  • CPU占用:如果你有某些應用需要消耗大量的cpu去計算,比如正則表達式,如果你使用正則表達式比較頻繁,而其又占用了很多CPU的話,那你就應該使用緩存將正則表達式的結果給緩存下來。

  • 數據庫IO占用:如果你發現你的數據庫連接池比較空閑,那么不應該用緩存。但是如果數據庫連接池比較繁忙,甚至經常報出連接不夠的報警,那么是時候應該考慮緩存了。筆者曾經有個服務,被很多其他服務調用,其他時間都還好,但是在每天早上10點的時候總是會報出數據庫連接池連接不夠的報警,經過排查,發現有幾個服務選擇了在10點做定時任務,大量的請求打過來,DB連接池不夠,從而報出連接池不夠的報警。這個時候有幾個選擇,我們可以通過擴容機器來解決,也可以通過增加數據庫連接池來解決,但是沒有必要增加這些成本,因為只有在10點的時候才會出現這個問題。后來引入了緩存,不僅解決了這個問題,而且還增加了讀的性能。

  • 如果并沒有上述兩個問題,那么你不必為了增加緩存而緩存。

    2.選擇合適的緩存

    緩存又分進程內緩存和分布式緩存兩種。很多人包括筆者在開始選緩存框架的時候都感到了困惑:網上的緩存太多了,大家都吹噓自己很牛逼,我該怎么選擇呢?

    2.1 選擇合適的進程緩存

    首先看看幾個比較常用的緩存的比較,具體原理可以參考你應該知道的緩存進化史:

    比較項ConcurrentHashMapLRUMapEhcacheGuava CacheCaffeine
    讀寫性能很好,分段鎖一般,全局加鎖好,需要做淘汰操作很好
    淘汰算法LRU,一般支持多種淘汰算法,LRU,LFU,FIFOLRU,一般W-TinyLFU, 很好
    功能豐富程度功能比較簡單功能比較單一功能很豐富功能很豐富,支持刷新和虛引用等功能和Guava Cache類似
    工具大小jdk自帶類,很小基于LinkedHashMap,較小很大,最新版本1.4MB是Guava工具類中的一個小部分,較小一般,最新版本644KB
    是否持久化
    是否支持集群
    • 對于ConcurrentHashMap來說,比較適合緩存比較固定不變的元素,且緩存的數量較小的。雖然從上面表格中比起來有點遜色,但是其由于是jdk自帶的類,在各種框架中依然有大量的使用,比如我們可以用來緩存我們反射的Method,Field等等;也可以緩存一些鏈接,防止其重復建立。在Caffeine中也是使用的ConcurrentHashMap來存儲元素。
    • 對于LRUMap來說,如果不想引入第三方包,又想使用淘汰算法淘汰數據,可以使用這個。
    • 對于Ehcache來說,由于其jar包很大,較重量級。對于需要持久化和集群的一些功能的,可以選擇Ehcache。筆者沒怎么使用過這個緩存,如果要選擇的話,可以選擇分布式緩存來替代Ehcache。
    • 對于Guava Cache來說,Guava這個jar包在很多Java應用程序中都有大量的引入,所以很多時候其實是直接用就好了,并且其本身是輕量級的而且功能較為豐富,在不了解Caffeine的情況下可以選擇Guava Cache。
    • 對于Caffeine來說,筆者是非常推薦的,其在命中率,讀寫性能上都比Guava Cache好很多,并且其API和Guava cache基本一致,甚至會多一點。在真實環境中使用Caffeine,取得過不錯的效果。

    總結一下: 如果不需要淘汰算法則選擇ConcurrentHashMap,如果需要淘汰算法和一些豐富的API,這里推薦選擇Caffeine

    2.2 選擇合適的分布式緩存

    這里選取三個比較出名的分布式緩存來作為比較,MemCache(沒有實戰使用過),Redis(在美團又叫Squirrel),Tair(在美團又叫Cellar)。不同的分布式緩存功能特性和實現原理方面有很大的差異,因此他們所適應的場景也有所不同。

    比較項MemCacheSquirrel/RedisCellar/Tair
    數據結構只支持簡單的Key-Value結構String,Hash, List, Set, Sorted SetString,HashMap, List,Set
    持久化不支持支持支持
    容量大小數據純內存,數據存儲不宜過多數據全內存,資源成本考量不宜超過100GB可以配置全內存或內存+磁盤引擎,數據容量可無限擴充
    讀寫性能很高很高(RT0.5ms左右)String類型比較高(RT1ms左右),復雜類型比較慢(RT5ms左右)
    • MemCache:這一塊接觸得比較少,不做過多的推薦。其吞吐量較大,但是支持的數據結構較少,并且不支持持久化。
    • Redis:支持豐富的數據結構,讀寫性能很高,但是數據全內存,必須要考慮資源成本,支持持久化。
    • Tair: 支持豐富的數據結構,讀寫性能較高,部分類型比較慢,理論上容量可以無限擴充。

    總結: 如果服務對延遲比較敏感,Map/Set數據也比較多的話,比較適合Redis。如果服務需要放入緩存量的數據很大,對延遲又不是特別敏感的話,那就可以選擇Tair。在美團的很多應用中對Tair都有應用,在筆者的項目中使用其存放我們生成的支付token,支付碼,用來替代數據庫存儲。大部分的情況下兩者都可以選擇,互為替代。

    3.多級緩存

    很多人一想到緩存馬上腦子里面就會出現下面的圖:

    Redis用來存儲熱點數據,Redis中沒有的數據則直接去數據庫訪問。

    在之前介紹本地緩存的時候,很多人都問我,我已經有Redis了,我干嘛還需要了解Guava,Caffeine這些進程緩存呢。我基本統一回復下面兩個答案:

  • Redis如果掛了或者使用老版本的Redis,其會進行全量同步,此時Redis是不可用的,這個時候我們只能訪問數據庫,很容易造成雪崩。
  • 訪問Redis會有一定的網絡I/O以及序列化反序列化,雖然性能很高但是其終究沒有本地方法快,可以將最熱的數據存放在本地,以便進一步加快訪問速度。這個思路并不是我們做互聯網架構獨有的,在計算機系統中使用L1,L2,L3多級緩存,用來減少對內存的直接訪問,從而加快訪問速度。
  • 所以如果僅僅是使用Redis,能滿足我們大部分需求,但是當需要追求更高的性能以及更高的可用性的時候,那就不得不了解多級緩存。

    3.1使用進程緩存

    對于進程內緩存,其本來受限于內存的大小的限制,以及進程緩存更新后其他緩存無法得知,所以一般來說進程緩存適用于:

  • 數據量不是很大,數據更新頻率較低,之前我們有個查詢商家名字的服務,在發送短信的時候需要調用,由于商家名字變更頻率較低,并且就算是變更了沒有及時變更緩存,短信里面帶有老的商家名字客戶也能接受。利用Caffeine作為本地緩存,size設置為1萬,過期時間設置為1個小時,基本能在高峰期解決問題。
  • 如果數據量更新頻繁,也想使用進程緩存的話,那么可以將其過期時間設置為較短,或者設置其較短的自動刷新的時間。這些對于Caffeine或者Guava Cache來說都是現成的API。
  • 3.2使用多級緩存

    俗話說得好,世界上沒有什么是一個緩存解決不了的事,如果有,那就兩個。

    一般來說我們選擇一個進程緩存和一個分布式緩存來搭配做多級緩存,一般來說引入兩個也足夠了,如果使用三個,四個的話,技術維護成本會很高,反而有可能會得不償失,如下圖所示:

    利用Caffeine做一級緩存,Redis作為二級緩存。

  • 首先去Caffeine中查詢數據,如果有直接返回。如果沒有則進行第2步。
  • 再去Redis中查詢,如果查詢到了返回數據并在Caffeine中填充此數據。如果沒有查到則進行第3步。
  • 最后去Mysql中查詢,如果查詢到了返回數據并在Redis,Caffeine中依次填充此數據。
  • 對于Caffeine的緩存,如果有數據更新,只能刪除更新數據的那臺機器上的緩存,其他機器只能通過超時來過期緩存,超時設定可以有兩種策略:

    • 設置成寫入后多少時間后過期
    • 設置成寫入后多少時間刷新

    對于Redis的緩存更新,其他機器立馬可見,但是也必須要設置超時時間,其時間比Caffeine的過期長。

    為了解決進程內緩存的問題,設計進一步優化:

    通過Redis的pub/sub,可以通知其他進程緩存對此緩存進行刪除。如果Redis掛了或者訂閱機制不靠譜,依靠超時設定,依然可以做兜底處理。

    4.緩存更新

    一般來說緩存的更新有兩種情況:

    • 先刪除緩存,再更新數據庫。
    • 先更新數據庫,再刪除緩存。 這兩種情況在業界,大家對其都有自己的看法。具體怎么使用還得看各自的取舍。當然肯定會有人問為什么要刪除緩存呢?而不是更新緩存呢?你可以想想當有多個并發的請求更新數據,你并不能保證更新數據庫的順序和更新緩存的順序一致,那就會出現數據庫中和緩存中數據不一致的情況。所以一般來說考慮刪除緩存。

    4.1先刪除緩存,再更新數據庫

    對于一個更新操作簡單來說,就是先去各級緩存進行刪除,然后更新數據庫。這個操作有一個比較大的問題,在對緩存刪除完之后,有一個讀請求,這個時候由于緩存被刪除所以直接會讀庫,讀操作的數據是老的并且會被加載進入緩存當中,后續讀請求全部訪問的老數據。

    對緩存的操作不論成功失敗都不能阻塞我們對數據庫的操作,那么很多時候刪除緩存可以用異步的操作,但是先刪除緩存不能很好的適用于這個場景。

    先刪除緩存也有一個好處是,如果對數據庫操作失敗了,那么由于先刪除的緩存,最多只是造成Cache Miss。

    4.2先更新數據庫,再刪除緩存(推薦)

    如果我們使用更新數據庫,再刪除緩存就能避免上面的問題。但是同樣的引入了新的問題,試想一下有一個數據此時是沒有緩存的,所以查詢請求會直接落庫,更新操作在查詢請求之后,但是更新操作刪除數據庫操作在查詢完之后回填緩存之前,就會導致我們緩存中和數據庫出現緩存不一致。

    為什么我們這種情況有問題,很多公司包括Facebook還會選擇呢?因為要觸發這個條件比較苛刻。

  • 首先需要數據不在緩存中。
  • 其次查詢操作需要在更新操作先到達數據庫。
  • 最后查詢操作的回填比更新操作的刪除后觸發,這個條件基本很難出現,因為更新操作的本來在查詢操作之后,一般來說更新操作比查詢操作稍慢。但是更新操作的刪除卻在查詢操作之后,所以這個情況比較少出現。
  • 對比上面4.1的問題來說這種問題的概率很低,況且我們有超時機制保底所以基本能滿足我們的需求。如果真的需要追求完美,可以使用二階段提交,但是其成本和收益一般來說不成正比。

    當然還有個問題是如果我們刪除失敗了,緩存的數據就會和數據庫的數據不一致,那么我們就只能靠過期超時來進行兜底。對此我們可以進行優化,如果刪除失敗的話 我們不能影響主流程那么我們可以將其放入隊列后續進行異步刪除。

    5.緩存挖坑三劍客

    大家一聽到緩存有哪些注意事項,肯定首先想到的是緩存穿透,緩存擊穿,緩存雪崩這三個挖坑的小能手,這里簡單介紹一下他們具體是什么以及應對的方法。

    5.1緩存穿透

    緩存穿透是指查詢的數據在數據庫是沒有的,那么在緩存中自然也沒有,所以,在緩存中查不到就會去數據庫取查詢,這樣的請求一多,那么我們的數據庫的壓力自然會增大。

    為了避免這個問題,可以采取下面兩個手段:

  • 約定:對于返回為NULL的依然緩存,對于拋出異常的返回不進行緩存,注意不要把拋異常的也給緩存了。采用這種手段的會增加我們緩存的維護成本,需要在插入緩存的時候刪除這個空緩存,當然我們可以通過設置較短的超時時間來解決這個問題。
  • 制定一些規則過濾一些不可能存在的數據,小數據用BitMap,大數據可以用布隆過濾器,比如你的訂單ID 明顯是在一個范圍1-1000,如果不是1-1000之內的數據那其實可以直接給過濾掉。
  • 5.2緩存擊穿

    對于某些key設置了過期時間,但是其是熱點數據,如果某個key失效,可能大量的請求打過來,緩存未命中,然后去數據庫訪問,此時數據庫訪問量會急劇增加。

    為了避免這個問題,我們可以采取下面的兩個手段:

  • 加分布式鎖:加載數據的時候可以利用分布式鎖鎖住這個數據的Key,在Redis中直接使用setNX操作即可,對于獲取到這個鎖的線程,查詢數據庫更新緩存,其他線程采取重試策略,這樣數據庫不會同時受到很多線程訪問同一條數據。
  • 異步加載:由于緩存擊穿是熱點數據才會出現的問題,可以對這部分熱點數據采取到期自動刷新的策略,而不是到期自動淘汰。淘汰其實也是為了數據的時效性,所以采用自動刷新也可以。
  • 5.3緩存雪崩

    緩存雪崩是指緩存不可用或者大量緩存由于超時時間相同在同一時間段失效,大量請求直接訪問數據庫,數據庫壓力過大導致系統雪崩。

    為了避免這個問題,我們采取下面的手段:

  • 增加緩存系統可用性,通過監控關注緩存的健康程度,根據業務量適當的擴容緩存。
  • 采用多級緩存,不同級別緩存設置的超時時間不同,即使某個級別緩存都過期,也有其他級別緩存兜底。
  • 緩存的過期時間可以取個隨機值,比如以前是設置10分鐘的超時時間,那每個Key都可以隨機8-13分鐘過期,盡量讓不同Key的過期時間不同。
  • 6.緩存污染

    緩存污染一般出現在我們使用本地緩存中,可以想象,在本地緩存中如果你獲得了緩存,但是你接下來修改了這個數據,但是這個數據并沒有更新在數據庫,這樣就造成了緩存污染:

    上面的代碼就造成了緩存污染,通過id獲取Customer,但是需求需要修改Customer的名字,所以開發人員直接在取出來的對象中直接修改,這個Customer對象就會被污染,其他線程取出這個數據就是錯誤的數據。

    要想避免這個問題需要開發人員從編碼上注意,并且代碼必須經過嚴格的review,以及全方位的回歸測試,才能從一定程度上解決這個問題。

    7.序列化

    序列化是很多人都不注意的一個問題,很多人忽略了序列化的問題,上線之后馬上報出一下奇怪的錯誤異常,造成了不必要的損失,最后一排查都是序列化的問題。列舉幾個序列化常見的問題:

  • key-value對象過于復雜導致序列化不支持: 筆者之前出過一個問題,在美團的Tair內部默認是使用protostuff進行序列化,而美團使用的通訊框架是thfift,thrift的TO是自動生成的,這個TO里面很多復雜的數據結構,但是將其存放到了Tair中。查詢的時候反序列化也沒有報錯,單測也通過,但是到qa測試的時候發現這一塊功能有問題,發現有個字段是boolean類型默認是false,把它改成true之后,序列化到tair中再反序列化還是false。定位到是protostuff對于復雜結構的對象(比如數組,List等等)支持不是很好,會造成一定的問題。后來對這個TO進行了轉換,用普通的Java對象就能進行正確的序列化反序列化。
  • 添加了字段或者刪除了字段,導致上線之后老的緩存獲取的時候反序列化報錯,或者出現一些數據移位。
  • 不同的JVM的序列化不同,如果你的緩存有不同的服務都在共同使用(不提倡),那么需要注意不同JVM可能會對Class內部的Field排序不同,而影響序列化。比如下面的代碼,在Jdk7和Jdk8中對象A的排列順序不同,最終會導致反序列化結果出現問題:
  • //jdk 7 class A{int a;int b; } //jdk 8 class A{int b;int a; }

    序列化的問題必須得到重視,解決的辦法有如下幾點:

  • 測試:對于序列化需要進行全面的測試,如果有不同的服務并且他們的JVM不同那么你也需要做這一塊的測試,在上面的問題中筆者的單測通過的原因是用的默認數據false,所以根本沒有測試true的情況,還好QA給力,將其給測試出來了。
  • 對于不同的序列化框架都有自己不同的原理,對于添加字段之后如果當前序列化框架不能兼容老的,那么可以換個序列化框架。 對于protostuff來說他是按照Field的順序來進行反序列化的,對于添加字段我們需要放到末尾,也就是不能插在中間,否則會出現錯誤。對于刪除字段來說,用@Deprecated注解進行標注棄用,如果貿然刪除,除非是最后一個字段,否則肯定會出現序列化異常。
  • 可以使用雙寫來避免,對于每個緩存的key值可以加上版本號,每次上線版本號都加1,比如現在線上的緩存用的是Key_1,即將要上線的是Key_2,上線之后對緩存的添加是會寫新老兩個不同的版本(Key_1,Key_2)的Key-Value,讀取數據還是讀取老版本Key_1的數據,假設之前的緩存的過期時間是半個小時,那么上線半個小時之后,之前的老緩存存量的數據都會被淘汰,此時線上老緩存和新緩存他們的數據基本是一樣的,切換讀操作到新緩存,然后停止雙寫。采用這種方法基本能平滑過渡新老Model交替,但是不好的點就是需要短暫的維護兩套新老Model,下次上線的時候需要刪除掉老Model,增加了維護成本。
  • 8. GC調優

    對于大量使用本地緩存的應用,由于涉及到緩存淘汰,那么GC問題必定是常事。如果出現GC較多,STW時間較長,那么必定會影響服務可用性。這一塊給出下面幾點建議:

  • 經常查看GC監控,如果發現不正常,需要想辦法對其進行優化。
  • 對于CMS垃圾收集器,如果發現remark過長,如果是大量本地緩存應用的話這個過長應該很正常,因為在并發階段很容易有很多新對象進入緩存,從而remark階段掃描很耗時,remark又會暫停。可以開啟-XX:CMSScavengeBeforeRemark,在remark階段前進行一次YGC,從而減少remark階段掃描gc root的開銷。
  • 可以使用G1垃圾收集器,通過-XX:MaxGCPauseMillis設置最大停頓時間,提高服務可用性。
  • 9. 緩存的監控

    很多人對于緩存的監控也比較忽略,基本上線之后如果不報錯然后就默認他就生效了。但是存在這個問題,很多人由于經驗不足,有可能設置了不恰當的過期時間,或者不恰當的緩存大小導致緩存命中率不高,讓緩存就成為了代碼中的一個裝飾品。所以對于緩存各種指標的監控,也比較重要,通過其不同的指標數據,我們可以對緩存的參數進行優化,從而讓緩存達到最優化:

    上面的代碼中用來記錄get操作的,通過Cat記錄了獲取緩存成功,緩存不存在,緩存過期,緩存失敗(獲取緩存時如果拋出異常,則叫失敗),通過這些指標,我們就能統計出命中率,我們調整過期時間和大小的時候就可以參考這些指標進行優化。

    10. 一款好的框架

    一個好的劍客沒有一把好劍怎么行呢?如果要使用好緩存,一個好的框架也必不可少。在最開始使用的時候大家使用緩存都用一些util,把緩存的邏輯寫在業務邏輯中:

    上面的代碼把緩存的邏輯耦合在業務邏輯當中,如果我們要增加成多級緩存那就需要修改我們的業務邏輯,不符合開閉原則,所以引入一個好的框架是不錯的選擇。

    推薦大家使用JetCache這款開源框架,其實現了Java緩存規范JSR107并且支持自動刷新等高級功能。筆者參考JetCache結合Spring Cache, 監控框架Cat以及美團的熔斷限流框架Rhino實現了一套自有的緩存框架,讓操作緩存,打點監控,熔斷降級,業務人員無需關心。上面的代碼可以優化成:

    對于一些監控數據也能輕松從大盤上看到:

    最后

    想要真正的使用好一個緩存,必須要掌握很多的知識,并不是看幾個Redis原理分析,就能把Redis緩存用得爐火純青。對于不同場景,緩存有各自不同的用法,同樣的不同的緩存也有自己的調優策略,進程內緩存你需要關注的是他的淘汰算法和GC調優,以及要避免緩存污染等。分布式緩存你需要關注的是他的高可用,如果其不可用了如何進行降級,以及一些序列化的問題。一個好的框架也是必不可少的,對其如果使用得當再加上上面介紹的經驗,相信能讓你很好的駕馭住這頭野馬——緩存。

    轉載自:公眾號_咖啡拿鐵
    原文鏈接:https://juejin.im/post/6844903665845665805
    來源:掘金

    總結

    以上是生活随笔為你收集整理的如何优雅的设计和使用缓存?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 天天爽夜夜爽夜夜爽 | 九九色九九 | 中文字幕在线观看网址 | 最新av| 亚洲精品成人无码熟妇在线 | 天天草夜夜操 | 写真福利片hd在线播放 | 麻豆成人精品国产免费 | 国产大片一区二区三区 | 人妻大战黑人白浆狂泄 | 噜噜色图 | 不卡中文字幕在线 | 亚洲麻豆视频 | jzzijzzij亚洲成熟少妇 | 色版视频 | 理论视频在线观看 | 伊人影音| 一区二区国产视频 | 色诱av | 超碰麻豆 | 一本加勒比北条麻妃 | 初高中福利视频网站 | 生活片av| proumb性欧美在线观看 | 黄频在线 | 99草视频| 亚洲国产成人精品女人久久 | 美丽的姑娘观看在线播放 | 秋霞伦理一区二区 | 国产精品zjzjzj在线观看 | а√天堂www在线天堂小说 | 亚洲国产精品一区二区久久hs | 99re国产| 国产网红在线 | 国产专区第一页 | 噜噜在线视频 | 美女扒开尿口让男人捅爽 | 国产色在线,com | 岛国av噜噜噜久久久狠狠av | 婷婷色综合 | 亚洲小视频网站 | 亚洲综合精品一区 | 北条麻妃一区二区三区在线观看 | 国产一区a | 欧美一级xxx| 亚洲一区二区蜜桃 | 久久久夜色 | 少妇15p | 美国成人免费视频 | 久久国产欧美日韩精品 | 日韩不卡| 亚洲 美腿 欧美 偷拍 | 国产福利一区二区三区在线观看 | 欲求不满的岳中文字幕 | 日日骚网 | 高清一区二区三区四区五区 | 欧美色图网站 | 人人爽av | 又大又硬又爽免费视频 | 自拍偷拍第 | 欧美一区二区三区四区在线 | 欧美一级片在线 | 国产三级视频网站 | 污片免费看| 免费观看av毛片 | 中文字幕丰满人伦在线 | 天堂在线免费视频 | 欧美激情精品久久久久久免费 | 成人免费毛片视频 | 操操操视频 | 不卡一区二区三区四区 | 日日操夜夜爱 | 国产av无码专区亚洲av麻豆 | 久久国语精品 | 中文字幕在线免费播放 | 欧美精品亚洲精品 | 国产精品水嫩水嫩 | 羞羞的软件| 亚洲欧美日韩在线一区二区 | 欧洲中文字幕 | 天堂а√在线最新版中文在线 | 91激情在线观看 | 丰满少妇被猛烈进入 | 国产激情免费视频 | 一区二区三区高清 | 欧美国产精品一区 | 无遮挡国产 | 国产一级自拍 | 国产叼嘿视频 | 噜噜噜在线| 久久免费看少妇高潮 | 亚洲网在线 | 波多野结衣中文字幕在线播放 | 欧美色欧美 | 黄色免费片 | 久久国产二区 | 欧美精品免费一区二区三区 | 欧美成人午夜 | 国产青青|