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

COPS 性能和一致性之間的更貼合業務直覺、更易于編程的「中間地帶」

開發 前端
讓我們先構思一個最簡單的方案,稱之為“稻草人”設計一號:每個數據中心都分片存儲著完整數據。用戶的讀寫請求都只發往本地數據中心的分片,本地寫入成功后,再異步地把這次寫入“推送”給其他數據中心的對應分片。

我們來深入探討一下 COPS 這篇經典的分布式系統論文。在學習 Spanner 這樣的強一致性系統和 Memcached 這樣的最終一致性系統之后,COPS 給我們展示了在性能和一致性之間,是否存在一個更貼合業務直覺、更易于編程的“中間地帶”。

設定場景:地理分布下的困境與抉擇

想象一下,我們正在構建一個全球性的社交網絡或電商平臺。為了讓世界各地的用戶都能獲得飛快的訪問體驗,我們會在全球部署多個數據中心,比如在北美、歐洲和亞洲各部署一個。理想情況下,每個數據中心都擁有所有數據的完整副本,這樣用戶的讀請求就可以在本地數據中心完成,延遲極低。

但問題來了: 寫操作怎么辦?

我們之前學過兩種主流方案:

  1. 強一致性方案(如 Goggle/Spanner) :用戶的寫操作需要通過 Paxos 或 Raft 這樣的共識算法,在多個數據中心的副本之間達成一致。這意味著,一次寫操作可能需要等待遠在地球另一邊的數據中心的確認,延遲較高。
  2. 主從方案(如 Facebook/Memcache) :所有寫操作都必須發往一個指定的“主”數據中心。其他數據中心都是只讀副本,異步地從主數據中心同步數據。這同樣意味著非主數據中心的用戶無法享受低延遲的本地寫入。

這兩種方案都犧牲了某些東西。我們能不能設計一個系統,它既能讓 任何數據中心都能處理寫操作 ,又能讓這些寫操作 在本地立即完成 ,無需等待其他數據中心?

這正是 COPS 想要實現的目標。為了達到這個高性能目標,我們愿意在一致性上做一些妥協,但我們希望找到一種比“最終一致性”更強大、對程序員更友好的模型。

最終一致性的“陷阱”

讓我們先構思一個最簡單的方案,稱之為“稻草人”設計一號:每個數據中心都分片存儲著完整數據。用戶的讀寫請求都只發往本地數據中心的分片,本地寫入成功后,再異步地把這次寫入“推送”給其他數據中心的對應分片。

這個設計性能極好,但它屬于 最終一致性(Eventual Consistency) 。這意味著系統只保證,如果大家停止寫入,所有數據中心最終會同步到一樣的數據。但在寫入過程中,它可能會出現一些反直覺的“異常”現象(anomalies)。

舉個經典的例子:

  1. 愛麗絲在她的社交網絡主頁上傳了一張美麗的風景照。
  2. 然后,她把這張照片的鏈接添加到了自己的“公開相冊”里。

這個過程涉及兩個寫操作:put(photo_key, photo_data) 和 put(album_key, photo_link)。在愛麗絲看來,這兩個操作是先后發生的。

現在,愛麗絲的朋友鮑勃刷新頁面,看到了“公開相冊”里新增的鏈接。他滿心歡喜地點進去,結果卻看到了什么?一個“圖片不存在”的錯誤!

愛麗絲 (數據中心A):
    操作1: put(photo_key, data)
    操作2: put(album_key, link_to_photo)
       |
       |--- (異步復制) --->
       |
鮑勃 (數據中心B):
    get(album_key) -> 成功, 拿到了 link_to_photo
    get(photo_key) -> 失敗!

為什么會這樣?因為put(album) 的更新數據包可能比 put(photo) 的數據包更早地從數據中心 A 到達了數據中心 B。對于應用開發者來說,這種不確定性非常頭疼,需要寫很多復雜的防御性代碼來處理“鏈接存在但內容不存在”的窘境。

撥亂反正:因果一致性

為了解決上述問題,我們需要一個比最終一致性更強的一致性模型。COPS 提出的核心概念是 因果+一致性(Causal+ Consistency) 。

它的核心思想很簡單:如果操作 A 是操作 B 的“原因”,那么在系統中的任何觀察者看來,A 都必須發生在 B 之前。

