亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > 文庫 > 正文

Amazon Aurora 高吞吐量的云原生關系數據庫的策劃考量

2024-09-07 22:12:52
字體:
來源:轉載
供稿:網友
  譯者:Aceking,極數云舟技術合伙人,數據庫內核研發專家,負責企業級云原生數據庫ArkDB等核心數據庫產品,華中科技大學計算機系數據庫方向研究生畢業,原達夢數據庫產品研發工程師,負責達夢數據庫內核開發,長期致力于數據庫原理和源碼開發,精通C/C++,公司內部流傳有他的名言:以后再也不敢說精通C++了。
 
  摘要
 
  Amazon Aurora是亞馬遜網絡服務(AWS)的一個組成部分,對外提供一個OLTP負載類型的關系數據庫服務。本文描述這種架構設計考量。我們確信,高吞吐量的數據處理的主要約束已經從計算、存儲轉移到網絡中來了。Aurora給出一個新穎的架構來解決這個約束,其最顯著的特點是把重做日志(redo)處理下放到專門為Aurora設計的存儲服務中。文章會介紹如何既能減少網絡流量,又能快速崩潰恢復(crash recovery), 還能實現復制失效不損失數據,以及存儲上的容錯,自愈。然后介紹Aurora在多存儲節點中的保持持久狀態的一致性的高效異步方案,避免了代價高昂繁復的恢復協議。最后,我們分享了18個多月運營Aurora產品的經驗,這些經驗是從現代云應用的客戶們對數據庫層的期望中總結的。
 
  關鍵字
 
  數據庫; 分布式系統; 日志處理; 仲裁模型; 復制; 恢復; 性能; OLTP
 
  01 導論
 
  越來越多的IT負載轉移到公有云中,這種全行業的轉變的重大原因包括:公有云服務商能夠彈性按需提供容量,以及只需支付運營費用而不用支付資產費用的模式。許多IT負載需要一個OLTP的關系型數據庫。因此,提供一種等效甚至超越的預置數據庫用以支持這種轉變顯得至關重要。
 
  越來越多現代分布式云服務,通過解耦計算與存儲,以及跨越多節點復制的方式實現了彈性與可伸縮性。這樣做,可以讓我們進行某些操作,例如替換失誤或者不可達的主機,添加復制節點,寫入節點與復制節點的故障轉移,拓展或者收縮數據庫實例的大小等等。在這種環境下,傳統的數據庫系統所面臨的IO瓶頸發生改變。因為IO可以分散到多租戶集群中的多個節點和多個磁盤中,導致單個磁盤和節點不在是熱點。相反,瓶頸轉移到發起這些IO請求的數據庫層與執行這些IO請求的存儲層之間的網絡中。除了每秒包數(packets per second , PPS)以及帶寬這種基本瓶頸外,一個高性能的數據庫會向發起存儲機群并行的寫入,從而放大了網絡流量。某個異常存儲節點的性能,磁盤或者網絡通路,都會嚴重影響響應時間。
 
  雖然數據庫大部分的操作可以互相重疊執行,但是有一些情況需要同步操作,這會導致停頓和上下文切換(可能是線程上下文切換,也可以是內核態與用戶態切換--譯者注)。情況之一,數據庫由于緩沖緩存(buffer cache)未命中,導致進行磁盤讀,讀線程無法繼續只能等待磁盤讀取完成。將臟頁強制趕出并且刷盤,用以給新頁騰出空間。也會導致緩存(cache)不命中。雖然后臺處理,例如檢查點,臟頁寫入線程能減少這種強制行為,但是仍然會導致停頓,上下文切換以及資源爭用。
 
  事務提交是另一個干擾源。一個正在提交的事務的停頓,會阻止另一個事務的進行。處理多節點同步協議的提交,如兩階段提交(2PC)對云級規模(cloud-scale)的分布式系統來說更是一個挑戰。這些協議不能容忍失敗。但是高規模(high-scale)總是充斥著軟硬件失效的“背景噪聲”。同時還有高延遲,因為高規模系統總是跨多個數據中心分布的。
 
  本文中,我們介紹Amazon Aurora,一種新型的數據庫服務,通過大膽激進的使用高分布性的云環境中的日志來解決上述問題。我們給出了一種使用多租戶可伸縮的存儲面向服務的架構(圖1),這種存儲服務與數據庫實例集群松耦合,并且從中提取虛擬的分段的重做日志(redo log).雖然每個數據庫實例仍然有大部分的傳統的數據庫內核(查詢處理,事務,鎖,緩沖緩存,訪問方法,回滾管理), 但是一些功能(重做日志,持久存儲,崩潰恢復,備份恢復)已經剝離,放到存儲服務中。
  Amazon Aurora:高吞吐量的云原生關系數據庫的設計考量
 
  我們的架構與傳統方法相比,有三大明顯優勢:首先,把存儲建為一個容錯、自愈、跨多個數據中心的獨立服務,我們可以保護數據庫,使得網絡層或存儲層的性能差異,暫時或永久的失效,對數據庫不再有影響。我們觀察到持久存儲的失效可以作為一個長時-可用性事件(longlasting availability event)來建模, 而可用性事件可以作為一個長時性能變動來建模,長時性能變動已經有一個設計良好的系統統一處理。 其次,通過存儲寫日志的方式,可以把網絡的IOPS減少一個量級。一旦我們移除了這個瓶頸,就可以大膽的在大量的其他爭用點上做優化,就能獲取比我們基于的MySQL基線源碼更明顯的吞吐量的提升。第三,我們把一些最重要最復雜的功能(如:備份、日志恢復)從數據庫引擎中一次性代價高昂的操作轉變為分攤到大型分布式機群的連續異步的操作。從而獲得近乎瞬時的崩潰恢復,無需檢查點,同時,備份的代價也不高昂,不會影響前臺處理。
 
  本文介紹了我們的三點貢獻
 
  如何分析云級規模下的持久性,如何設計具有對相關失效具有彈性的仲裁系統。(段2)
 
  如何使用靈巧的分離存儲,使得到存儲的負載低于傳統的1/4。(段3)
 
  如何在存儲分布式系統中消除多階段同步,崩潰恢復,檢查點。(段4)
 
  我們把三個創意組合在一起,設計出Auraro總體架構(段5),隨后(段 6)檢視我們的性能結果,(段7)展示我們的運營經驗,(段8)概述相關的工作,(段9)給出結束語。
 
  02 可伸縮的持久性
 
  如果數據庫不做其他的事情,必須滿足如下要求:一旦寫入,必須可讀。不是所有系統可以做到這一點。在本段中我們討論了aurora仲裁模型背后的原理,為什么我們要將存儲分段,如何將持久性與可獲得性結合在一起,減少抖動,并且幫助解決大規模存儲機群的運營問題。
 
  2.1 復制與相關失效
 
  實例的生命周期與存儲的生命周期并沒有太大的相關。實例失效,用戶會將其關閉,他們會根據負載情況調整其大小。這些特點有助于我們將計算層與存儲層解耦。
 
  一旦你這樣做了,這些存儲節點和磁盤仍然會失效,因此需要某種形式的復制實現對失效的彈性。在規模大的云環境下,存在持續的下層背景噪聲,如節點失效,磁盤、網絡路徑失效。每一種失效有不同的持續時間和破壞半徑。比如,某個節點暫時無法網絡到達,重啟導致的臨時停機時間,磁盤,節點,機架,網關的葉節點或者主干節點, 甚至整個數據中心的永久失效。
 
  在存在復制的系統中,實現容錯使用一種[]基于仲裁的投票協議。如果一個復制數據項有V個副本,每個副本可以賦予一個投票,一次讀操作或者寫操作分別需要Vr個投票的讀仲裁,或者Vw個投票的寫仲裁。那么要達到一致性,仲裁必須兩個規則,首先,每次讀操作必須能獲得最新的修改。公式為:
 
  Vr+Vw > V,
 
  這個規則,保證讀取的節點集與寫節點集有交集,讀仲裁至少能讀到一個最新版本的數據副本。其次,每次寫必須占副本多數,用以避免寫沖突。即公式:
 
  Vw > V/2,
 
  一個能容忍復制數據項(V=3)一個節點損失的通用的方法是,寫需要2/3的投票仲裁(Vw=2),讀也需要2/3投票仲裁(Vr=2)。
 
  我們確信2/3的投票仲裁數是不充分的,為了解釋為什么,先了解AWS的一個概念,可用區(AZ,availability zone)是區域(region)的子集。一個可用區與其他可用區可以低延遲的連接,但是可以隔離其他可用區的故障,例如,電源,網絡,軟件部署,洪水等等??鏏Z的分布復制數據可以保證典型的大規模故障模式只影響一個復制副本,這意味著,可以簡單地放三個副本到在不同的可用區,就可以支持大范圍的事件容錯,但是少量的個別失效事件除外。
 
  然而,在一個大的存儲機群,故障的背景噪聲意味著,任意給一個時刻,都會有一個節點或者磁盤的子集可能壞掉并修復。這些故障可能在可用區A、B、C中獨立分布。然而,可用區C由于火災、洪水、屋頂倒塌等等,與此同時,可用區A或者B也有故障(故障背景噪聲),就打破了任意一個副本的仲裁過程。在這一點上,2/3票數的讀取仲裁模型,已經失去了兩個副本,因此無法確定第三個副本是否是最新的。換一句話說,雖然,每個可用區的個體復制節點故障互不相關,但是一個可用區的失效,則與可用區所有的節點和磁盤都相關。仲裁系統要能容忍故障背景噪聲類型的故障與整個可用區的故障同時發生的情況。
 
  在Aurora中,我們選用一種可以容兩種錯誤的設計:(a)在損失整個可用區外加一個節點(AZ+1)情況下不損失數據。
 
  (b)損失整個可用區不影響寫數據的能力。
 
  在三個可用區的情況下,我們把一個數據項6路寫入到3個可用區,每個可用區有2個副本。使用6個投票模型(V=6),一個寫仲裁要4/6票數(Vw=4),一個讀仲裁需要3/6票數(Vr=3),在這種模型下,像(a)那樣丟失整個可用區外加一個節點(總共3個節點失效),不會損失讀取可用性,像(b)那樣,損失2個節點,乃至整個可用區(2個節點),仍然保持寫的可用性。保證讀仲裁,使得我們可以通過添加額外的復制副本來重建寫仲裁。
 
  2.2 分段的存儲
 
  現在我們考慮AZ+1情況是否能提供足夠的持久性問題。在這個模型中要提供足夠的持久性,就必須保證兩次獨立故障發生的概率(平均故障時間,Mean Time to Failure, MTTF)足夠低于修復這些故障的時間(Mean Time to Repair, MTTR)。如果兩次故障的概率夠高,我們可能看到可用區失效,打破了沖裁。減少獨立失效的MTTF,哪怕是一點點,都是很困難的。相反,我們更關注減少MTTR,縮短兩次故障的脆弱的時間窗口。我們是這樣做的:將數據庫卷切分成小的固定大小的段,目前是10G大小。每份數據項以6路復制到保護組(protection Group,PG)中,每個保護組由6個10GB的段組成,分散在3個可用區中。每個可用區持有2個段。一個存儲卷是一組相連的PG集合,在物理上的實現是,采用亞馬遜彈性計算云(ES2)提供的虛擬機附加SSD,組成的大型存儲節點機群。組成存儲卷PG隨著卷的增長而分配。目前我們支持的卷沒有開啟復制的情況下可增長達64TB。
 
  段是我們進行背景噪聲失效和修復的獨立單元。我們把監視和自動修復故障作為我們服務的一部分。在10Gbps的網絡連接情況下,一個10GB的段可以在10秒鐘修復。只有在同一個10秒窗口中,出現兩個段的失效,外加一個可用區的失效,并且該可用區不包含這兩個段,我們才可以看到仲裁失效。以我們觀察的失效率來看,幾乎不可能,即使在為我們客戶管理的數據庫數量上,也是如此。
 
  2.3 彈性的運營優勢
 
  一旦有人設計出一種能對長時失效自然可復原(彈性)的系統,自然也對短時失效也能做到可復原。一個能處理可用區長時失效的系統,當然也能處理像電源事故這樣的短時停頓,或者是因糟糕的軟件部署導致的回滾。能處理多秒的仲裁成員的可用性的損失的系統,也能處理短時的網絡的阻塞,單個存儲節點的過載。
 
  由于我們系統有高容錯性,可以利用這點,通過引起段不可用,做一些維護工作。比如 熱管理就直截了當,我們直接把把熱點磁盤或節點的一個段標記為壞段,然后仲裁系統通過在機群中遷移到較冷的節點來修復。操作系統或者安全打補丁在打補丁時,也是一個短時不可用事件。甚至,軟件升級也可以通過這個方式做。在某個時刻,我們升級一個AZ,但是確保PG中不超過一個成員(段或者節點)也在進行補丁。因此,我們的系統可以用敏捷的方法論在我們的存儲服務中進行快速部署。
 
  03 日志即數據庫
 
  本段解釋為什么傳統的數據庫系統在采用段2所述的分段的復制存儲系統,仍難以承受網絡IO和同步停頓導致的性能負擔。我們解釋了將日志處理剝離到存儲服務的方法,以及實驗證實這種方法如何顯著的降低網絡IO,最后講述了最小化同步停頓和不必要寫操作的各種技術。
 
  3.1 寫放大的負擔
 
  我們的存儲卷的分段存儲,以及6路寫入4/6仲裁票數的模型,具有高彈性。但是不幸的是,這種模型會讓傳統的數據庫如MYSQL無法承受這種性能負擔,因為應用往存儲做一次寫入,會產生存儲中許多不同的真實IO。高量的IO又被復制操作放大,產生沉重的PPS(每秒包數,packets per second)負擔。同時,IO也會導致同步點流水線停滯,以及延遲放大。雖然鏈復制[8]以及其他替代方案能減少網絡代價,但是仍然有同步停頓以及額外的延遲。讓我們看看傳統的數據庫寫操作是怎么進行的把。像Mysql這樣的系統,一邊要向已知對象(例如,heap文件,B-數等等)寫入頁,一邊要像先寫日志系統(write-ahead log, WAL)寫入日志。日志要記錄頁的前像到后像的修改的差異。應用日志,可以讓頁由前像變為后像。
  而實際上,還有其他的數據也要寫入。舉個例子,考慮一下如圖2所示以主從方式實現的同步鏡像mysql配置, 用以實現跨數據中心的高可用性。AZ1是主mysql實例,使用亞馬遜彈性塊存儲(EBS),AZ2是從Mysql實例,也用EBS存儲,往主EBS的寫入,均要通過軟件鏡像的方法同步到從EBS卷中。
  
   引擎需要寫入的數據類型:重做日志,binlog日志,修改過數據頁,double-write寫,還有元數據FRM文件。圖中給了如下的實際IO順序:
 
  步驟1步驟2,像EBS發起寫操作,并且會像本地可用區的EBS鏡像寫入,以及操作完成的響應消息。
 
  步驟3,使用塊級鏡像軟件將寫入轉入到從節點。
 
  步驟4和5從節點將傳入的寫入操作執行到從節點的EBS和它的EBS鏡像中。
 
  上述MySQL的鏡像模型不可取,不僅僅因為它如何寫入的,也因為它寫進了什么數據。首先,1,3,5步驟是順序同步的過程,由于有許多順序寫入,產生了額外的延遲。抖動也被放大,哪怕是在異步寫的時候,因為它必須等待最慢的操作,讓系統任憑異常節點的擺布。按照分布式視角來看,這個模型可以視作4/4的寫仲裁,在失效或者異常節點的異常性能面前,顯得十分脆弱。其次,OLTP應用產生的用戶操作,可以產生許多不同類型的寫入,而這些數據寫入方式雖然都不同,但是卻表示同樣的信息。例如,往雙寫緩沖的寫入,主要是為了防止存儲層頁的損壞,(但是內容與頁的普通寫入是一樣的)
 
  3.2 日志處理分離到存儲
 
  傳統數據庫修改一個頁,就會產生日志記錄。調用日志應用器,應用日志到內存中該頁數據的前像,得到該頁的后像。事務提交前日志必須已經寫入,而數據頁則可推后寫入。在Aurora中,通過網絡的寫入只有重做日志。數據庫層不寫入數據頁,也沒有后臺寫入,沒有檢查點,沒有Cache替換。相反,日志應用器已經放置到存儲層,存儲層在后臺生成,或者按需生成數據庫的數據頁。當然,從頭開始應用所有修改的,代價讓人難以承受,因此,我們在后臺持續生成數據頁以避免每次抓取時在重新生成這些頁。從正確性的角度來看,后臺生成是完全可選的:就引擎而言,日志即數據庫 ,存儲所有具體化出來的頁,都可以視作日志應用的緩存。與檢查點不同,只有那些很長修改鏈的頁才會要重新具化 ,檢查點由整個日志鏈長度控制,而Aurora由給定頁的日志鏈長度來控制。
 
  盡管復制會導致的寫放大,我們的方法明顯能減少網絡負載,而且保證性能與持久性。在令人尷尬的并行寫入,存儲能超載IO而不影響數據庫引擎的寫吞吐能力。舉個例子,圖3所示,是一個一主多從Aurora集群,部署在多個可用區中。在這個模型中,主庫往存儲寫入日志,并且把這些日志與元數據更新發送給從節點?;诠泊鎯δ繕耍ㄒ粋€邏輯段,比如,PG)的一批批日志都是完全有序的。把每個批次以6路傳輸給復制節點,存儲引擎等待4個或4個多的回應,用以滿足寫仲裁條件,來判斷日志在持久上或硬化上是否有問題。復制節點應用這些日志記錄來更新自身的緩存緩沖。
 
  為了測量網絡IO的狀況,我們在以上所述的兩種mysql配置下,進行了100GB的數據集只寫負載的sysbench[9]測試:一種是跨多個可用區的mysql鏡像配置,另一個是Aurora的RDS,在r3.8large EC2的實例中運行了30分鐘。
 
  實驗結果如表1所示。在30分鐘的時間里,在事務上,Aurora比mysql鏡像多35倍,雖然Aurora的寫放大了6倍,但是每個事務寫IO仍然比mysql鏡像小7.7倍。這里并沒有記錄EBS的鏈式復制與mysql跨可用區的寫。每個存儲節點,只是6個復制節點中的一個,因此看不到寫放大。這里的IO數量減少了46倍。寫入了更少的數據,省下的網絡能力,可以激進地通過復制實現持久性與可用性,并在發起并行請求時,最小化抖動的影響。
  Amazon Aurora:高吞吐量的云原生關系數據庫的設計考量
 
  把日志處理放到存儲服務中,也可以最小化崩潰恢復的時間,來提高可用性,并且消除檢查點、后臺寫、備份等后臺處理所帶來的抖動。我們再看崩潰恢復。傳統數據庫在崩潰之后,必須從最近的檢查點開始,將日志重演并要報保證所有的保存的日志都被應用。在Aurora中,持續的日志應用發生在存儲中,并且它是持續的,異步的,分散在機群中的。任何一次讀頁請求,如果該頁不是當前版本,則要應用一些重做日志。因此,崩潰恢復過程已經分散到所有的正常的前臺處理中,不需要在數據庫啟動的時候執行。
 
  3.3 存儲服務的設計點
 
  我們的存儲服務設計的核心原則是最小化前臺寫請求的延遲。我們把大部分的存儲處理移到了后臺。鑒于存儲層前臺的請求峰值與平均值之間的自然變動,我們有足夠的時間在前臺請求之外進行這些處理。而且我們也有機會用cpu換磁盤。比如說,當存儲節點忙于前端請求處理,就沒有必要進行舊頁的垃圾回收(GC),除非該磁盤快滿了。Aurora中,后臺處理與前臺處理負相關。與傳統的數據庫不一樣,傳統數據庫的后臺寫頁、檢查點處理與系統的的前臺的請求量正相關。如果系統中有積壓請求,我們會抑制前端請求,避免形成長隊列。因為系統中的段以高熵的形式(高混亂程度)分布在不同的存儲節點中,限制一個存儲節點在4/6仲裁系統中自然的作為慢節點處理。
 
  現在以更多的細節來觀察存儲節點各種活動。如圖4所示,包含了如下若干步驟:
 
  1、接收日志記錄并且放入內存隊列中。
 
  2、保存到磁盤并且返回應答。
 
  3、組織日志記錄,并且識別日志中的空白,因為有些批次的日志會丟失。
 
  4、與對等節點交流(gossip)填住空白。
 
  5、合入日志到新的數據頁。
 
  6、周期地將新數據頁和日志備份到S3。
 
  7、周期的回收舊版本。
 
  8、校驗頁中的CRC編碼。
 
  注意,以上各個步驟不全是異步的,1 和 2 在前臺路徑中有潛在的延遲影響。
 
  04 日志前行
 
  本段中,我們介紹數據庫引擎生成的日志如何在持久狀態,運行狀態,復制狀態始終保持一致。特別是,如何不需要2PC協議高效地實現一致性。首先,我們展示了如何在崩潰恢復中避免使用高昂的重做處理。我們解釋正常操作中如何維護運行狀態與復制狀態。最后,我們披露崩潰恢復的細節。
 
  4.1 解決方案草圖:異步處理
 
  因為我們把數據庫建模為一個日志流,事實上日志作為有序的修改序列,這點我們也要利用。實際上,每個日志都有與之關聯的日志序列號(Log Sequence Number, LSN), LSN是由數據庫產生的單調遞增的值。
 
  這就可以使我們簡化共識協議,我們采用異步方式協議而不是2PC協議。2PC協議交互繁復并且不容錯。在高層次上,我們維護一致性與持久化的點,在接收還未完成的存儲請求的響應時推進這些點,并且是持續的推進。由于單獨的存儲節點可能會丟失一個或者多個日志記錄,它們可以與同PG的其他成員進行交流,尋找空白并填補空洞。運行狀態是由數據庫維護的,我們可以直接從存儲段讀取而不需要讀仲裁。但在崩潰恢復時候,運行狀態已丟失需要重建的時候除外,這時候仍需要讀仲裁。
 
  數據庫可能有很多獨立的未完成的事務,這些事務可以與發起時順序完全不同的順序完成(達到持久化的結束狀態)。假設數據庫奔潰或重啟,這些獨立事務是否回滾的決策是分開的。則跟蹤并撤銷部分完成事務的邏輯保留在數據庫引擎中,就像寫入簡單磁盤一樣。在重啟過程中,在允許數據庫訪問存儲卷之前,存儲進行自身的崩潰恢復,而不關心用戶層的事務。當然,要保證數據庫看到的存儲系統是單一的視圖,盡管實際上存儲是分布式的。
 
  存儲服務決定一個最高的LSN,保證在在這個LSN之前的日志記錄都是可以讀取的。(VCL,volume Complete LSN)。在恢復過程中,對應LSN任何高于VCL的重做日志都要丟棄。但是,數據庫還可以進一步約束條件,取其子集,用以標記哪些日志可以丟棄。這個子集就是CPL集(Consistency Point LSNs)。因此,我們還可以定義一個VDL(volume durable LSN)為小與VCL的最大CPL。舉個例子,雖然數據完成到LSN為1007,但是數據庫標記的CPL集為900,1000,1100。在這種情況下,我們丟棄的位置為1000(1000以后的都要丟棄),也就是我們完成到1007(VCL),但是持久到1000(VDL)。
 
  因此,完成性與持久性是不同的。CPL可以看作存儲事務必須有序接受的某種限制形式。如果客戶端沒有對此加以區別,我們把每個日志記錄標記為一個CPL。實際上,數據庫與存儲以如下方式交互:
 
  每個數據庫層面的事務,都被打斷為多個迷你事務(mini-transactions,MTRs),迷你事務是有序的,而且是原子的方式執行(就是不可分割地執行)。
 
  一個迷你事務由多條連續的日志記錄組成(要多少有多少)。
 
  迷你事務的最后一條日志記錄就是一個CPL
 
  在崩潰恢復過程中,數據庫告訴存儲層為每個PG建立一個持久點,用來建立一個VDL,然后發起丟棄高于VDL日志的命令。
 
  4.2 正常操作
 
  我們現在描述數據庫的“正常操作”, 依次關注寫、讀、提交與復制。
 
  4.2.1 寫
 
  在Aurora中,數據庫不停地與存儲服務交互,并且維護狀態以建立仲裁,推進卷持久性(volume durablity),并且在提交時注冊事務。舉個例子,在正常/前轉路徑中,當數據庫接收到響應消息為每批日志建立寫仲裁,則推進當前VDL。在任意給定時刻,數據庫可能有大量的并發事務活動。每個事務均產生日志,數據庫又為每條日志分配唯一的有序的LSN,但是分配受限于一條原則,LSN不能大于當前VDL與一個常量值的和。這個常量稱為LSN分配限值(LAL, LSN Allocation limit)(目前設置為一千萬)。這個限值保證數據庫的LSN不超出存儲系統太遠,在存儲或者網絡跟不上時,提供一個反壓,用以調節來入的寫請求。
 
  注意,每個PG的每個段僅僅能看到存儲卷日志記錄的子集,該子集的日志僅僅影響駐留于該段的頁。每個日志記錄包含一個指向PG中前一個日志記錄的反向鏈接。這些反向鏈接可以跟蹤達到每個段的日志記錄的完成點,用以建立段完成LSN(Segment Complete LSN, SCL), SCL是表示一個最大LSN,在該LSN之下所有的日志記錄均已經被該PG接收到。存儲節點使用SCL相互交流,用來查找并交換獲得自己確實的那部分日志。
 
  4.2.2 提交
 
  在Aurora中,事務提交是異步完成的。當客戶端提交一個事務,處理事務提交的線程記錄一個“提交LSN”(commit lsn)到一個單獨的等待提交的事務列表中,然后將事務擱置去處理其他任務。這相當于WAL協議是基于事務提交的完成,也即當且僅當最新的VDL大于或等于事務的提交LSN的時候。隨著VDL的推進,數據庫在正在等待提交事務識別符合條件的,由專有線程向正在等待的客戶端發送提交響應消息。工作線程不會因為提交事務而暫停,它們僅是把其他的掛起的請求拉起繼續處理。
 
  4.2.3 讀
 
  在Aurora中,和大部分的數據庫一樣,頁由buf和cache提供。只有頁是否在Cache中還存疑的時候,才會導致存儲IO請求。
 
  如果buf cache已滿,系統找出受害頁,將其趕出cache。在傳統數據庫中,如果受害頁是“臟頁“,替換前要刷盤。這就保證后續的頁的提取,總是最新數據。然而Aurora在驅逐頁的時候并沒有將頁寫出,但它強制執行一個保證:在buff或cache中的頁始終是最新的版本。實現這一保證的措施是,僅僅將“頁LSN(Page LSN)“(與頁相關最新的日志LSN)大于或者等于VDL。這個協議保證了:(a)頁的所有修改在日志中都已硬化, (b)在cache沒命中的時候,獲得最近的持久化版本的頁,請求當前VDL版本頁就足夠了。
 
  數據庫在正常情況下不需要使用讀仲裁來建立一致性。當從磁盤讀取一個頁,數據庫建立一個讀取點(read-point)
 
  表示讀取發起時候的VDL。數據庫可以選擇一個相對于讀取點數據完整存儲節點,從而取得到最新版本的數據。存儲節點返回的數據頁一定與數據庫的迷你事務(mtr)的預期語義一致。因為,數據庫管理著往存儲節點日志的饋送,跟蹤這個過程(比如,每個端的SCL),因此它知道那些段滿足讀取要求(那些SCL大與讀取點的段)。然后直接向有足額數據的段發起讀請求。
 
  考慮到數據庫知道那些讀操作沒有完成,可以在任何時間在每個PG的基礎上計算出最小的讀取點LSN(Minimum Read Point LSN). 如果有存儲節點交流寫的可讀副本,用來建立所有節點每個PG的最小讀取點,那么這個值就叫做保護組最小讀取點LSN(Protection Group Min Read Point LSN, PGMRPL). PGMRPL用來標識“低位水線”,低于這個“低位水線”的PG日志記錄都是不必要的。換句話說,每個存儲段必須保證沒有低于PGMRPL的讀取點的頁讀請求。每個存儲節點可以從數據庫了解到PGMRPL,因此,可以收集舊日志,物化這些頁到磁盤中,再安全回收日志垃圾。
 
  實際上,在數據庫執行的并發控制協議,其數據庫頁和回滾段組織方式,與使用本地存儲的傳統數據庫的組織方式并無二致。
 
  4.2.4 復制節點(replicas)
 
  在Aurora中,在同一個存儲卷中,一次單獨的寫最多有15個讀復制。因此,讀復制在消耗存儲方面,并沒有增加額外的代價,也沒有增加額外的磁盤寫。為了最小化延遲,寫生成的日志流除了發送給存儲節點,也發送所有的讀復制節點。在讀節點中,數據庫依次檢查日志流的每一天日志記錄。如果日志引用的頁在讀節點的緩沖緩存中,則日志應用器應用指定的日志記錄到緩存中的頁。否則,簡單丟棄日志記錄。注意從寫節點的視角來看,復制節點是異步消費日志流的,而寫節點獨立于復制節點響應用戶的提交。復制節點在應用日志的時候必須遵從如下兩個重要規則:(a)只有LSN小于或等于VDL的日志記錄才能應用。(b)只有屬于單個迷你事務(MTR)的日志記錄才能被應用(mtr不完整的日志記錄不能應用),用以保證復制節點看到的是所有數據庫對象的一致視圖。實際上,每個復制節點僅僅在寫節點后面延遲一個很短的時間(20ms甚至更少)。
 
  4.3 恢復
 
  大部分數據庫(如ARIES)采用的恢復協議,取決于是否采用了能表示提交事務所有的精確的內容的先寫日志(write ahead log,WAL)。這些系統周期的做數據庫檢查點,通過刷臟頁到磁盤,并在日志中寫入檢查點記錄,粗粒度地建立持久點。在重啟的時候,任何指定的頁都可能丟失數據,丟失的數據可能是已經提交了的,也可能包含未提交的。因此,在崩潰恢復的過程中,系統從最近的檢查點開始處理日志,使用日志應用器將這些日志應用日志到相關數據庫頁中。通過執行相應的回滾日志記錄,可以回滾崩潰時正在運行的事務,這個過程給數據庫帶來了故障點時候的一致性狀態。崩潰恢復是一個代價高昂的操作,減少檢查點間隔可以減少代價,但是這會帶來影響前端事務的代價。傳統數據庫需要在兩者做權衡,而Aurora則不需要這樣的權衡。
 
  傳統數據庫有一個重要的簡化原則是,使用同一個日志應用器,推進數據庫狀態與進行同步的日志恢復。并且此時從前端看來,數據庫庫是脫機的。Aurora設計也遵循同樣的原則。但是日志應用器已經從數據庫中解耦出來,直接在存儲服務中在總是在后臺并行運行。一旦數據庫開始執行卷恢復,它會與存儲服務合作來進行。結果是,Aurora數據庫恢復速度非??欤ㄍǔT?0秒以下),哪怕是每秒運行100,000條語句時候崩潰后情況下做恢復。
 
  Aurora數據庫不需要在崩潰之后重建運行狀態。在崩潰的情況下,它會聯系每個PG,只要數據滿足了寫仲裁的條件,段的讀仲裁完全可以保證能發現這些數據。一旦數據庫為每個PG建立了讀仲裁,則可以重新計算VDL,生成高于該VDL的丟棄范圍(truncation range),保證這個范圍后的日志都要丟棄,丟棄范圍是這是數據庫能可以證明的最大可能保證未完成的日志(不是完整MTR的日志)可見的結束LSN。然后,數據庫可以推斷出LSN分配的上限,即LSN的上限能超過VDL多少(前面描述的一千萬)。丟棄范圍使用時間數字(epoch number)作為版本,寫在存儲服務中,無論崩潰恢復還是重啟,都不會弄混丟棄日志的持久化。
 
  數據庫仍然需要做undo恢復,用來回滾崩潰時正在進行的事務。但是,回滾事務可以在數據庫聯機的時候進行,在此之前,數據庫已經通過回滾段的信息,建立了未完成事務列表。
 
  05 放在一起
 
  本段中,我們描述如圖5所示Aurora的各個模塊。
 
  Aurora庫是從社區版的mysql/innodb數據庫fork出來的分支,與之不同的主要在讀寫磁盤數據這塊。在社區版的Innodb中,數據的寫操作修改buffer中的頁,相應的日志也按LSN順序寫入WAL的緩存中。在事務提交的時候,WAL協議只要求事務的日志記錄寫入到磁盤。最終,這個被修改的緩存頁使用雙寫技術寫入到磁盤中,使用雙寫的目的是為了避免不完整的頁寫(partial page writes)。這些寫操作在后臺執行,或者從cache驅逐頁出去時候執行,或者在檢查點時候執行。除IO子系統外,innodb還包含事務子系統,鎖管理器,B+樹的實現,以及“迷你事務”(MTR)。innodb的將一組不可分割執行(executed atomically)的操作稱為一個迷你事務(例如,分裂/合并B+樹頁)。
  
  在Aurora的Innodb變種中,mtr中原先那些不可分割執行日志,按照批次組織,分片并寫入到其所屬的PG中,將mtr最后一個日志記錄標記為一致點(consistency point), Aurora在寫方面支持與社區mysql一樣的隔離等級(ANSI標準級別,Snapshot 隔離級,一致性讀)。Aurora讀復制節點可以從寫節點獲取事務開始和提交的持續信息,利用這些信息支持本地只讀事務的snapshot隔離級。注意,并發控制是完全有數據庫實現的,對存儲服務沒有任何影響。存儲服務為下層數據提供了展現了一個統一視圖,與社區版本innodb往本地存儲寫數據的方式,在邏輯上完全等效。
 
  Aurora使用亞馬遜關系數據庫服務(RDS)作為控制平臺。RDS包含一個數據庫實例上的代理,監控集群的健康情況,用以決定是否進行故障切換,或者是否進行實例替換。而實例可以是集群中的一個,集群則由一個寫節點,0個或者多個讀復制節點組成。集群中所有的示例,均在同一個地理區域內(例如,us-east-1,us-west-2等)。但是放置在不同的可用區內。連接同一個區域的存儲機群。為了安全起見,數據庫、應用、存儲之間的連接都被隔離。實際上,每個數據庫實例都可以通過三個亞馬遜虛擬私有云(VPC)進行通信:用戶VPC,用戶應用程序可以通過它與數據庫實例進行交互。RDS VPC,通過它數據庫節點之間,數據庫與控制平臺之間進行交互。存儲VPC,用以進行數據庫與存儲之間的交互。
 
  存儲服務部署在EC2虛擬機集群中。這些虛擬機在一個區域內至少跨三個可用區,共同負責多用戶提供存儲卷、以及這些卷的讀寫、備份、恢復。存儲節點負責操作本地SSD,與對等節點或數據庫實例進行交互,以及備份恢復服務。備份恢復服務持續的將數據的改變備份到S3,并且依據需求從S3恢復。存儲控制平臺使用亞馬遜DynamoDB服務存儲集群的永久數據、存儲卷配置、卷的元數據、備份到S3的數據的描述信息。為了協調長時間的操作,如數據庫卷恢復操作,修復(重新復制)存儲節點失效等,存儲控制平臺使用亞馬遜簡單工作流服務(Amazon Simple Workflow Service)。維持高可用性,需要在影響用戶之前,主動地、自動地、盡早地檢測出真正的或潛在的問題。存儲操作各個關鍵的方面都要通過metric收集服務進行持續監控,metric會在關鍵性能、可用性參數值指示出現異常進行報警。
 
  06 性能結果
 
  在本段中,我們分享了自2015五月Aurora達到“GA”(基本可用)之后的運營經驗。我們給出工業標準的基準測試結果,以及從我們客戶獲得的性能結果。
 
  標準基準測試結果
 
  這里展示了在不同的試驗下,Aurora與mysql的性能對比結果。實驗使用的是工業標準的基準測試,如sysbench和TPC-C的變種。我們運行的mysql實例,附加的存儲是有30K IPOS的EBS存儲卷,除非另有說明,這些mysql運行在有32 vCPU和244G內存的r3.8xlarge EC2實例中,配備了Intel Xeon E5-2670 v2 (Ivy Bridge) 處理器,r3.8xlarge的緩存緩沖設置到170GB。
 
  07 學到的經驗
 
  我們可以看到客戶運行的大量的各種應用,客戶有小型的互聯網公司,也有運行大量Aurora集群的復雜組織。然而許多應用的都是標準的用例,我們關注于這些云服務應用中共同的場景和期望,以引領我們走向新方向。
 
  7.1 多租戶與數據庫整合
 
  我們許多客戶運營軟件即服務(SaaS)的業務,有專有云業務客戶,也有將企業部署的遺留系統轉向SaaS的客戶。我們發現這些客戶往往依賴于一種不能輕易修改應用。因此,他們通常把他們自己的不同用戶通過一個租戶一個庫或模式的方式整合到一個單實例中。這種風格可以減少成本:他們避免為每個用戶購買一個專有實例,因為他們的用戶不可能同時活躍。舉個例子,有些SaaS的客戶說他們有50,000多用戶。
 
  這種模式與我們眾所周知的多租戶應用如Saleforce.com不同,saleFore.com采用的多租戶模式是,所有用戶都在同一模式統一的表中,在行級記錄中標記租戶。結果是,我們看到進行數據庫整合的用戶擁有巨量的表。生產實例中擁有超過150,000個表的小數據庫非常的普遍。這就給管理如字典緩存等元數據的組件帶來了壓力。這些用戶需要(a)維持高水平的吞吐量以及并發的多用戶連接,(b)用多少數據就購買提供多少的模式,很難進一步預測使用多少存儲空間,(c)減少抖動,最小化單個用戶負載尖峰對其他租戶的影響。Aurora支持這些屬性,對這些SaaS的應用適配得很好。
 
  7.2 高并發自動伸縮負載
 
  互聯網負載需要處理因為突發事件導致的尖峰流量。我們的主要客戶之一,在一次高度受歡迎的全國性電視節目中出現特殊狀況,經歷了遠高于正常吞吐量峰值的尖峰,但是并沒有給數據庫帶來壓力。要支持這樣的尖峰,數據庫處理大量并發用戶連接顯得十分的重要。這在Aurora是可行的,因為下層存儲系統伸縮性如此之好。我們有些用戶運行時都達到了每秒8000個連接。
 
  7.3 模式升級
 
  現代web應用框架,如Ruby on Rails,都整合了ORM(object-relational mapping, 對象-關系映射)。導致對于應用開發人員來說,數據庫模式改變非常容易,但是對DBA來說,如何升級數據庫模式就成為一種挑戰。在Rail應用中,我們有關于DBA的第一手資料:“數據庫遷移“,對于DBA來說是"一周做大把的遷移“,或者是采用一些回避策略,用以保證將來遷移的不那么痛苦。而Mysql提供了自由的模式升級語義,大部分的修改的實現方式是全表復制。頻繁的DDL操作是一個務實的現實,我們實現了一種高效的在線DDL,使用(a)基于每頁的數據庫版本化模式,使用模式歷史信息,按需對單獨頁進行解碼。(b)使用寫時修改(modify-on-write)原語,實現對單頁的最新模式懶更新。
 
  7.4 可用性與軟件升級
 
  我們的客戶對云原生數據庫如何解決運行機群和對服務器的補丁升級的矛盾,有著強烈的期望。客戶持有某種應用,而這些應用有主要使用Aurora作為OLTP服務支持。對這些客戶來說,任何中斷都是痛苦的。所以,我們許多客戶對數據庫軟件的更新的容忍度很低,哪怕是相當于6周30秒的停機時間。因此,我們最近發布了零停機補?。▃ero downtime patch)特性。這個特性允許給用戶補丁但是不影響運行的數據庫連接。
 
   ZDP通過尋找沒有活動事務的瞬間,在這瞬間將應用假脫機到本地臨時存儲,給數據庫引擎打補丁然后更新應用狀態。在這個過程中,用戶會話仍然是活動的,并不知道數據庫引擎已經發生了改變。
 
  08 相關工作
 
  在本段中,我們討論其他人的貢獻,這些貢獻與Aurora采用的方法相關。
 
  存儲與引擎解耦雖然傳統的數據都被設計成單內核的守護進程。但是仍有相關的工作,將數據庫內核解耦成不同的組成部分,例如,Deuteronomy就是這樣的系統,將系統分為事務組件(Tranascation Component, TC)和數據組件(Data Componet ,DC).事務組件提供并發控制功能已經從DC中做崩潰恢復的功能,DC提供了一個LLAMA之上的訪問方法。LLAMA是一個無閂鎖的基于日志結構的緩存和存儲管理系統。Sinfonia 和 Hyder則從可拓展的服務抽出了事務性訪問方法,實現了可以抽象使用這些方法的數據庫系統。Yesquel系統實現了一個多版本分布式平衡樹,并且把將并發控制從查詢處理中獨立出來。Aurora解耦存儲比Deuteronomy、Hyder、Sinfonia更為底層。在Aurora中,查詢處理,事務,并發,緩存緩沖以及訪問方法都和日志存儲解耦,并且崩潰恢復作為一個可拓展的服務實現的。
 
  分布式系統 在分區面前,正確性與可用性的權衡早已為人所知,在網絡分區去情況下,一個副本的可串行化是不可能的,最近Brewer的CAP理論已經證明了在高可用系統在網絡分區的情況下,不可能提供“強”一致性。這些結果以及我們在云級規模的經驗,激發了我們的一致性目標,即使在AZ失效引起分區的情況下也要一致性。
 
  Brailis等人研究了高可用事務系統(Highly Available Transactions, HATs)的問題。他們已經證明分區或者高網絡延遲,并不會導致不可用性??纱谢?、snapshot隔離級、可重復讀隔離級與HAT不兼容。然而其他的隔離級可以達到高可用性。Aurora提供了所有的隔離級,它給了一個簡單的假設,即任何時候都只有一個寫節點產生日志,日志更新的LSN,是在單個有序域中分配的。
 
  Google的Spanner提供了讀和寫的外部一致性,并且提供了跨數據在同一個時間戳上全球一致性讀。這些特性使得spanner可以一致性備份,一致性分布式查詢處理以及原子模式更新,這些特性都是全球規模的,哪怕是正在運行的事務的時候,也支持。正如Bailis解釋的一樣,Spanner是為google的重-讀(read-heavy)負載高度定制的。采用兩階段提交,讀/寫事務采用兩階段鎖。
 
  并發控制弱一致性與弱隔離級模型在分布式數據庫中已為人所知。由此產生了樂觀復制技術以及最終一致性系統在中心化的系統中,采用的其他的方法,有基于鎖的悲觀模式(),采用如多版本并發控制樂觀模式,如Hekaton,如VoltDB采用分片方法,Deuteronomy和Hyper采用時間戳排序的方法。而Aurora給數據庫系統提供了一個持久存在的抽象的本地磁盤,允許引擎自己處理隔離級與并發控制。
 
  日志結構存儲1992年LFS就引入了日志結構存儲系統。最近Deuteronomy和LLMA的相關工作,以及Bw-tree以多種方式在存儲引擎棧中采用日志結構技術,和Aurora一樣,通過寫入差量而不是寫整頁減少寫放大。Aurora與Deuteronomy都實現了純重做日志系統,并且跟蹤最高持久化的LSN,用以確認提交。
 
  崩潰恢復 傳統數據庫依賴于ARIES的恢復協議,現在有些數據庫為了性能而采用了其他途徑。例如,Hekaton與VoltDB采用某種形式的更新日志來重建崩潰后的內存狀態。像Sinfonia系統采用如進程對以及復制狀態機的技術來避免崩潰恢復。Graefe描述一種使用每頁日志記錄鏈的系統,可以按需逐頁重做??梢蕴岣弑罎⒒謴偷乃俣?。Aurora與Deuteronomy不需要重做崩潰恢復的過程。這是因為Deuteronomy會將事務延遲,以便只有提交的事務的修改才會寫入到持久存儲中。因而,與Aurora不同,Deuteronomy能處理的事務大小必然受到限制。
 
  09 結論
 
  我們設計出了高吞吐量的OLTP數據庫Aurora,在云級規模環境下,并沒有損失其可用性與持久性。主要思想是,沒有采用傳統數據庫的單核架構,而是從計算節點中把存儲解耦出來。實際上,我們只從數據庫內核中移走了低于1/4的部分到獨立的彈性伸縮的分布式服務中,用以管理日志與存儲。由于所有的IO寫都要通過網絡,現在我們的基本的約束就在于網絡。所以我們關注于能緩解網絡壓力并能提高吞吐量的技術。我們使用仲裁模型來處理大規模的云環境下的相關的復雜失效。并且避免了特殊節點帶來的性能懲罰。使用日志處理減少總的IO負擔。采用異步共識方法消除多階段提交同步協議的繁復交互與高昂的代價,以及離線的崩潰恢復,和分布式存儲的檢查點。我們的方法導致了簡化系統架構,能降低復雜性,易于伸縮能為未來的發展打下基礎。
 
  文章個人解讀
 
  圖1中所示的Data Plane中,數據庫引擎那個框包住了Caching,而存儲服務那個框,也包住了Caching。耐人尋味。可以猜測,Cache是共享內存,數據庫引擎和存儲服務都可以訪問。而且Cache不光是數據庫引擎的一部分,而且也是存儲服務的一部分。全文大部分篇幅講如何優化寫請求帶來的網絡負擔,而只字未提讀請求是否帶來網絡負擔。因此,可以大膽猜測,一次寫操作,不光是把日志應用到磁盤存儲中,同時也把已經在cache的頁也應用了,因此大部分的讀請求不需要真實的存儲IO,除非該頁在cache中沒有命中。從段6的Aurora測試可以看到,Aurora實例擁有的緩存相當大,一般的應用軟件的數據庫數據都能放在內存中。從圖3也可以看到,AZ1主實例,也會向AZ2,AZ3數據庫從實例發送日志與元數據,既然已經將日志處理從數據庫引擎解耦出來了,發送的日志由誰應用呢?個人認為,AZ2與AZ3接收到日志,仍然是有存儲服務應用的,只不過Cache是存儲服務與數據庫引擎共享的。
 
  而且有這個猜測,我們進一步解讀零停機補丁的實現方式。ZDP如何保持用戶連接實現假脫機?個人認為,應用到數據庫之間有proxy。使用proxy來保持應用程序的連接,并重新與更新后數據庫實例建立連接,而且要做到用戶會話無感覺,Cache是共享內存是必要的。因為Cache保存了大部分數據庫運行狀態,重啟后的數據庫實例仍然繼續進行用戶會話的查詢。這個和使用共享內存的postgre有點像,你隨意殺死postgre某些進程,并不影響用戶會話的查詢。
 
  此外,個人認為,Aurora的計算節點,有可能也是存儲節點。雖然邏輯上是存儲與計算分離的,但是也可以享受不分離帶來的好處,比如,存儲服務可以直接往Cache應用日志,使得數據庫引擎在大部分讀請求不需要真實的IO。
 
  Aurora有沒有checkpoint?
 
  Aurora的PGMRPL可以認為是檢查點。LSN小于這個點的數據頁已經刷盤,而大于這個點的頁可以刷盤,也可以不刷盤,LSN小于這個點的日志都可以丟棄。PGMRPL在邏輯上與存儲引擎的檢查點是等效的??梢哉J為是PG上的檢查點。
 
  Aurora與polardb
 
  Aurora與Polardb都是存儲與計算分離、一些多讀、共享分布式存儲的架構。很顯然,polardb在寫放大上面沒有做優化。從節點需要同步主庫的臟頁,共享的存儲,私有的臟頁,是個很難解決的矛盾。因此polardb的讀節點會影響寫節點。而Aurora可以認為沒有臟頁。日志即數據庫,可以把日志應用器看作更慢的存儲,存儲服務與緩存都可以認為是日志應用器的Cache。
 
  從節點與主節點之間有延遲,而aurora存儲的數據頁有多版本,文中明確指出存儲有舊頁回收處理。從節點依據讀取點LSN讀取到指定版本的頁,文中段4.2.4指出,寫節點到讀復制節點之間的延遲小于20ms,因此,不可回收的舊版本頁應該不會太多。
 
  臨時表
 
  每個讀節點雖然只有查詢操作,但是查詢操作會生成臨時表用以保存查詢的中間結果。生成臨時表數據是不會產生日志的。但是這里仍有寫IO,個人認為,Aurora有可能直接寫在本地存儲,這樣不會產生網絡上的負擔。

