精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Web應用的緩存設計模式

開發 前端
我們去年有一個老產品重寫的項目,這個產品有超過10年歷史了,數據庫的數據量很大,多個表都是上千萬條記錄,最大的表記錄達到了9000萬條,Web訪問的請求數每天有300萬左右。

ORM緩存引言

從10年前的2003年開始,在Web應用領域,ORM(對象-關系映射)框架就開始逐漸普及,并且流行開來,其中最廣為人知的就是Java的開源ORM框架Hibernate,后來Hibernate也成為了EJB3的實現框架;2005年以后,ORM開始普及到其他編程語言領域,其中最有名氣的是Ruby on rails框架的ORM - ActiveRecord。如今各種開源框架的ORM,乃至ODM(對象-文檔關系映射,用在訪問NoSQLDB)層出不窮,功能都十分強大,也很普及。

然而圍繞ORM的性能問題,也一直有很多批評的聲音。其實ORM的架構對插入緩存技術是非常容易的,我做的很多項目和產品,但凡使用ORM,緩存都是標配,性能都非常好。而且我發現業界使用ORM的案例都忽視了緩存的運用,或者說沒有意識到ORM緩存可以帶來巨大的性能提升。

ORM緩存應用案例

我們去年有一個老產品重寫的項目,這個產品有超過10年歷史了,數據庫的數據量很大,多個表都是上千萬條記錄,最大的表記錄達到了9000萬條,Web訪問的請求數每天有300萬左右。

老產品采用了傳統的解決性能問題的方案:Web層采用了動態頁面靜態化技術,超過一定時間的文章生成靜態HTML文件;對數據庫進行分庫分表,按年拆表。動態頁面靜態化和分庫分表是應對大訪問量和大數據量的常規手段,本身也有效。但它的缺點也很多,比方說增加了代碼復雜度和維護難度,跨庫運算的困難等等,這個產品的代碼維護歷來非常困難,導致bug很多。

進行產品重寫的時候,我們放棄了動態頁面靜態化,采用了純動態網頁;放棄了分庫分表,直接操作千萬級,乃至近億條記錄的大表進行SQL查詢;也沒有采取讀寫分離技術,全部查詢都是在單臺主數據庫上進行;數據庫訪問全部使用ActiveRecord,進行了大量的ORM緩存。上線以后的效果非常好:單臺MySQL數據庫服務器CPU的IO Wait低于5%;用單臺1U服務器2顆4核至強CPU已經可以輕松支持每天350萬動態請求量;最重要的是,插入緩存并不需要代碼增加多少復雜度,可維護性非常好。

總之,采用ORM緩存是Web應用提升性能一種有效的思路,這種思路和傳統的提升性能的解決方案有很大的不同,但它在很多應用場景(包括高度動態化的SNS類型應用)非常有效,而且不會顯著增加代碼復雜度,所以這也是我自己一直偏愛的方式。因此我一直很想寫篇文章,結合示例代碼介紹ORM緩存的編程技巧。

今年春節前后,我開發自己的個人網站項目,有意識的大量使用了ORM緩存技巧。對一個沒多少訪問量的個人站點來說,有些過度設計了,但我也想借這個機會把常用的ORM緩存設計模式寫成示例代碼,提供給大家參考。我的個人網站源代碼是開源的,托管在github上:robbin_site

ORM緩存的基本理念

·我在2007年的時候寫過一篇文章,分析ORM緩存的理念:ORM對象緩存探討 ,所以這篇文章不展開詳談了,總結來說,ORM緩存的基本理念是:

·以減少數據庫服務器磁盤IO為最終目的,而不是減少發送到數據庫的SQL條數。實際上使用ORM,會顯著增加SQL條數,有時候會成倍增加SQL。

·數據庫schema設計的取向是盡量設計 細顆粒度 的表,表和表之間用外鍵關聯,顆粒度越細,緩存對象的單位越小,緩存的應用場景越廣泛

盡量避免多表關聯查詢,盡量拆成多個表單獨的主鍵查詢,盡量多制造 n + 1 條查詢,不要害怕“臭名昭著”的 n + 1 問題,實際上 n + 1 才能有效利用ORM緩存

利用表關聯實現透明的對象緩存

在設計數據庫的schema的時候,設計多個細顆粒度的表,用外鍵關聯起來。當通過ORM訪問關聯對象的時候,ORM框架會將關聯對象的訪問轉化成用主鍵查詢關聯表,發送 n + 1條SQL。而基于主鍵的查詢可以直接利用對象緩存。