什么是“因果關系”?論文定義了三條規則來確定操作之間的潛在因果關系

  1. 執行線程(Execution Thread) :在同一個客戶端的執行流中,先發生的操作是后發生操作的原因。比如,愛麗絲先 put(photo),再 put(album),那么 put(photo) 就因果上先于 put(album)
  2. 讀寫關系(Gets From) :如果一個 get 操作讀到了某個 put 操作寫入的值,那么這個 put 操作就是該 get 操作的原因。
  3. 傳遞性(Transitivity) :如果 A 是 B 的原因,B 是 C 的原因,那么 A 就是 C 的原因。

有了這個模型,put(photo) 和 put(album) 就有了明確的因果關系。因果一致性保證了,如果鮑勃能讀到 album 的更新,他一定也能讀到 photo 的內容。

“+”號的含義:收斂的沖突處理

因果一致性只對有因果關系的操作進行排序,對于并發(concurrent)的操作,它不作任何保證。例如,愛麗絲和查理同時修改同一個活動的開始時間,一個改成晚上 8 點,一個改成晚上 10 點。這兩個 put 操作是并發的。

單純的因果一致性可能會導致一個嚴重問題: 數據副本永久分裂 。數據中心 A 可能永遠顯示 8 點,而數據中心 B 永遠顯示 10 點。

Causal+ 中的“+”號,代表了 收斂的沖突處理(Convergent Conflict Handling) 。它要求所有副本必須用同樣的方式處理并發沖突,最終達到一致的狀態。最常見的策略是 最后寫入者獲勝(last-writer-wins) 。

在生產實踐中,這是一個很重要但也很棘手的問題。對于計數器遞增、購物車加商品這類場景,“最后寫入者獲勝”顯然是不夠的。更高級的系統可能會采用:

  • CRDTs (Conflict-free Replicated Data Types) :為特定數據類型(如計數器、集合)設計的、天然能夠收斂的數據結構。
  • 應用層合并邏輯 :系統檢測到沖突后,交給應用程序自己去定義如何合并,比如購物車的合并邏輯就是取兩個集合的并集。

COPS 默認使用 last-writer-wins,并通過 蘭伯特時鐘(Lamport Clocks) 來為每個寫操作生成一個全局有序的版本號,從而確定誰是“最后的寫入者”。

蘭伯特時鐘(Lamport Clocks)與最后寫入者獲勝(LWW)

“最后寫入者獲勝”(Last-Writer-Wins, LWW)是最簡單直接的沖突解決方法。當兩個并發的寫操作修改同一個 key 時,系統選擇一個“勝利者”覆蓋另一個。但問題是,在沒有全局統一時鐘的分布式系統中,如何定義“最后”?

這就是 蘭伯特時鐘(Lamport Clocks) 發揮作用的地方。它不是一個物理時鐘,而是一個邏輯計數器,用來為分布式系統中的事件確定一個偏序關系。

  • 工作原理 :每個節點都維護一個本地的邏輯時鐘(一個整數)。

每當節點內部發生一個事件(比如處理一個寫請求),它就將本地時鐘加一。

當節點發送消息時,會附上自己當前的邏輯時鐘。

當節點接收到消息時,它會將自己的本地時鐘更新為 max(本地時鐘, 接收到的時鐘) + 1

通過這個機制,如果事件 A 因果上先于事件 B,那么 A 的蘭伯特時間戳一定小于 B 的時間戳。

  • 在 COPS 中的應用 :COPS 為每個寫操作分配一個版本號,這個版本號就是基于蘭伯特時鐘生成的。為了處理時間戳完全相同(雖然罕見)的情況,COPS 會在時間戳的低位附加一個唯一的節點 ID 來打破平局。當兩個對同一 key 的并發 put 操作到達一個副本時,該副本只需比較它們的版本號,保留版本號較大的那個,丟棄較小的那個。由于所有副本都遵循同樣的規則,它們最終都會保留同一個“勝利”的版本,從而實現收斂。

例子 : 假設數據中心 A 和 B 的節點同時收到對 key event_time 的寫請求。

  1. 節點 A 的時鐘是 100,收到 put(event_time, "8pm")。它將時鐘更新為 101,并標記這次寫入的版本為 101-A
  2. 節點 B 的時鐘也是 100,收到 put(event_time, "10pm")。它將時鐘更新為 101,標記版本為 101-B
  3. 當節點 A 收到來自 B 的 101-B 更新時,它比較 101-A 和 101-B。假設節點 ID B > A,那么 101-B 獲勝,event_time 被更新為 "10pm"。
  4. 同樣,當節點 B 收到來自 A 的 101-A 更新時,它也會選擇 101-B。最終,所有副本都收斂到 "10pm"。

