<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Twitter 如何使用 Redis 進行擴展-105TB RAM,39MM QPS,10,000 多個實例 > 原文: [http://highscalability.com/blog/2014/9/8/how-twitter-uses-redis-to-scale-105tb-ram-39mm-qps-10000-ins.html](http://highscalability.com/blog/2014/9/8/how-twitter-uses-redis-to-scale-105tb-ram-39mm-qps-10000-ins.html) <iframe align="right" allowfullscreen="" frameborder="0" height="200" src="//www.youtube.com/embed/rP9EKvWt0zo?rel=0" width="220"></iframe>[姚悅](https://twitter.com/thinkingfish)自 2010 年以來一直在 Twitter 的 Cache 團隊工作。 當然,這是關于 Redis 的,但不僅是關于 Redis 的。 姚明已經在 Twitter 工作了幾年。 她看過一些東西。 她看到 Twitter 上緩存服務的增長從僅由一個項目使用到迅速增加到將近 100 個項目。 那就是成千上萬臺機器,許多集群和數 TB 的 RAM。 從她的講話中可以很明顯地看出,她來自一個真正的個人經歷的地方,并且以一種探索問題的實用方式閃耀出來。 這個話題值得一看。 如您所料,Twitter 具有大量緩存。 Timeline Service for one datacenter using Hybrid List: * 約 40TB 分配的堆 * ?30MM qps * > 6,000 個實例 Use of BTree in one datacenter: * 約 65TB 的已分配堆 * ?9MM qps * > 4,000 個實例 稍后,您將了解有關 BTree 和 Hybrid List 的更多信息。 有幾點值得注意: * Redis 是一個絕妙的主意,因為它占用服務器上未充分利用的資源并將其轉變為有價值的服務。 * Twitter 對 Redis 進行了專門化,提供了兩種完全適合其用例的新數據類型。 因此他們獲得了所需的性能,但是將它們鎖定在基于舊代碼的代碼中,因此很難合并到新功能中。 我想知道,為什么要使用 Redis 這樣的東西? 只需使用您自己的數據結構創建時間軸服務即可。 Redis 真的為聚會增添了什么嗎? * 在網絡飽和之前,請使用本地 CPU 功能匯總節點上的大量日志數據。 * 如果您想要高性能的產品,請將快速路徑(即數據路徑)與慢速路徑(即命令和控制路徑)分開, * Twitter 正在以 Mesos 作為作業調度程序進入容器環境。 這仍然是一種新方法,因此了解它的工作方式很有趣。 一個問題是 Mesos 浪費問題,該問題源于在復雜的運行時世界中指定硬資源使用限制的要求。 * 中央集群管理器對于使集群保持易于理解的狀態非常重要。 * JVM 慢,C 快。 他們的緩存代理層正在回到 C / C ++。 考慮到這一點,讓我們進一步了解 Twitter 上 Redis 的用法: ## 為什么要使用 Redis? * Redis 驅動著 Twitter 最重要的服務時間軸。 時間軸是由 ID 索引的推文索引。 在列表中將推文鏈接在一起會生成“主頁時間軸”。 用戶時間軸(由用戶已發布的推文組成)只是另一個列表。 * 為什么考慮使用 Redis 而不是 Memcache? 網絡帶寬問題和長通用前綴問題。 * 網絡帶寬問題。 * Memcache 在時間表上不如 Redis 正常工作。 問題在于處理扇出。 * Twitter 讀取和寫入**的次數是遞增的**,它們很小,但時間表本身卻很大。 * 生成推文時,需要將其寫入所有相關的時間軸。 推文是一小塊數據,附加到某些數據結構。 閱讀時,最好加載一小部分推文。 向下滾動會加載另一個批次。 * 本地時間行可能比較大,這對于觀看者一組閱讀是合理的。 例如,也許有 3000 個條目。 由于性能原因,應避免訪問數據庫。 * 在大對象(時間軸)上進行增量寫入和小型讀取的讀取-修改-寫入周期太昂貴,并且會造成網絡瓶頸。 * 在每秒 100K +的千兆鏈接讀寫中,如果平均對象大小大于 1K,則網絡將成為瓶頸。 * 長通用前綴問題(確實是兩個問題) * 靈活的架構方法用于數據格式。 對象具有可能存在或可能不存在的某些屬性。 可以為每個單獨的屬性創建一個單獨的鍵。 這要求針對每個單獨的屬性發出單獨的請求,并且并非所有屬性都可以在緩存中。 * 隨時間推移觀察到的度量標準具有相同的名稱,每個樣本具有不同的時間戳。 如果單獨存儲每個度量標準,則長公共前綴會被存儲很多次。 * 為了在兩種情況下都更加節省空間,對于指標和靈活的架構,希望有一個分層的密鑰空間。 * **下的專用緩存群集 利用 CPU** 。 對于簡單的情況,內存中的鍵值存儲是 CPU 輕的。 對于較小的鍵值,一個盒子上 1%的 CPU 時間可以每秒處理超過 1K 個請求。 盡管對于不同的數據結構,結果可能有所不同。 * **Redis 是個絕妙的主意** 。 它可以看到服務器可以做什么,但不能做什么。 對于簡單的鍵值存儲,服務器端在 Redis 等服務上有很多 CPU 余量。 * Redis 于 2010 年在 Twitter 中首次用于時間軸服務。 廣告服務中也使用它。 * 未使用 Redis 的磁盤功能。 部分原因是因為在 Twitter 內部,緩存和存儲服務位于不同的團隊中,因此他們使用他們認為最佳的任何機制。 部分原因可能是因為存儲團隊認為其他服務比 Redis 更適合他們的目標。 * Twitter 分叉了 Redis 2.4 并為其添加了一些功能,因此它們停留在 2.4(2.8.14 是最新的穩定版本)上。 更改為:Redis 中的兩個數據結構功能; 內部集群管理功能; 內部日志記錄和數據洞察力。 * 熱鍵是一個問題,因此它們正在構建具有客戶端緩存的分層緩存解決方案,該解決方案將自動緩存熱鍵。 ## 混合列表 * 為**增加了可預測的內存性能**,為 Redis 添加了 Hybrid List。 * 時間軸是 Tweet ID 的列表,因此是整數列表。 每個 ID 都很小。 * Redis 支持兩種列表類型:ziplist 和 linklist。 Ziplist 節省空間。 鏈表是靈活的,但是由于雙鏈表每個鍵都有兩個指針的開銷,因此給定 ID 的大小開銷非常大。 * 為了有效利用內存,僅使用 ziplist。 * Redis ziplist 閾值設置為時間軸的最大大小。 永遠不要存儲比壓縮列表中更大的時間軸。 這意味著產品決策(時間軸中可以包含多少條推文)已鏈接到低級組件(Redis)。 通常不理想。 * 添加或刪除 ziplist 效率低下,尤其是列表很大時。 從 ziplist 刪除使用 memmove 來移動數據,以確保該列表仍然是連續的。 添加到 ziplist 需要內存重新分配調用,以為新條目騰出足夠的空間。 * 由于時間軸大小,寫入操作可能會出現**高延遲。 時間線的大小差異很大。 大多數用戶的推文很少,因此他們的用戶時間軸很小。 家庭時間表,尤其是那些涉及名人的時間表。 當更新較大的時間線并且高速緩存用完了堆時,這通常是在使用高速緩存時的情況,在有足夠的連續 RAM 來處理一個大 ziplist 之前,將淘汰非常大的**小時間線** 。 由于所有這些緩存管理都需要時間,因此寫操作可能會具有較高的延遲。** * 由于寫入被散布到許多時間軸,因此由于內存用于擴展時間軸,因此更有可能陷入**寫等待時間陷阱**。 * 鑒于寫入延遲的高度可變性,**很難為寫入操作創建 SLA** 。 * 混合列表是 ziplist 的鏈接列表。 閾值設置為每個 ziplist 可以以字節為單位的大小。 以字節為單位,因為對于**內存有效**而言,它有助于**分配和取消分配相同大小的塊**。 當列表經過時,它將溢出到下一個 ziplist 中。 ziplist 直到列表為空時才被回收,這意味著可以通過刪除使每個 ziplist 只有一個條目。 實際上,推文并不是經常被刪除。 * 在“混合列表”之前,一種變通方法是使較大的時間軸更快地過期,這為其他時間軸釋放了內存,但是當用戶查看其時間軸時,這是昂貴的。 ## BTree * 在 Redis 中添加了 BTree 以支持對層次結構鍵的范圍查詢,以返回結果列表。 * 在 Redis 中,處理輔助鍵或字段的方法是哈希映射。 為了對數據進行排序以便執行范圍查詢,使用了一個排序集。 排序后的訂單按雙倍得分排序,因此不能使用任意的輔助鍵或任意的名稱進行排序。 由于哈希圖使用線性搜索,因此如果有很多輔助鍵或字段,那就不好了。 * BTree 是嘗試解決哈希映射和排序集的缺點。 最好讓**一個可以完成您想要的內容的數據結構**。 更容易理解和推理。 * 借用了 BTree 的 BSD 實現,并將其添加到 Redis 中以創建 BTree。 支持鍵查找以及范圍查詢。 具有良好的查找性能。 代碼相對簡單。 缺點是 **BTree 的內存效率不高**。 由于指針,它具有大量的元數據開銷。 ## 集群管理 * 集群出于單一目的使用多個 Redis 實例。 如果數據集大于單個 Redis 實例可以處理的數據量或吞吐量高于單個實例可以處理的數據量,則需要對鍵空間進行分區,以便可以將數據存儲在一組實例中的多個分片中 。 路由選擇一個密鑰,并弄清楚該密鑰的數據在哪個分片上。 * 認為集群管理是 Redis 采用率未激增的**首要原因。 當群集可用時,沒有理由不**將所有用例遷移到 Redis** 。** * Tricky 正確安裝 Redis 群集。 人們之所以使用 Redis 是因為作為數據結構服務器的想法是執行頻繁的更新。 但是很多 Redis 操作都不是冪等的。 如果出現網絡故障,則需要重試,并且數據可能會損壞。 * Redis 集群**傾向于使用** **集中管理器** **來規定全局視圖**。 對于內存緩存,很多集群都使用基于一致性哈希的客戶端方法。 如果數據不一致,那就這樣。 為了提供真正好的服務,集群需要一些功能,例如檢測哪個分片已關閉,然后重播操作以恢復同步。 經過足夠長的時間后,應清除緩存狀態。 Redis 中的損壞數據很難檢測。 當有一個列表并且缺少一個大塊時,很難說出來。 * Twitter 多次嘗試構建 Redis 集群。 [Twemproxy](https://github.com/twitter/twemproxy) 并未在 Twitter 內部使用,它是為 [Twemcache](https://github.com/twitter/twemcache) 構建的 和 Redis 支持增加了。 另外兩個解決方案基于代理樣式路由。 其中一項與時間軸服務相關,并不意味著具有普遍性。 第二個是對 Timeline 解決方案的概括,該解決方案提供了群集管理,復制和碎片修復。 * **群集中的三個選項**:服務器相互通信以達成群集外觀的共識; 使用代理; 或進行客戶端集群的客戶端集群管理。 * 并非采用服務器方法,因為其理念是**使服務器保持簡單** **,笨拙且快速**。 * 不接受客戶端,因為 **更改很難傳播** 。 Twitter 中約有 100 個項目使用緩存集群。 要更改客戶端中的任何內容,必須將其推送到 100 個客戶端,更改可能要花費數年的時間才能傳播。 快速迭代意味著幾乎不可能將代碼放入客戶端。 * 之所以使用代理樣式路由方法和分區,有兩個原因。 緩存服務是一種高性能服務。 如果您想要**高性能的產品,請將快速路徑(即數據路徑)與慢速路徑** **(即命令和控制路徑**)分開。 如果將群集管理合并到服務器中,則會使作為有狀態服務的 Redis 代碼變得復雜,每當您想要**修復錯誤或為群集管理代碼提供**升級時,有狀態 Redis 服務必須 也需要重新啟動,這可能會丟棄大量數據。 群集的滾動重啟很痛苦。 * 使用代理方法存在一個問題,即在客戶端和服務器之間插入了另一個網絡躍點。 **分析顯示額外的躍點是一個神話**。 至少在他們的生態系統中。 通過 Redis 服務器的等待時間不到 0.5 毫秒。 在 Twitter 上,大多數后端服務都是基于 Java 的,并使用 Finagle 進行對話。 通過 Finagle 路徑時,延遲接近 10 毫秒。 因此,額外的躍點并不是問題。 **JVM 內部是問題**。 在 JVM 之外,您幾乎可以做任何您想做的事情,除非您當然要通過另一個 JVM。 * 代理失敗并不重要。 在數據路徑上引入代理層還不錯。 客戶不在乎與之交談的代理。 如果超時后代理失敗,則客戶端將轉到另一個代理。 在代理級別沒有分片操作,它們都是無狀態的。 要擴展吞吐量,只需添加更多代理。 權衡是額外的成本。 代理層被分配用于執行轉發的資源。 群集管理,分片和查看群集的操作均在代理服務器外部進行。 代理不必彼此同意。 * Twitter 的實例具有 **100K 開放連接** ,并且工作正常。 只是有開銷要支付。 沒有理由關閉連接。 只要保持打開狀態,就可以改善延遲。 * 緩存集群用作 [后備緩存](http://www.quora.com/Is-Memcached-look-aside-cache) 。 緩存本身不負責數據補充。 客戶端負責從存儲中獲取丟失的密鑰,然后將其緩存。 如果某個節點發生故障,則分片將移至另一個節點。 出現故障的計算機恢復運行時將被刷新,因此不會留下任何數據。 所有這些都是由**集群負責人**完成的。 集中觀點對于使集群保持易于理解的狀態非常重要。 * 用 C ++編寫的代理進行了實驗。 **C ++代理看到** **性能顯著提高**(未給出編號)。 代理層將移回 C 和 C ++。 ## Data Insight * 當有電話說緩存系統在大多數情況下都無法正常運行**時,緩存就很好**。 通常,客戶端配置錯誤。 或者他們通過請求太多密鑰來濫用緩存系統。 或一遍又一遍地請求相同的密鑰,并使服務器或鏈接飽和。 * 當您告訴某人他們正在濫用您的系統**時,他們需要證明**。 哪個鍵? 哪個分片不好? 什么樣的流量導致這種行為? 證明需要可以顯示給客戶的指標和分析。 * SOA 架構不會給您問題隔離或自動調試的便利。 您必須對組成系統的每個組件具有良好的可見性**。** * 決定將 Insight 內置到緩存中。 緩存是用 C 語言編寫的,并且速度很快,因此可以提供其他組件無法提供的數據。 其他組件無法處理為每個請求提供數據的負擔。 * **可以記錄每個命令**。 緩存可以 100K qps 記錄所有內容。 僅記錄元數據,不記錄值(關于 NSA 的笑話)。 * **避免鎖定和阻止**。 特別是不要阻止磁盤寫入。 * 以 100 qps 和每條日志消息 100 字節的速度,每個盒子每秒將記錄 10MB 數據。 開箱即用的大量數據。 萬一出現問題,將使用 10%的網絡帶寬。 **在經濟上不可行**。 * **預計算日志可降低成本** 。 假設它已經知道將要計算什么。 進程讀取日志并生成摘要,并定期發送該框視圖。 與原始數據相比,該視圖很小。 * View 數據由 Storm 匯總,存儲并在頂部放置一個可視化系統。 您可以獲取數據,例如,這是您的前 20 個鍵; 這是您的點擊量的第二個,并且有一個高峰,這表示點擊量模式很尖銳; 這是唯一鍵的數量,這有助于容量規劃。 當捕獲每個日志時,可以做很多事情。 * 洞察力對于運營非常有價值。 如果存在丟包現象,通常可以將其與熱鍵或尖刻的流量行為相關聯。 ## Redis 的愿望清單 * 顯式內存管理 。 * **可部署(Lua)腳本** 。 剛開始談論。 * **多線程** 。 將使群集管理更加容易。 Twitter 有很多“高個子”,其中主機具有 100+ GB 的內存和許多 CPU。 要使用服務器的全部功能,需要在物理機上啟動許多 Redis 實例。 使用多線程,將需要啟動更少的實例,這更易于管理。 ## 獲得的經驗教訓 * **量表要求可預測性** 。 集群越大,客戶越多,您希望服務成為更具可預測性和確定性的對象。 當有一個客戶并且有問題時,您可以深入研究問題,并且很有趣。 當您有 70 個客戶時,您將無法跟上。 * **尾部延遲很重要** 。 當您扇出很多分片時,如果分片緩慢,則整個查詢將變慢。 * 確定性配置在操作上很重要 。 Twitter 正朝著容器環境邁進。 Mesos 用作作業計劃程序。 調度程序滿足對 CPU,內存等數量的請求。監視器將殺死超出其資源需求的任何作業。 Redis 在容器環境中引起問題。 Redis 引入了外部碎片,這意味著您將使用更多內存來存儲相同數量的數據。 如果您不想被殺死,則必須通過供過于求來彌補。 您必須考慮我的內存碎片率不會超過 5%,但我會多分配 10%作為緩沖空間。 甚至 20%。 或者,我想每臺主機將獲得 5000 個連接,但以防萬一我為 10,000 個連接分配內存。 結果是巨大的浪費潛力。 如今,超低延遲服務在 Mesos 中不能很好地發揮作用,因此這些工作與其他工作是隔離的。 * **在運行時了解您的資源使用情況確實很有幫助** 。 在大型集群中,會發生壞事。 您認為自己很安全,但是事情會發生,行為是無法預料的。 如今,大多數服務無法正常降級。 例如,當 RAM 達到 10GB 的限制時,請求將被拒絕,直到有可用的 RAM。 這只會使與所需資源成比例的一小部分流量失敗。 很好 垃圾收集問題不是很正常,流量只是掉在地上,這個問題每天都會影響許多公司中的許多團隊。 * **將計算推入數據** 。 如果查看相對的網絡速度,CPU 速度和磁盤速度,那么在進入磁盤之前進行計算并在進入網絡之前進行計算是有意義的。 一個示例是在將節點上的日志推送到集中式監視服務之前對其進行匯總。 Redis 中的 LUA 是將計算應用于數據附近的另一種方法。 * **LUA 今天尚未在 Redis 中投入生產** 。 按需腳本編寫意味著服務提供商無法保證其 SLA。 加載的腳本可以執行任何操作。 哪個服務提供商會愿意冒別人代碼的風險承擔違反 SLA 的風險? 部署模型會更好。 它將允許代碼審查和基準測試,因此可以正確計算資源使用情況和性能。 * **Redis 是下一代高性能流處理平臺** 。 它具有 pub-sub 和腳本。 為什么不? ## 相關文章 * [Google:馴服長時間延遲的尾巴-當更多的機器等于更差的結果時](http://highscalability.com/blog/2012/3/12/google-taming-the-long-latency-tail-when-more-machines-equal.html) [架構](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html) * [Twitter 用于處理 1.5 億活躍用戶,300K QPS,22 MB / S 的 Firehose,并在 5 秒內發送推文](http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html) * [帶有碎片的問題-我們可以從 Foursquare 事件中學習到什么?](http://highscalability.com/blog/2010/10/15/troubles-with-sharding-what-can-we-learn-from-the-foursquare.html) * [始終記錄所有內容](http://highscalability.com/blog/2007/8/30/log-everything-all-the-time.html) * [低級可伸縮性解決方案-聚合集合](http://highscalability.com/blog/2013/3/6/low-level-scalability-solutions-the-aggregation-collection.html) 萬一 Twitter 上有人讀過我:為什么不禁用 EVAL(不是 EVALSHA),重命名 SCRIPT 并使用它來預加載腳本? 然后,您可以發布您的客戶端可以使用的 SHA 目錄。 “ Redis 是下一代高性能流處理平臺。它具有 pub-sub 和腳本功能。為什么不呢?” 更重要的是,2.8.9 在 PFADD / PFCOUNT / PFMERGE 命令中添加了 HyperLogLog(當然,Twitter 被困在 2.4 中)。 這樣就可以在恒定內存中非常精確地近似估計流中唯一鍵的數量,而不必存儲整個數據集。 例如,每天/每周/每月的唯一身份訪問者數量。 這使大量分析成為可能,而不必使用像 Hadoop 這樣的大數據大炮。 @Pierre Chapuis:我認為您的建議會奏效。 我認為這不是最干凈的方法,但是:SCRIPT *是一個在線命令,如果我要離線加載(或者至少不通過數據路徑完成加載),我會強烈建議這樣做。 可能添加了一個配置選項,例如 SCRIPT_LOAD_PATH,以按照您的建議從目錄中讀取它們。 現在,如果我們允許即時重新加載配置(我在當前項目中已經計劃過的事情),您甚至可以更新腳本而不會丟失所有數據或阻止流量。 MM 被用作百萬的縮寫嗎? 在技??術環境中看到它似乎有些奇怪……這不是更多的財務縮寫嗎? Just M 對我來說更容易。 我喜歡這樣的觀察:面向服務的體系結構的優點(概括地說)僅與您在服務邊界處所做的工作一樣好。 她說這是出于監視的目的(SOA 并沒有因為服務 A 而神奇地將服務 B 隔離出問題)。 但這似乎同樣適用于記錄清晰的 API 合同,保持代碼庫清晰等。我在闡明將應用程序分解為服務方面對我有吸引力的方面時遇到了一些麻煩,而我認為那是缺少的部分-僅僅是 SOA 的概念不能提供大多數價值; 在邊界上應用的整套實踐可以提供幫助。 還發人深省(且合理):像 Redis 這樣的代碼庫往往不會由委員會維護,您需要進行認真的審查才能阻止糟糕的代碼。 (最近閱讀了很多 golang 的代碼審查/變更列表流,因為它是公開的,有時它是保持語言狀態最簡單的方法,并且通常給它留下深刻的印象。) 關于腳本,我想知道如何在包裝盒上找到包含數據的腳本,作為具有自己的容器和資源限制的普通 Redis 客戶端。 您可以避免帶寬限制; 您可以控制資源的使用(也許在分配內核的級別?); 您不僅可以使用 Lua,還可以使用 Scala 或其他任何方法(盡管如此,但是,GC)。 Redis 的進程內 Lua 腳本可能沒有通信成本,而它們會占用寶貴的 RAM 來存儲數據,但這是一件容易的事。 對于 Twitter 開放源代碼混合列表/樹,這聽起來像是最好的“自私”論據,它最終意味著更快地加入 2.8。 :) @姚謝謝您的回答。 我同意選擇離線加載(“東京霸王”)會更好。 另外,為 SHA 賦予別名是經常需要的功能,這將大有幫助,并使得可以以向后兼容的方式更新腳本的實現。 閱讀這篇文章會讓我覺得自己生活在一個平行的宇宙中,并且做著非常相似的事情。 嗨, 不錯的演示。 我曾經遇到的一個問題是-您是否將 ssl 與 redis 一起使用?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看