(編輯:武林網)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品三级网站| 欧美黑人巨大精品一区二区| 欧美性高跟鞋xxxxhd| 91精品国产综合久久男男| 日韩欧美a级成人黄色| 国内精品国产三级国产在线专| 国产色视频一区| 久久伊人色综合| 69精品小视频| 久久人人爽人人爽人人片av高请| 国产一区二区三区中文| 日韩最新av在线| 中文字幕在线精品| 欧美精品aaa| 欧美在线观看日本一区| 国产精品免费在线免费| 国产精品一区二区三区久久久| 成人免费网站在线观看| 日韩精品视频观看| 国产乱肥老妇国产一区二| 国产这里只有精品| 久久人人爽人人| 国产日韩欧美日韩| 国产精品久久久久aaaa九色| 亚洲第一av网| 欧美精品videossex性护士| 欧美亚洲国产视频小说| 57pao成人国产永久免费| 国产精品wwwwww| 欧美天天综合色影久久精品| 精品久久久久久久久久久久| 精品国产91乱高清在线观看| 久久久久国色av免费观看性色| 久久久久久久999精品视频| 亚洲精品理论电影| 亚洲电影免费在线观看| 国产精品久久久久久婷婷天堂| 亚洲人成啪啪网站| 91精品久久久久久久久久入口| 欧美亚洲另类视频| 国产精品入口夜色视频大尺度| 久久亚洲精品一区| 国产精品天天狠天天看| 色偷偷av一区二区三区| 国产91av在线| 国产精品高清免费在线观看| 日韩av有码在线| 久久成人这里只有精品| 国产精品久久久久久久午夜| 丝袜情趣国产精品| 2018中文字幕一区二区三区| 久久婷婷国产麻豆91天堂| 久久久久久久久久久网站| 91国产一区在线| 国产美女精彩久久| 亚洲3p在线观看| 亚洲自拍高清视频网站| 午夜精品久久久久久99热软件| 中文字幕日韩免费视频| 亚洲欧美一区二区精品久久久| 欧美激情奇米色| 国产精品福利在线观看网址| 狠狠久久五月精品中文字幕| 欧美日韩免费一区| 欧美乱人伦中文字幕在线| 日韩成人中文电影| 国产小视频国产精品| 成人福利免费观看| 亚洲国产精品久久久久| 中文字幕精品www乱入免费视频| 成人美女av在线直播| 欧美自拍大量在线观看| 欧美成人免费在线视频| 亚洲福利视频网站| 91精品国产高清久久久久久久久| 亚洲人成绝费网站色www| 欧美黄色三级网站| 国产精品成人免费视频| 精品毛片三在线观看| 91在线视频导航| 国产一区二区三区丝袜| 538国产精品一区二区在线| 日韩在线视频网站| 久久69精品久久久久久国产越南| 国产精品精品一区二区三区午夜版| 日本sm极度另类视频| 欧美在线一区二区三区四| 中文字幕欧美国内| 亚洲一区二区三区视频播放| 欧美日韩亚洲精品内裤| 国产啪精品视频| 久久久久久久999| 深夜福利亚洲导航| 中国人与牲禽动交精品| 91在线视频九色| 成人午夜激情免费视频| 欧美日韩另类在线| 久久久精品999| 亚洲va欧美va国产综合剧情| 欧美性极品xxxx做受| 欧美风情在线观看| 国产91在线播放九色快色| 久久99青青精品免费观看| 欧美黑人极品猛少妇色xxxxx| 91超碰中文字幕久久精品| 亚洲欧美日韩第一区| 日韩专区在线播放| 日韩中文字幕在线视频播放| 伊人久久久久久久久久久| 日本三级久久久| 1769国内精品视频在线播放| 狠狠躁夜夜躁久久躁别揉| 亚洲精品视频免费在线观看| 国产精品中文在线| 国产视频精品在线| 国产精品久久久av| 欧美极品在线视频| 国产精品亚洲美女av网站| 欧美大片va欧美在线播放| 色偷偷综合社区| 欧美一区二区三区免费观看| 欧美国产亚洲精品久久久8v| 亚洲精品一区久久久久久| 国产精品天天狠天天看| 成人精品久久av网站| 亚洲丝袜一区在线| 国产精品福利在线观看网址| 国产成人精品一区| 91精品久久久久久久久中文字幕| 国产精品入口夜色视频大尺度| 亚洲精品一区二区在线| 欧美夫妻性生活xx| 中文字幕亚洲欧美一区二区三区| 在线观看国产精品日韩av| 久久久久久尹人网香蕉| 欧美电影免费观看大全| 日韩国产中文字幕| 26uuu久久噜噜噜噜| 欧美日韩中文字幕在线视频| 在线观看免费高清视频97| 97人洗澡人人免费公开视频碰碰碰| 国产精品99一区| 精品国产电影一区| 亚洲天堂av高清| 九色精品美女在线| 91社影院在线观看| 97国产真实伦对白精彩视频8| 91久久国产精品91久久性色| 成人av.网址在线网站| 欧美激情亚洲激情| 欧美激情第6页| 最新中文字幕亚洲| 95av在线视频| 91精品国产高清| 久久久久女教师免费一区| 久久婷婷国产麻豆91天堂| 欧美成人精品h版在线观看| 日韩国产一区三区| 亚洲aa中文字幕| 精品美女久久久久久免费| 欧美一级大片视频| 日韩欧美亚洲范冰冰与中字| www.久久久久久.com| 日韩免费观看高清|