應用層合并邏輯

LWW 雖然簡單,但對于很多業務場景來說過于粗暴。例如,合并兩個用戶的購物車,我們希望得到的是兩個購物車商品的并集,而不是一個覆蓋另一個。

應用層合并邏輯 就是將沖突的決定權交給應用程序。

  • 工作原理 :存儲系統檢測到對同一個 key 的并發寫入后,它不會擅自決定誰贏誰輸。相反,它會保留所有沖突的版本,或者將它們標記為“沖突狀態”。當客戶端下次讀取這個 key 時,系統會返回所有沖突的版本,并告知客戶端“這里有沖突,請解決”。應用程序根據自己的業務邏輯來決定如何合并這些值,然后將合并后的結果寫回系統。
  • 例子:購物車
  1. 愛麗絲在數據中心 A 將“牛奶”加入購物車。購物車狀態為 {"牛奶"}。
  2. 鮑勃(使用同一賬號)在數據中心 B 并發地將“面包”加入購物車。購物車狀態為 {"面包"}。
  3. 當這兩個更新在某個副本上相遇時,系統檢測到沖突。
  4. 下次 get(cart) 時,系統返回兩個版本:[{"牛奶"}, {"面包"}]。
  5. 客戶端(或服務器端的業務邏輯)看到這個結果后,執行合并操作:取兩個集合的并集,得到 {"牛奶", "面包"}。
  6. 最后,將這個合并后的結果 put(cart, {"牛奶", "面包"}) 寫回系統,解決沖突。

Bayou 和 DynamoDB 等系統都支持這種自定義沖突解決策略。COPS 也可以被配置為顯式地檢測沖突并調用應用定義好的處理函數。

CRDTs (Conflict-free Replicated Data Types)

CRDTs 是一種更優雅的解決方案。它們是一類特殊的數據結構,其數學性質保證了無論并發操作以何種順序應用,所有副本最終都會收斂到相同的狀態,并且這個過程 不需要額外的協調或復雜的合并邏輯 。

  • 工作原理 : CRDTs 的操作被設計為天然滿足交換律、結合律和冪等性。這意味著操作的順序和重復執行都不會影響最終結果。
  • 例子 1:計數器 (PN-Counter) :一個支持增和減的計數器。它內部由兩個普通計數器組成:一個只增不減的 P-Counter (Increments) 和一個只增不減的 N-Counter (Decrements)。

要增加總數,就在 P-Counter 上加一。

要減少總數,就在 N-Counter 上加一。

總值 = P-Counter 的值 - N-Counter 的值。

如果數據中心 A 執行了兩次 increment,它的狀態是 (P:2, N:0)。數據中心 B 執行了一次 decrement,狀態是 (P:0, N:1)。當它們的狀態同步后,大家都會合并成 (P:2, N:1),最終總值都是 1,結果永遠正確。

  • 例子 2:集合 (G-Set, Grow-Only Set)

一個只能添加元素的集合。它的合并操作就是取兩個集合的并集。無論并發地添加了多少元素,最終所有副本的并集都是一樣的。

CRDTs 非常適合實現點贊數、在線用戶統計、集合標簽等功能,它將沖突解決的復雜性隱藏在了數據結構的設計之中,極大地簡化了應用開發。

COPS 的核心魔法:顯式依賴跟蹤

那么,COPS 是如何在不引入全局同步點(比如單點日志服務器)的情況下,實現可擴展的因果一致性的呢?答案是: 顯式依賴跟蹤 。