我們自己開發了一個基于ActiveRecord封裝的對象緩存框架:second_level_cache ,從這個ruby插件的名稱就可以看出,實現借鑒了Hibernate的二級緩存實現。這個對象緩存的配置和使用,可以看我寫的ActiveRecord對象緩存配置

下面用一個實際例子來演示一下對象緩存起到的作用:訪問我個人站點的首頁。 這個頁面的數據需要讀取三張表:blogs表獲取文章信息,blog_contents表獲取文章內容,accounts表獲取作者信息。三張表的model定義片段如下,完整代碼請看models

  1. class Account < ActiveRecord::Base  
  2.   acts_as_cached  
  3.   has_many :blogs  
  4. end 
  5.  
  6. class Blog < ActiveRecord::Base  
  7.   acts_as_cached  
  8.   belongs_to :blog_content, :dependent => :destroy   
  9.   belongs_to :account, :counter_cache => true 
  10. end 
  11.  
  12. class BlogContent < ActiveRecord::Base  
  13.   acts_as_cached  
  14. end 

傳統的做法是發送一條三表關聯的查詢語句,類似這樣的:

  1. SELECT blogs.*, blog_contents.content, account.name   
  2.     FROM blogs   
  3.     LEFT JOIN blog_contents ON blogs.blog_content_id = blog_contents.id   
  4.     LEFT JOIN accounts ON blogs.account_id = account.id  

往往單條SQL語句就搞定了,但是復雜SQL的帶來的表掃描范圍可能比較大,造成的數據庫服務器磁盤IO會高很多,數據庫實際IO負載往往無法得到有效緩解。

我的做法如下,完整代碼請看home.rb

  1. @blogs = Blog.order('id DESC').page(params[:page]) 

這是一條分頁查詢,實際發送的SQL如下:

  1. SELECT * FROM blogs ORDER BY id DESC LIMIT 20 

轉成了單表查詢,磁盤IO會小很多。至于文章內容,則是通過blog.content的對象訪問獲得的,由于首頁抓取20篇文章,所以實際上會多出來20條主鍵查詢SQL訪問blog_contents表。就像下面這樣:

  1. DEBUG -  BlogContent Load (0.3ms)  SELECT `blog_contents`.* FROM `blog_contents` WHERE `blog_contents`.`id` = 29 LIMIT 1  
  2. DEBUG -  BlogContent Load (0.2ms)  SELECT `blog_contents`.* FROM `blog_contents` WHERE `blog_contents`.`id` = 28 LIMIT 1  
  3. DEBUG -  BlogContent Load (1.3ms)  SELECT `blog_contents`.* FROM `blog_contents` WHERE `blog_contents`.`id` = 27 LIMIT 1  
  4. ......  
  5. DEBUG -  BlogContent Load (0.9ms)  SELECT `blog_contents`.* FROM `blog_contents` WHERE `blog_contents`.`id` = 10 LIMIT 1 

但是主鍵查詢SQL不會造成表的掃描,而且往往已經被數據庫buffer緩存,所以基本不會發生數據庫服務器的磁盤IO,因而總體的數據庫IO負載會遠遠小于前者的多表聯合查詢。特別是當使用對象緩存之后,會緩存所有主鍵查詢語句,這20條SQL語句往往并不會全部發生,特別是熱點數據,緩存命中率很高:

  1. DEBUG -  Cache read: robbin/blog/29/1  
  2. DEBUG -  Cache read: robbin/account/1/0  
  3. DEBUG -  Cache read: robbin/blogcontent/29/0  
  4. DEBUG -  Cache read: robbin/account/1/0  
  5. DEBUG -  Cache read: robbin/blog/28/1  
  6. ......  
  7. DEBUG -  Cache read: robbin/blogcontent/11/0  
  8. DEBUG -  Cache read: robbin/account/1/0  
  9. DEBUG -  Cache read: robbin/blog/10/1  
  10. DEBUG -  Cache read: robbin/blogcontent/10/0  
  11. DEBUG -  Cache read: robbin/account/1/0  

拆分n+1條查詢的方式,看起來似乎非常違反大家的直覺,但實際上這是真理,我實踐經驗證明:數據庫服務器的瓶頸往往是磁盤IO,而不是SQL并發數量。因此 拆分n+1條查詢本質上是以增加n條SQL語句為代價,簡化復雜SQL,換取數據庫服務器磁盤IO的降低 當然這樣做以后,對于ORM來說,有額外的好處,就是可以高效的使用緩存了。

#p#

按照column拆表實現細粒度對象緩存

數據庫的瓶頸往往在磁盤IO上,所以應該盡量避免對大表的掃描。傳統的拆表是按照row去拆分,保持表的體積不會過大,但是缺點是造成應用代碼復雜度很高;使用ORM緩存的辦法,則是按照column進行拆表,原則一般是:

·將大字段拆分出來,放在一個單獨的表里面,表只有主鍵和大字段,外鍵放在主表當中

·將不參與where條件和統計查詢的字段拆分出來,放在獨立的表中,外鍵放在主表當中

按照column拆表本質上是一個去關系化的過程。主表只保留參與關系運算的字段,將非關系型的字段剝離到關聯表當中,關聯表僅允許主鍵查詢,以Key-Value DB的方式來訪問。因此這種緩存設計模式本質上是一種SQLDB和NoSQLDB的混合架構設計

下面看一個實際的例子:文章的內容content字段是一個大字段,該字段不能放在blogs表中,否則會造成blogs表過大,表掃描造成較多的磁盤IO。我實際做法是創建blog_contents表,保存content字段,schema簡化定義如下:

  1. CREATE TABLE `blogs` (  
  2.   `id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `title` varchar(255) NOT NULL,  
  4.   `blog_content_id` int(11) NOT NULL,  
  5.   `content_updated_at` datetime DEFAULT NULL,  
  6.   PRIMARY KEY (`id`),  
  7. );  
  8.  
  9. CREATE TABLE `blog_contents` (  
  10.   `id` int(11) NOT NULL AUTO_INCREMENT,  
  11.   `content` mediumtext NOT NULL,  
  12.   PRIMARY KEY (`id`)  
  13. ); 

blog_contents表只有content大字段,其外鍵保存到主表blogs的blog_content_id字段里面。

model定義和相關的封裝如下:

  1. class Blog < ActiveRecord::Base  
  2.   acts_as_cached  
  3.   delegate :content, :to => :blog_content, :allow_nil => true 
  4.  
  5.   def content=(value)  
  6.     self.blog_content ||= BlogContent.new  
  7.     self.blog_content.content = value  
  8.     self.content_updated_at = Time.now  
  9.   end 
  10. end 
  11.  
  12. class BlogContent < ActiveRecord::Base  
  13.   acts_as_cached  
  14.   validates :content, :presence => true 
  15. end      

在Blog類上定義了虛擬屬性content,當訪問blog.content的時候,實際上會發生一條主鍵查詢的SQL語句,獲取blog_content.content內容。由于BlogContent上面定義了對象緩存acts_as_cached,只要被訪問過一次,content內容就會被緩存到memcached里面。

這種緩存技術實際會非常有效,因為: 只要緩存足夠大,所有文章內容可以全部被加載到緩存當中,無論文章內容表有多么大,你都不需要再訪問數據庫了 更進一步的是: 這張大表你永遠都只需要通過主鍵進行訪問,絕無可能出現表掃描的狀況 為何當數據量大到9000萬條記錄以后,我們的系統仍然能夠保持良好的性能,秘密就在于此。

還有一點非常重要: 使用以上兩種對象緩存的設計模式,你除了需要添加一條緩存聲明語句acts_as_cached以外,不需要顯式編寫一行代碼 有效利用緩存的代價如此之低,何樂而不為呢?

以上兩種緩存設計模式都不需要顯式編寫緩存代碼,以下的緩存設計模式則需要編寫少量的緩存代碼,不過代碼的增加量非常少。

寫一致性緩存

寫一致性緩存,叫做write-through cache,是一個CPU Cache借鑒過來的概念,意思是說,當數據庫記錄被修改以后,同時更新緩存,不必進行額外的緩存過期處理操作。但在應用系統中,我們需要一點技巧來實現寫一致性緩存。來看一個例子:

我的網站文章原文是markdown格式的,當頁面顯示的時候,需要轉換成html的頁面,這個轉換過程本身是非常消耗CPU的,我使用的是Github的markdown的庫。Github為了提高性能,用C寫了轉換庫,但如果是非常大的文章,仍然是一個耗時的過程,Ruby應用服務器的負載就會比較高。

我的解決辦法是緩存markdown原文轉換好的html頁面的內容,這樣當再次訪問該頁面的時候,就不必再次轉換了,直接從緩存當中取出已經緩存好的頁面內容即可,極大提升了系統性能。我的網站文章最終頁的代碼執行時間開銷往往小于10ms,就是這個原因。代碼如下:

  1. def md_content  # cached markdown format blog content  
  2.   APP_CACHE.fetch(content_cache_key) { GitHub::Markdown.to_html(content, :gfm) }  
  3. end 

這里存在一個如何進行緩存過期的問題,當文章內容被修改以后,應該更新緩存內容,讓老的緩存過期,否則就會出現數據不一致的現象。進行緩存過期處理是比較麻煩的,我們可以利用一個技巧來實現自動緩存過期:

  1. def content_cache_key  
  2.   "#{CACHE_PREFIX}/blog_content/#{self.id}/#{content_updated_at.to_i}" 
  3. end 

當構造緩存對象的key的時候,我用文章內容被更新的時間來構造key值,這個文章內容更新時間用的是blogs表的content_updated_at字段,當文章被更新的時候,blogs表會進行update,更新該字段。因此每當文章內容被更新,緩存的頁面內容的key就會改變,應用程序下次訪問文章頁面的時候,緩存就會失效,于是重新調用GitHub::Markdown.to_html(content, :gfm)生成新的頁面內容。 而老的頁面緩存內容再也不會被應用程序存取,根據memcached的LRU算法,當緩存填滿之后,將被優先剔除。

除了文章內容緩存之外,文章的評論內容轉換成html以后也使用了這種緩存設計模式。具體可以看相應的源代碼:blog_comment.rb

#p#

片段緩存和過期處理

Web應用當中有大量的并非實時更新的數據,這些數據都可以使用緩存,避免每次存取的時候都進行數據庫查詢和運算。這種片段緩存的應用場景很多,例如:

·展示網站的Tag分類統計(只要沒有更新文章分類,或者發布新文章,緩存一直有效)

·輸出網站RSS(只要沒有發新文章,緩存一直有效)

·網站右側欄(如果沒有新的評論或者發布新文章,則在一段時間例如一天內基本不需要更新)

以上應用場景都可以使用緩存,代碼示例:

  1. def self.cached_tag_cloud  
  2.   APP_CACHE.fetch("#{CACHE_PREFIX}/blog_tags/tag_cloud") do  
  3.     self.tag_counts.sort_by(&:count).reverse  
  4.   end 
  5. end 

對全站文章的Tag云進行查詢,對查詢結果進行緩存

  1. <% cache("#{CACHE_PREFIX}/layout/right", :expires_in => 1.day) do %> 
  2.  
  3. <div class="tag"> 
  4.   <% Blog.cached_tag_cloud.select {|t| t.count > 2}.each do |tag| %> 
  5.   <%= link_to "#{tag.name}<span>#{tag.count}</span>".html_safe, url(:blog, :tag, :name => tag.name) %> 
  6.   <% end %> 
  7. </div> 
  8. ......  
  9. <% end %> 

對全站右側欄頁面進行緩存,過期時間是1天。

緩存的過期處理往往是比較麻煩的事情,但在ORM框架當中,我們可以利用model對象的回調,很容易實現緩存過期處理。我們的緩存都是和文章,以及評論相關的,所以可以直接注冊Blog類和BlogComment類的回調接口,聲明當對象被保存或者刪除的時候調用刪除方法:

  1. class Blog < ActiveRecord::Base 
  2.   acts_as_cached  
  3.   after_save :clean_cache  
  4.   before_destroy :clean_cache  
  5.   def clean_cache  
  6.     APP_CACHE.delete("#{CACHE_PREFIX}/blog_tags/tag_cloud")   # clean tag_cloud  
  7.     APP_CACHE.delete("#{CACHE_PREFIX}/rss/all")               # clean rss cache  
  8.     APP_CACHE.delete("#{CACHE_PREFIX}/layout/right")          # clean layout right column cache in _right.erb  
  9.   end  
  10. end  
  11.  
  12. class BlogComment < ActiveRecord::Base 
  13.   acts_as_cached  
  14.   after_save :clean_cache  
  15.   before_destroy :clean_cache  
  16.   def clean_cache  
  17.     APP_CACHE.delete("#{CACHE_PREFIX}/layout/right")     # clean layout right column cache in _right.erb  
  18.   end  
  19. end    

在Blog對象的after_save和before_destroy上注冊clean_cache方法,當文章被修改或者刪除的時候,刪除以上緩存內容。總之,可以利用ORM對象的回調接口進行緩存過期處理,而不需要到處寫緩存清理代碼。

對象寫入緩存

我們通常說到緩存,總是認為緩存是提升應用讀取性能的,其實緩存也可以有效的提升應用的寫入性能。我們看一個常見的應用場景:記錄文章點擊次數這個功能。

文章點擊次數需要每次訪問文章頁面的時候,都要更新文章的點擊次數字段view_count,然后文章必須實時顯示文章的點擊次數,因此常見的讀緩存模式完全無效了。每次訪問都必須更新數據庫,當訪問量很大以后數據庫是吃不消的,因此我們必須同時做到兩點:

·每次文章頁面被訪問,都要實時更新文章的點擊次數,并且顯示出來

·不能每次文章頁面被訪問,都更新數據庫,否則數據庫吃不消

對付這種應用場景,我們可以利用對象緩存的不一致,來實現對象寫入緩存。原理就是每次頁面展示的時候,只更新緩存中的對象,頁面顯示的時候優先讀取緩存,但是不更新數據庫,讓緩存保持不一致,積累到n次,直接更新一次數據庫,但繞過緩存過期操作。具體的做法可以參考blog.rb

  1. # blog viewer hit counter  
  2. def increment_view_count  
  3.   increment(:view_count)        # add view_count += 1  
  4.   write_second_level_cache      # update cache per hit, but do not touch db  
  5.                                 # update db per 10 hits  
  6.   self.class.update_all({:view_count => view_count}, :id => id) if view_count % 10 == 0  
  7. end 

increment(:view_count)增加view_count計數,關鍵代碼是第2行write_second_level_cache,更新view_count之后直接寫入緩存,但不更新數據庫。累計10次點擊,再更新一次數據庫相應的字段。另外還要注意,如果blog對象不是通過主鍵查詢,而是通過查詢語句構造的,要優先讀取一次緩存,保證頁面點擊次數的顯示一致性,因此 _blog.erb 這個頁面模版文件開頭有這樣一段代碼:

  1. <%   
  2.   # read view_count from model cache if model has been cached.  
  3.   view_count = blog.view_count  
  4.   if b = Blog.read_second_level_cache(blog.id)  
  5.     view_count = b.view_count  
  6.   end 
  7. %>  

采用對象寫入緩存的設計模式,就可以非常容易的實現寫入操作的緩存,在這個例子當中,我們僅僅增加了一行緩存寫入代碼,而這個時間開銷大約是1ms,就可以實現文章實時點擊計數功能,是不是非常簡單和巧妙?實際上我們也可以使用這種設計模式實現很多數據庫寫入的緩存功能。

常用的ORM緩存設計模式就是以上的幾種,本質上都是非常簡單的編程技巧,代碼的增加量和復雜度也非常低,只需要很少的代碼就可以實現,但是在實際應用當中,特別是當數據量很龐大,訪問量很高的時候,可以發揮驚人的效果。我們實際的系統當中,緩存命中次數:SQL查詢語句,一般都是5:1左右,即每次向數據庫查詢一條SQL,都會在緩存當中命中5次,數據主要都是從緩存當中得到,而非來自于數據庫了。

其他緩存的使用技巧

還有一些并非ORM特有的緩存設計模式,但是在Web應用當中也比較常見,簡單提及一下:

用數據庫來實現的緩存

在我這個網站當中,每篇文章都標記了若干tag,而tag關聯關系都是保存到數據庫里面的,如果每次顯示文章,都需要額外查詢關聯表獲取tag,顯然會非常消耗數據庫。在我使用的acts-as-taggable-on插件中,它在blogs表當中添加了一個cached_tag_list字段,保存了該文章標記的tag。當文章被修改的時候,會自動相應更新該字段,避免了每次顯示文章的時候都需要去查詢關聯表的開銷。

HTTP客戶端緩存

基于資源協議實現的HTTP客戶端緩存也是一種非常有效的緩存設計模式,我在2009年寫過一篇文章詳細的講解了:基于資源的HTTP Cache的實現介紹 ,所以這里就不再復述了。

用緩存實現計數器功能

這種設計模式有點類似于對象寫入緩存,利用緩存寫入的低開銷來實現高性能計數器。舉一個例子:用戶登錄為了避免遭遇密碼暴力破解,我限定了每小時每IP只能嘗試登錄5次,如果超過5次,拒絕該IP再次嘗試登錄。代碼實現很簡單,如下:

  1. post :login, :map => '/login' do  
  2.   login_tries = APP_CACHE.read("#{CACHE_PREFIX}/login_counter/#{request.ip}")  
  3.   halt 403 if login_tries && login_tries.to_i > 5  # reject ip if login tries is over 5 times  
  4.   @account = Account.new(params[:account])  
  5.   if login_account = Account.authenticate(@account.email, @account.password)  
  6.     session[:account_id] = login_account.id  
  7.     redirect url(:index)  
  8.   else 
  9.     # retry 5 times per one hour 
  10.     APP_CACHE.increment("#{CACHE_PREFIX}/login_counter/#{request.ip}", 1, :expires_in => 1.hour)  
  11.     render 'home/login' 
  12.   end 
  13. end 

等用戶POST提交登錄信息之后,先從緩存當中取該IP嘗試登錄次數,如果大于5次,直接拒絕掉;如果不足5次,而且登錄失敗,計數加1,顯示再次嘗試登錄頁面。

以上相關代碼可以從這里獲取:robbin_site

原文鏈接:http://robbinfan.com/blog/38/orm-cache-sumup

責任編輯:張偉 來源: robbinfan
相關推薦

2009-07-06 14:03:01

高性能Web應用緩存

2009-01-03 14:25:10

ibmdwWeb

2009-07-19 10:32:44

2011-03-11 17:07:16

2017-05-05 10:13:03

應用級緩存緩存代碼

2009-06-25 15:54:18

設計模式EJB

2023-03-30 08:29:14

HTTP緩存Web應用

2023-11-29 13:55:00

系統設計Web

2021-03-03 16:01:48

Web設計模式

2014-10-27 09:51:19

Web設計HTML

2011-03-11 17:10:11

2022-02-13 22:42:52

設計模式策略

2021-07-28 08:31:25

設計系統應用

2011-04-21 15:33:23

2012-04-02 16:35:49

網絡緩存

2009-07-08 09:32:25

Java設計模式

2009-06-12 09:11:56

Web2.0應用商業模式

2012-02-01 14:12:55

iOS本地緩存機制

2012-03-01 15:06:58

2024-08-12 10:53:00

點贊
收藏

51CTO技術棧公眾號

精品无码国产一区二区三区51安| 久草免费福利在线| 91国在线视频| 国产精品v一区二区三区| 精品国产乱子伦一区| 日韩av片在线看| 日本亚洲精品| 大胆亚洲人体视频| 国产大片精品免费永久看nba| 一级免费黄色录像| 国产图片一区| 欧美日韩亚洲国产综合| 日韩成人三级视频| 成人在线免费观看| 国产91精品一区二区麻豆网站| 日本91av在线播放| 欧美成人精品欧美一级| 少妇精品久久久| 日韩一区二区在线看| 国产一区亚洲二区三区| 手机在线免费观看av| 久久亚洲精品小早川怜子| 91视频88av| 欧美国产成人精品一区二区三区| 欧美黄色大片网站| 中文字幕日韩欧美| 中文字幕在线观看的网站| 蜜桃精品视频| 欧美日韩国产在线观看| 日本在线观看a| 女人黄色免费在线观看| 亚洲欧洲av另类| 日本在线成人一区二区| 少妇av在线播放| 国产一区二区三区精品欧美日韩一区二区三区| 欧美一区二粉嫩精品国产一线天| 久久久久久久9999| 91成人精品| 中文字幕日韩视频| 久久丫精品忘忧草西安产品| 久久久久观看| 精品久久国产字幕高潮| 人人爽人人爽av| 巨胸喷奶水www久久久免费动漫| 欧美日韩中文字幕在线视频| 99在线观看视频免费| 超碰免费在线播放| 国产精品久久综合| 日韩精品极品视频在线观看免费| 深夜影院在线观看| 成人黄页毛片网站| 99九九视频| 国产国语亲子伦亲子| 国产一区二区三区不卡在线观看| 国产精品一区二区三区在线播放| 中文字幕在线天堂| 视频一区中文字幕| 国产精品精品视频一区二区三区| 无码视频在线观看| 日韩精品成人一区二区三区| 国产成人在线一区| 中文av免费观看| 久久精品久久综合| 91啪国产在线| 国内精品国产成人国产三级| 风流少妇一区二区| 国产麻豆日韩| 无码国产精品一区二区免费16| caoporn国产一区二区| 精品一区国产| 精华区一区二区三区| 国产欧美一区二区三区网站 | 久久五月婷婷丁香社区| 乱一区二区三区在线播放| 欧美在线观看在线观看| 国产亚洲综合av| 亚洲精品视频一二三| 久久bbxx| 亚洲成人在线网站| 99热成人精品热久久66| 成人在线中文| 日韩一区二区三区四区| 少妇一级淫片免费放播放| 自拍偷拍欧美一区| www国产精品视频| 麻豆视频在线观看| 亚洲欧美网站| 国产欧美精品日韩精品| 黄频在线免费观看| 久久精品视频一区二区| 在线看成人av电影| 日本在线视频www鲁啊鲁| 精品福利在线看| 五月激情婷婷在线| 久久a爱视频| 中文字幕久精品免费视频| 青娱乐国产在线| 久久久久国产精品一区三寸| 国产在线视频不卡| 搡老岳熟女国产熟妇| 国产精品污污网站在线观看| 久艹在线免费观看| 国产在线|日韩| 精品日韩一区二区三区| 亚洲一二三精品| 1024成人| 亚洲永久免费观看| 国产二区在线播放| 亚洲香肠在线观看| 欧美伦理片在线观看| 国产精品对白久久久久粗| 中文字幕精品网| 国产精品xxxx喷水欧美| 国产精品一区免费在线观看| 欧美一区二区三区在线播放| 先锋成人av| 欧美日韩亚洲另类| 四虎国产精品成人免费入口| 精品91视频| 91免费看片在线| 国产福利在线观看| 欧美性xxxxxxx| 韩国av中国字幕| 99国产精品一区二区| 欧美综合在线第二页| 亚洲AV无码精品国产| 国产精品美女久久久久av爽李琼| 国产69精品久久久久久久| 精品中文在线| 日韩在线www| 免费一级a毛片| 91麻豆精东视频| 婷婷五月综合缴情在线视频| 日韩视频在线直播| 色噜噜国产精品视频一区二区 | 欧美日韩综合色| 免费黄色在线视频| 国产欧美二区| 国产一区二区三区免费不卡| 免费电影网站在线视频观看福利| 91精品免费在线| 99久久婷婷国产综合| 精品一区免费av| 中文字幕欧美日韩一区二区三区 | 免费黄网站在线| 日本精品一区二区三区四区的功能| 中文字幕乱码一区| 亚洲看片免费| 激情视频一区二区| 黄色漫画在线免费看| 日韩av在线播放资源| 国产精品7777777| av午夜一区麻豆| 日韩欧美一区三区| 欧美精品第一区| 国产91免费看片| 成年人在线观看网站| 欧美性色aⅴ视频一区日韩精品| 性猛交娇小69hd| 日本在线观看不卡视频| 视频一区二区综合| 青青久久精品| 九九精品视频在线观看| 性一交一乱一精一晶| 亚洲一级二级三级| 黄色在线观看av| 三级亚洲高清视频| 亚洲高清123| 国产精品va视频| 欧美大荫蒂xxx| 香蕉视频免费在线看| 色综合天天综合给合国产| 永久免费毛片在线观看| 精久久久久久久久久久| 日本a在线天堂| 小说区图片区色综合区| 国产精品爽黄69| 亚洲资源一区| 精品视频一区在线视频| 自拍偷拍福利视频| 一区二区三区四区在线免费观看| 少妇被狂c下部羞羞漫画| 日韩中文字幕不卡| 黄瓜视频免费观看在线观看www| 亚洲国产高清在线观看| 欧美在线视频观看免费网站| 成年网站在线| 欧美成人国产一区二区| 天干夜夜爽爽日日日日| 亚洲欧美一区二区三区久本道91| 无码人妻一区二区三区在线| 视频一区二区不卡| www.好吊操| 极品美女一区二区三区| 亚洲aaa激情| 国产精品av一区二区三区| 久久艳片www.17c.com| 无码精品人妻一区二区三区影院| 欧美在线播放高清精品| 精品亚洲永久免费| 欧美国产欧美综合| 9.1在线观看免费| 麻豆精品久久久| 国产精品裸体瑜伽视频| 国产精品久久久久久麻豆一区软件 | 熟妇熟女乱妇乱女网站| 欧美电影完整版在线观看| 国产有码在线一区二区视频| 在线成人av观看| 欧美大片第1页| 日本美女在线中文版| 亚洲国产精品va在线看黑人| 91国产免费视频| 在线视频综合导航| 国产成人精品a视频一区| 1000部国产精品成人观看| 日本japanese极品少妇| 国产激情视频一区二区三区欧美| 亚洲黄色a v| 国产偷自视频区视频一区二区| 无码人妻精品一区二区三区99v| 精品freesex老太交| 国产在线精品一区| 国产日韩欧美中文在线| 国产精品免费久久久久久| 成人免费图片免费观看| 欧美成在线观看| 国产写真视频在线观看| 视频一区视频二区国产精品| 欧美精品少妇| 亚洲精品动漫100p| 国内爆初菊对白视频| 欧美一区二区成人| 国产精品人人爽| 欧洲一区二区av| 日本a级c片免费看三区| 欧美日韩国产精品一区| 五月天婷婷综合网| 亚洲超碰精品一区二区| 免费视频一二三区| 一个色在线综合| 免费网站看av| 亚洲国产精品综合小说图片区| 精品国产乱码久久久久久鸭王1| 国产精品久久久久久久岛一牛影视| 手机免费看av| 国产亚洲午夜高清国产拍精品| 国产三级av在线播放| 国产亚洲欧洲997久久综合| 三级网站在线免费观看| 国产欧美久久久精品影院| 人妻少妇无码精品视频区| 国产亚洲综合性久久久影院| 亚洲综合欧美综合| 国产精品三级视频| 欧美风情第一页| 亚洲欧美日本韩国| 久久久久亚洲AV成人| 亚洲黄色片在线观看| 少妇影院在线观看| 亚洲国产成人va在线观看天堂| 久草视频精品在线| 精品欧美aⅴ在线网站 | 欧美日韩aaa| 国产精品久久久久久69| 91精品国产综合久久精品麻豆 | 亚洲国产成人精品久久| 神马午夜电影一区二区三区在线观看 | 国内自拍视频一区| 老司机一区二区| 中文字幕一区二区三区四| 国产成人a级片| 大地资源二中文在线影视观看 | 小h片在线观看| 国产精品久久久久久久久久ktv| 日韩五码电影| 国产欧美韩日| 国产videos久久| 黄色a级在线观看| 亚洲精品黄色| 一道本视频在线观看| 91高清在线观看视频| 欧美精美视频| 亚洲二区三区四区| 女生裸体视频一区二区三区| 亚洲理论电影在线观看| 久久久久久一区二区| 亚洲免费av一区| 粉嫩高潮美女一区二区三区| 麻豆国产精品一区| 国产精品色在线观看| 欧美日韩中文视频| 精品视频在线免费| 好吊色在线观看| 尤物yw午夜国产精品视频明星| av在线免费网址| 日本精品一区二区三区在线播放视频 | 每日在线更新av| 久久99久久99| 变态另类丨国产精品| 亚洲欧洲精品一区二区三区| 国产美女激情视频| 欧美一级淫片007| 国产精品久久久久久久龚玥菲 | 欧美日韩123区| 91精品综合久久| 国内精品久久久久久久久电影网| 白白操在线视频| 奇米四色…亚洲| 免费成人蒂法网站| 亚洲美女视频一区| 五月激情丁香网| 亚洲精品国精品久久99热| 成视频免费观看在线看| 国产精品成人一区二区| 欧美成人基地| 免费cad大片在线观看| 美女任你摸久久| 熟女俱乐部一区二区| 舔着乳尖日韩一区| 性生交大片免费看女人按摩| 精品国产美女在线| 日韩另类视频| 欧美乱偷一区二区三区在线| 伊人精品成人久久综合软件| 日韩成人精品视频在线观看| 国产欧美日韩在线| 免费av网站在线| 亚洲精品wwww| 岛国在线视频网站| 豆国产97在线| 欧美精品一卡| 五月天六月丁香| 综合自拍亚洲综合图不卡区| 最近日韩免费视频| 亚洲视频网站在线观看| 国产精品专区免费| 久久亚洲午夜电影| 国产一级久久| 亚洲天堂成人av| 午夜免费久久看| 日本黄色大片视频| 午夜精品视频在线| 巨人精品**| 免费黄色日本网站| 91视频在线看| 日本免费在线观看视频| 亚洲欧美日韩一区在线| 国产精品专区免费| 日韩性感在线| 男女男精品网站| 亚洲欧美精品久久| 9191久久久久久久久久久| 91在线中文| 国产精品久久久久久久免费大片| 激情久久一区| 成人h动漫精品一区| 日本精品一区二区三区四区的功能| 国产免费视频在线| 国产欧美一区二区三区久久| 99re66热这里只有精品8| 超碰91在线播放| 亚洲国产成人精品视频| 日韩三级电影网| 国产精品夫妻激情| 欧美激情欧美| av地址在线观看| 黄色成人av在线| 高清毛片在线看| 91精品视频专区| 在线日韩av| 亚洲精品国产一区黑色丝袜| 欧美高清视频不卡网| 里番在线播放| 日本免费高清一区| 狠狠色狠狠色综合系列| 久久久久久久久久久97| 精品性高朝久久久久久久| 久久麻豆视频| 久久艹国产精品| 欧美激情综合五月色丁香小说| 国产欧美第一页| 97视频色精品| 色天天久久综合婷婷女18| 久久久久久久久久久久国产精品| 欧美日韩在线视频观看| 日本视频在线免费观看| 国产日韩欧美亚洲一区| 日本网站在线观看一区二区三区| 国产女人18水真多毛片18精品| 亚洲激情在线观看| 欧洲美女精品免费观看视频 | 欧美一区二区三区四区夜夜大片 | 第一页在线视频| 色94色欧美sute亚洲线路二| 精品国产99久久久久久| 极品日韩久久| 国产在线视频一区二区| 一级黄色免费网站| 欧美超级免费视 在线|