它的工作流程是這樣的:

  1. 客戶端上下文(Client Context) :COPS 的客戶端庫會為每個執行線程維護一個“上下文”。這個上下文記錄了該線程“看到”的所有鍵值對的最新版本,也就是它的因果歷史。
  2. 寫入時攜帶依賴 :當客戶端執行一個 put 操作時,比如 put(album_key, ...),客戶端庫會自動將當前上下文中的所有依賴項,附加到這個寫請求上,一起發送給本地數據中心的存儲節點。在我們的例子中,put(album) 請求會明確地告訴系統:“我依賴于 photo_key 的某個版本”。
  3. 本地立即寫入,遠程延遲驗證 :
  • 這個 put(album) 操作在 本地數據中心 會 立即執行 并返回,保證了低延遲。
  • 然后,本地存儲節點會將這個寫入(連同它的依賴列表)異步地復制到其他數據中心。
  • 當一個 遠程數據中心 的節點收到這個 put(album) 請求時,它不會立即寫入。它會先進行一次 依賴檢查(dependency check) 。它會檢查該請求的所有依賴項(比如 photo_key)是否已經在本地滿足了。
  • 只有當所有依賴項都已在本地存在時,這個 put(album) 操作才會被應用。如果依賴項還沒到,它就會 等待 。
數據中心A (寫入方)
Client: put(photo, v1)                  -> Context: {photo:v1}
Client: put(album, v2, deps:{photo:v1}) -> Context: {album:v2}

   |
   +--- 異步復制 put(photo, v1) ---> 數據中心B
   |
   +--- 異步復制 put(album, v2, deps:{photo:v1}) ---> 數據中心B

數據中心B (接收方)
NodeB: 收到 put(album, v2, deps:{photo:v1})
NodeB: 檢查依賴 {photo:v1}
       - 如果 photo v1 已存在 -> 直接寫入 album v2
       - 如果 photo v1 不存在 -> 等待... 直到 photo v1 到達并寫入

這個設計的精妙之處在于,它把保證因果序的責任從“寫入方”的同步等待,轉移到了“接收方”的異步驗證。這使得系統可以水平擴展,因為每個分片可以獨立地復制和驗證自己的數據,避免了中心化的瓶頸。

更進一步:多 key 讀取與 Get 事務

因果一致性解決了單向依賴的問題,但對于需要同時讀取多個 key 的場景,我們可能還需要更強的保證。

論文中舉了 訪問控制列表(Access Control List, ACL) 的例子:

愛麗絲想修改相冊,她先把相冊設為私密,然后往相冊里添加了一張私密照片。

  • 初始狀態(系統空白或之前已有一些公開照片,無關本例)。
  • 操作 A:上傳私密照片put(album, add photo?)

系統先讀當前 ACL(此時是 v1=FRIENDS_ONLY),

在新版本 Album@v1 里寫入條目 photo? (depends_on ACL=v1)

  • 操作 B:切換為公開put(ACL, PUBLIC)
  • 生成新 ACL 版本 ACL@v2 = PUBLIC,但  去改動已有的 Album@v1 內容。
  • 此時,系統全局已有:
  • ACL@v2 = PUBLIC(部分副本已可見)
  • Album@v1 包含一條依賴 ACL=v1(FRIENDS_ONLY) 的私密照片 photo?。

另一個用戶伊芙想查看這個相冊。她的代碼邏輯是:先檢查 ACL,如果公開,就去讀取相冊內容。

// 伊芙的客戶端代碼
const acl = get("ACL");        // 讀到 ACL@v2 → "PUBLIC"
if (acl === "PUBLIC") {
  const album = get("album");  // 可能從某副本讀到舊版 Album@v1
  display(album);              // 展示全部條目,包括 photo?
}

時序穿越

  1. get("ACL") 讀到最新的 ACL@v2 = PUBLIC,Eve 認為相冊已對所有人公開。
  2. 隨后 get("album") 卻命中尚未同步到 ACL@v2 的某個副本,返回舊的 Album@v1,其中含有原本“僅好友可見”的 photo?。

結果 :Eve 最終在“公開”條件下看到了本應“私密”的照片,造成安全泄露。

為了解決這個問題,COPS 的擴展版本 COPS-GT 引入了 get 事務(get transaction / get_trans) 。它能保證一次性返回多個 key 的一個因果一致的快照。

它的實現是一個非常聰明的 兩階段非阻塞算法 :

  1. 第一輪:并行 get :客戶端庫向本地數據中心并行地為所有請求的 key(比如 ACL 和 album)發出 get_by_version 請求。這些請求會返回每個 key 的最新值、版本號以及 完整的依賴列表 。
  2. 檢查與第二輪 get (如果需要) :
  • 客戶端庫拿到第一輪的所有結果后,開始檢查一致性。例如,它發現返回的 album 版本依賴于一個比它在第一輪中拿到的 ACL 版本 更新的版本 。
  • 如果發現這種不一致,它會發起第二輪 get_by_version 請求。但這次,它不是去獲取最新版本,而是去獲取在第一輪依賴中看到的、能滿足一致性需求的 那個特定版本 。

這個算法為什么最多兩輪就能搞定?因為因果+一致性保證了,如果一個依賴(比如 ACL_v2)被另一個值(album_v2)所依賴,那么 ACL_v2一定 已經存在于本地數據中心了。所以第二輪的 get 絕不會被阻塞等待,可以立即返回。

現實世界的考量:垃圾回收與系統開銷

COPS 的設計聽起來很美好,但在工程實踐中,魔鬼藏在細節里。

  • 垃圾回收 (Garbage Collection) :依賴列表不能無限增長,否則客戶端上下文和存儲服務端的元數據都會爆炸。COPS 設計了一套垃圾回收機制。比如,當一個寫操作已經被所有數據中心確認后,它就可以被標記為“無需再依賴”,客戶端和服務器就可以清理掉相關的依賴信息。系統還會計算一個 全局檢查點時間(global checkpoint time) ,所有早于這個時間戳的依賴都可以被安全地清理掉。
  • 性能與開銷 :

COPS 本身相比于純粹的最終一致性系統,增加了跟蹤和檢查依賴的開銷,但評估顯示其性能依然很高,且擴展性良好。

COPS-GT 的開銷更大,因為它需要存儲每個 key 的多個歷史版本和完整的依賴列表,以便響應 get_trans 。但在讀多寫少的典型 Web 負載下,它的性能可以接近 COPS 。

總結與反思

COPS 是一篇里程碑式的論文,它清晰地闡述了在強一致性和最終一致性之間,存在一個既實用又高效的中間地帶——因果一致性。

它的核心貢獻是:

  1. 定義了 Causal+ Consistency :一個比最終一致性更強、更符合直覺,但又比強一致性性能更高的模型。
  2. 提出了一種可擴展的實現 :通過客戶端跟蹤上下文和遠程數據中心進行依賴檢查,避免了單點瓶頸,實現了系統的水平擴展。
  3. 設計了非阻塞的 Get 事務:通過巧妙的兩階段算法,實現了多 key 讀取的一致性快照,且延遲可控。

啟發:

  • 理解權衡 :沒有銀彈。Spanner、Dynamo、COPS 代表了在一致性、可用性、分區容忍性和性能之間不同的設計哲學和權衡點。理解這些權衡是分布式系統設計的核心。
  • 因果性的局限 :COPS 只能看到通過其 API 產生的因果關系。如果我 put 之后,用微信告訴你去看,這個“外部”的因果關系系統是不知道的。這是它和 Spanner 這種能保證外部一致性(或線性一致性)的系統的根本區別。
  • 沖突處理是關鍵 :在允許任意節點寫入的系統中,如何優雅地處理寫沖突,是一個繞不開的難題。last-writer-wins 是最簡單的,但往往不是最好的。

盡管因果一致性在學術界備受關注,但在工業界的大規模應用還比較少見。這可能是因為它對客戶端的侵入性較強(需要管理上下文),且對外部因果性的無能為力使其在某些場景下仍然不夠用。然而,COPS 的設計思想,尤其是其在去中心化系統中維護數據依賴關系的方法,至今仍對我們設計復雜的分布式系統有著深刻的啟發。

對比 Spanner / Memcache / COPS

維度

Spanner

Facebook/Memcache (主從模型)

COPS

一致性模型

線性一致性 (Linearizability)

 :提供全局、實時的操作順序,如同單機系統。

主從復制下的最終一致性

 :寫操作在主庫是原子的,但讀操作可能從緩存或只讀副本讀到舊數據。

因果+一致性 (Causal+)

 :保證因果相關的操作順序,但并發操作無序。

寫操作路徑

全局同步

 :寫操作需要在多個數據中心的 Paxos 副本中達成共識,通常涉及兩階段提交。

主數據中心寫入

 :所有寫操作必須路由到主數據中心的數據庫(如 MySQL),延遲較高。

本地寫入

 :寫操作在任何數據中心都能立即完成,然后異步復制到其他地方。

寫延遲

 :至少是一個廣域網的往返時延(RTT)。

 (對于非主數據中心的用戶):需要一個到主數據中心的 RTT。

極低

 :本地數據中心內的操作延遲,通常在毫秒級。

讀操作路徑

本地快照讀

 :可以讀取一個時間戳快照,通常很快,但若需最新數據則可能變慢。

本地緩存優先

 :優先從本地 Memcache 讀取,速度極快(百萬 QPS 級)。緩存未命中則回源到只讀數據庫。

本地讀取

 :所有讀操作都在本地數據中心完成。

讀延遲

 (對于快照讀)。

極低

 (緩存命中時)。

極低

 。

可用性

 :只要大多數副本存活,系統就能讀寫。但廣域網分區可能影響寫入。

寫可用性受限于主數據中心

 :主數據中心宕機,則無法寫入。讀可用性很高。

極高

 :即使數據中心之間完全隔離,每個數據中心依然能獨立處理本地的讀寫請求。

可擴展性

良好

 :可以通過增加分片來水平擴展。

良好

 :緩存層 (Memcache) 和數據庫層都可以通過分片來擴展。

良好

 :通過將 key 分區到不同節點,避免了單點瓶頸,可以水平擴展。

開發者體驗

簡單直觀

 :線性一致性最符合程序員的單機編程直覺,事務功能強大。

復雜

 :需要處理緩存失效、讀到舊數據等問題???key 操作通常需要應用層自己保證。

中等

 :比最終一致性簡單,因為因果關系得到了保證。但需要理解因果上下文,且 Get 事務比標準事務更微妙。

典型用例

金融系統、關鍵元數據存儲、需要強一致性保證的全球性應用。

讀取密集型的社交網絡 Feed、新聞網站、內容分發網絡。

協作編輯工具、有狀態的社交互動(如評論回復)、需要保證操作邏輯順序但對延遲非常敏感的場景。


責任編輯:武曉燕 來源: Pipeliu
相關推薦

2021-06-22 10:22:08

業務IT一致性首席信息官

2020-10-14 10:16:12

CIOIT技術

2017-07-25 14:38:56

數據庫一致性非鎖定讀一致性鎖定讀

2021-07-21 15:50:42

Serverless 業務部署

2022-12-14 08:23:30

2021-02-04 06:30:26

Python編程語言

2023-10-17 16:17:48

關系型數據庫數據一致性

2025-02-10 03:00:00

2021-07-26 06:33:42

CRDT數據CAP

2021-02-05 08:00:48

哈希算法?機器

2023-06-25 09:44:00

一致性哈希數據庫

2021-02-02 12:40:50

哈希算法數據

2021-12-14 07:15:57

MySQLRedis數據

2022-09-15 10:37:46

MySQLRedis數據一致性

2022-01-29 22:00:37

可用性存儲系統

2019-08-30 12:46:10

并發扣款查詢SQL

2020-04-01 15:50:17

TiDBMySQL數據庫

2021-05-19 21:50:46

Hash算法測試

2020-08-05 08:46:10

NFS網絡文件系統

2021-12-26 00:48:05

一致性視圖數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久综合一区 | 91视视频在线观看入口直接观看 | 国内精品视频在线 | 欧美日韩成人网 | 久久国产综合 | 成年男女免费视频网站 | 免费艹逼视频 | 蜜桃特黄a∨片免费观看 | 欧美日韩午夜精品 | 久久久久久免费观看 | 91精品一区| 日本人爽p大片免费看 | 日韩色视频 | 精品一区二区三区在线观看 | 精品亚洲第一 | 亚洲福利| 欧美一区两区 | 亚洲欧美一区二区在线观看 | 成人免费毛片片v | 亚洲欧美中文日韩在线v日本 | 国产成人精品一区二区三区网站观看 | 亚洲一区二区在线播放 | 欧美日韩精品一区二区三区四区 | 亚洲欧美视频一区二区 | 激情欧美日韩一区二区 | 国产一区二区三区视频 | www成人免费| 久久久久国产精品人 | 久久国产视频播放 | 三级黄色大片网站 | 欧美一级免费片 | 午夜av电影院 | 日本一区二区三区四区 | 日韩综合在线播放 | 日韩精品区 | 精品欧美一区二区三区久久久 | 91视频精选 | av一区二区三区四区 | av免费网站在线观看 | 欧美一区二区三区在线免费观看 | 亚洲精品乱码8久久久久久日本 |