整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          快速入門:使用 .NET Aspire 組件實現緩存

          云原生應用程序通常需要各種類型的可擴展緩存解決方案來提高性能。.NET Aspire 組件簡化了連接到流行的緩存服務(例如 Redis)的過程。

          本文的內容概要:

          • 創建一個設置為使用 .NET Aspire 的基本 ASP.NET Core 應用程序。
          • 添加.NET Aspire組件以連接到Redis并實現緩存。
          • 配置 .NET Aspire 組件以滿足特定要求。


          環境準備

          要使用 .NET Aspire,需要在本地安裝以下軟件:

          • .NET 8.0
          • .NET Aspire 工作負載:
          • 使用 Visual Studio 安裝程序
          • 使用dotnet workload install aspire命令
          • Docker 桌面
          • 集成開發環境 (IDE) 或代碼編輯器,例如:
          • Visual Studio 2022 預覽版 17.9 或更高版本(可選)
          • Visual Studio 代碼(可選)

          有關詳細信息,請參閱.NET Aspire 設置和工具。

          舉例示范

          1.新建一個工程文件

          1. 在 Visual Studio 頂部,導航到“文件” “新建” “項目...”。
          2. 在對話框窗口中,在項目模板搜索框中輸入.NET Aspire ,然后選擇.NET Aspire Starter Application。選擇下一步。
          3. 在“配置新項目”屏幕上:
          4. 輸入項目名稱AspireRedis。
          5. 將其余值保留為默認值,然后選擇“下一步”。
          6. 在附加信息屏幕上:
          7. 選擇.NET 8.0 。
          8. 取消選中“使用 Redis 進行緩存”
          9. 最后選擇創建。

          Visual Studio 創建了一個新的 .NET Aspire 解決方案,其中包含以下項目:

          • AspireRedis.Web 具有默認 .NET Aspire 配置的 Blazor UI 項目。
          • AspireRedis.ApiService 具有默認 .NET Aspire 配置的最小 API,可為前端提供數據。
          • AspireRedis.AppHost 一個協調器項目,旨在連接和配置應用程序的不同項目和服務。
          • AspireRedis.ServiceDefaults 一個 .NET Aspire 共享項目,用于管理解決方案中與彈性、服務發現和遙測相關的項目中重復使用的配置。

          2.使用輸出緩存配置 UI

          1. 將.NET Aspire StackExchange Redis 輸出緩存組件包添加到您的AspireStorage應用程序中:
          dotnet add package Aspire.StackExchange.Redis.OutputCaching --prerelease

          (1)在Blazor 項目的Program.csAspireRedis.Web文件中,緊接著該行之后,添加對AddRedisOutputCachevar builder = WebApplication.CreateBuilder(args);擴展方法的調用:

          builder.AddRedisOutputCache("cache");

          (2)在項目的_appsettings.json文件中AspireRedis.Web,添加對應的連接字符串信息:

          "ConnectionStrings": {
            "cache": "localhost:6379"
          }

          (3)將 Blazor 項目的Home.razor文件的內容替換AspireRedis.Web為以下內容:

          @page "/"
          @attribute [OutputCache(Duration = 10)]
          
          <PageTitle>Home</PageTitle>
          
          <h1>Hello, world!</h1>
          
          Welcome to your new app on @DateTime.Now

          該組件包含該[OutputCache]屬性,該屬性緩存整個呈現的響應。該頁面還包含一個調用@DateTime.Now來幫助驗證響應是否已緩存。

          3.使用分布式緩存配置 API

          將.NET Aspire StackExchange Redis 分布式緩存組件包添加到您的AspireRedis應用程序中:

          dotnet add package Aspire.StackExchange.Redis.DistributedCaching --prerelease

          (1)在Program.cs文件的頂部,添加對AddRedisDistributedCache 的調用:

          builder.AddRedisDistributedCache("cache");

          (2)在項目的_appsettings.json文件中AspireRedis.ApiService,添加對應的連接字符串信息:

          "ConnectionStrings": {
            "cache": "localhost:6379"
          }

          (3)在Program.cs文件中,將現有/weatherforecast端點代碼替換為以下內容:

          app.MapGet("/weatherforecast", async (IDistributedCache cache) =>
          {
              var cachedForecast = await cache.GetAsync("forecast");
          
              if (cachedForecast is null)
              {
                  var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
                  var forecast = Enumerable.Range(1, 5).Select(index =>
                  new AspireRedis.WeatherForecast
                  (
                      DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                      Random.Shared.Next(-20, 55),
                      summaries[Random.Shared.Next(summaries.Length)]
                  ))
                  .ToArray();
          
                  await cache.SetAsync("forecast", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(forecast)), new ()
                  {
                      AbsoluteExpiration = DateTime.Now.AddSeconds(10)
                  }); ;
          
                  return forecast;
              }
          
              return JsonSerializer.Deserialize<IEnumerable<AspireRedis.WeatherForecast>>(cachedForecast);
          })
          .WithName("GetWeatherForecast");

          4.配置應用程序宿主項目

          更新項目的Program.csAspireRedis.AppHost文件以匹配以下代碼:

          var builder = DistributedApplication.CreateBuilder(args);
          
          var redis = builder.AddRedisContainer("cache");
          
          var apiservice = builder.AddProject<Projects.AspireRedis_ApiService>("apiservice")
              .WithReference(redis);
          
          builder.AddProject<Projects.AspireRedis_Web>("webfrontend")
              .WithReference(apiservice)
              .WithReference(redis);
          
          builder.Build().Run();

          最后:在本地運行并測試應用程序

          使用以下步驟測試應用程序的緩存行為:

          1. 通過按鈕來使用 Visual Studio 運行應用程序F5。
          2. 如果出現“啟動 Docker Desktop”對話框,請選擇“是”啟動該服務。
          3. .NET Aspire Dashboard 在瀏覽器中加載并列出 UI 和 API 項目。

          測試輸出緩存:

          1. 在項目頁面的webfrontend行中,單擊Endpointslocalhost列中的鏈接以打開應用程序的 UI。
          2. 該應用程序將在主頁上顯示當前時間。
          3. 每隔幾秒刷新一次瀏覽器即可查看輸出緩存返回的同一頁面。10 秒后,緩存過期,頁面將根據更新的時間重新加載。

          測試分布式緩存:

          1. 導航到Blazor UI 上的“天氣”頁面可以加載隨機天氣數據表。
          2. 每隔幾秒刷新一次瀏覽器即可查看輸出緩存返回的相同天氣數據。10 秒后,緩存過期,頁面將重新加載更新的天氣數據。

          存是個老生長談的問題,對于前端工程師來講更是我們的必修課。或許很多人會說我的項目并沒有問題,根本不需要聊什么緩存。如果真的是這樣,只能證明你前端道路才剛剛開始。

          背景

          小郭今天分享緩存的原因在于:公司的一個核心APP中嵌入了SPA,而且應用核心都分布在SPA中,功能復雜且重。問題出現了:應用核心頁面打開一直處于加載狀態,排除掉弱網環境的原因,重點就在于沒有緩存,每次進入頁面都需要重載DOM和數據,拖慢頁面打開速度。

          那應該處理緩存問題呢?接下來小郭從三個方向來講解。

          瀏覽器緩存策略

          在了解瀏覽器緩存前,我們需要先了解一下相關的概念:cache-control,expires,last-Modified,ETag。

          瀏覽器通過請求頭實現緩存,關鍵的請求頭有cache-control,expires,last-Modified,ETag等。我們從時間和空間兩個角度來看瀏覽器緩存。

          時間

          瀏覽器發送第一次請求:不緩存,服務端根據設定的緩存策略返回相應的header,如:cache-control,expires,last-Modified,ETag。

          瀏覽器發送第二次請求:

          • 強緩存策略:不需要和服務端通信就決定是否使用緩存,cache-control優先級大于expires① 有cache-control且不過期,返回本地磁盤緩存,狀態值200;② 有expires且不過期,返回本地磁盤緩存,狀態值200。
          • 協商緩存策略:需要和服務端通信決定是否用緩存,Etag優先級大于last-Modified。① 有Etag,請求頭添加If-None-Match,值就是上次返回的Etag值,然后發送給服務端。服務端對比If-None-Match與現有的Etag值是否一樣;一樣的話只返回header,狀態碼304,瀏覽器從本地磁盤獲取緩存信息;不一樣走正常流程,返回header+body,狀態碼200;② 有last-Modified,添加請求頭If-Modified-Since,值是上次返回的last-Modified,然后發送給服務端。服務端對比If-Modified-Since與現有的是否一樣;一樣的話返回只返回header,狀態碼304,瀏覽器從本地磁盤獲取緩存信息;不一樣走正常流程,返回header+body,狀態碼200
          • 無緩存

          空間

          • 瀏覽器和服務端:服務端需要決定使用哪種緩存策略并在響應頭返回;前端不需要設置,是瀏覽器本身機制。
          • html和靜態資源:通常html不設置緩存,因為其它資源的入口都是html文件;靜態資源(js,css,圖片等)會設置緩存

          部署時緩存的問題

          如果緩存就按理論上設置,那就太簡單了。在實際應用有個嚴重的問題,我們不僅要緩存代碼,還需要更新代碼。如果靜態資源名字不變,怎么讓瀏覽器即能緩存又能在有新代碼時更新。最簡單的解決方式就是靜態資源路徑添加一個版本值,版本不變就走緩存策略,版本變了就加載新資源。如下:

          <script src="xx/xx.js?v=24334452"></script>

          然而這種處理方式在部署時有問題。

          解決方法:靜態資源和頁面是分開部署

          • 先部署頁面再部署靜態資源,會出現用戶訪問到舊的資源
          • 先部署靜態資源再部署頁面,會出現沒有緩存用戶加載到新資源而報錯

          這些問題的本質是以上的部署方式是“覆蓋式發布”,解決方式是“非覆蓋式發布”。即用靜態資源的文件摘要信息給文件命名,這樣每次更新資源不會覆蓋原來的資源,先將資源發布上去。這時候存在兩種資源,用戶用舊頁面訪問舊資源,然后再更新頁面,用戶變成新頁面訪問新資源,就能做到無縫切換。簡單來說就是給靜態文件名加hash值

          那如何實現呢?

          現在前端代碼都用webpack之類的構建工具打包,那么結合webpack該怎么做,怎么才能做到持久化緩存?

          webpack持久化緩存

          一、webpack給文件名添加hash值是很簡單的,但hash/chunkhash/contenthash要用哪個呢?

          官方定義

          hash: unique hash generated for every build

          chunkhash: hashes based on each chunks' content

          contenthash: hashes generated for extracted content

          根據分析,contenthash才是我們需要的,內容有更新,hash值才會更新。

          二、webpack會打包業務代碼、第三方庫及運行時代碼,為保證緩存互不干擾,應該將它們提取出來。

          第三方庫提取方式是設置optimization的splitChunks的cacheGroups。splitChunks能提取模塊,cacheGroups能緩存模塊,并且cacheGroups的配置會覆蓋splitChunks相同配置,既能提取又能緩存,故只需設置cacheGroups。

          運行時代碼的提取方式為配置runtimeChunk,默認為false,表示運行時代碼嵌入到不同的chunk文件中;現在將運行時代碼提取出來,并命名為manifest。

          module.exports = {
            entry: {
              index: "./src/index.js",
              bar: "./src/bar.js"
            },
            output: {
              filename: "[name].[contenthash].js"
            },
            optimization: {
              splitChunks: {
                cacheGroups: {
                  vendor: {
                    test:/[\\/]node_modules[\\/]/,
                    name: "vendors",
                    chunks: "all"
                  }
                }
              },
              runtimeChunk: {
                name: "manifest"
              }
            }
          };

          三、 moduleName 和 chunkName 對文件的影響

          module:就是js模塊

          chunk:webpack編譯過程中由多個module組成的文件

          bundle:bundle是chunk文件的最終狀態,是webpack編譯后的結果

          一個文件被分離為3個文件,文件間怎么相互依賴的,會影響彼此打包,解決方法是將moduleId和chunkId改成按照文件路徑生成。

          optimization: {
            moduleIds: 'hashed',
            namedModules: true,
            namedChunks: true
          }

          這樣子moduleId在編譯后的文件是文件目錄的hash值,更加安全。這也是namedChunks在production默認為false的原因,不想依賴的文件路徑在編譯后的文件直接展示,但是為了持久性緩存,這里也只能打開。

          四、CSS文件緩存

          當css代碼提取成單獨文件,當我們改變css時,怎么保證不影響引用它的js文件呢?配置如下:

          plugins: [
            new MiniCssExtractPlugin({
              filename: "[contenthash].css"
            })
          ]

          webpack持久化緩存目標是當且僅當該文件內容變動才改變該文件名字的hash值

          const MiniCssExtractPlugin = require("mini-css-extract-plugin");
          module.exports = { 
            output: { 
              filename: [name].[contenthash].js, // 讓hash值只在內容變動時更新 
              chunkFilename: [name].[contenthash].js // 動態引入的模塊命名,同上 
            }, 
            module: { 
              rules: [ { 
                test: /\.css$/, 
                use: [ 
                  "loader: MiniCssExtractPlugin.loader", // 提取出來css "css-loader" 
                ] 
              } ] 
            }, 
            optimization: { 
              moduleIds: "hashed", // 混淆文件路徑名 
              runtimeChunk: { name: 'manifest' }, // 提取runtime代碼命名為manifest 
              namedModules: true, // 讓模塊id根據路徑設置,避免每增加新模塊,所有id都改變,造成緩存失效的情況 
              namedChunks: true, // 避免增加entrypoint,其他文件都緩存失效 
              cacheGroups: { 
                vendor: { // 提取第三方庫文件 
                  test: /[\\/]node_modules[\\/]/, 
                  name: 'vendors', chunks: 'all', 
                }, 
              },
            } 
            plugins: [ 
              new webpack.HashedModuleIdsPlugin(), // 與namedModules: true作用一樣 
              new MiniCssExtractPlugin({ 
                filename: "[contenthash].css", // css文件也是按contenthash命名 
                chunkFilename: "[contenthash].css", // 動態引入的css命名,同上 
              }) 
            ], 
          }

          總結

          瀏覽器有其緩存機制,想要既能緩存又能在部署時沒有問題,需要給靜態文件名添加hash值。在webpack中,有些配置能讓我們實現持久化緩存。感興趣的同學可以自行去測試哦!

          有任何問題可以在下方留言,想了解更多前端知識歡迎關注公眾號“一郭鮮”,文章也將同步于公眾號,前端學習不迷路

          自TowardsDataScience

          作者:Adrien Treuille

          機器之心編譯

          參與:魔王、一鳴

          機器學習開發者想要打造一款 App 有多難?事實上,你只需要會 Python 代碼就可以了,剩下的工作都可以交給一個工具。近日,Streamlit 聯合創始人 Adrien Treuille 撰文介紹其開發的機器學習工具開發框架——Streamlit,這是一款專為機器學習工程師創建的免費、開源 app 構建框架。這款工具可以在你寫 Python 代碼的時候,實時更新你的應用。目前,Streamlit 的 GitHub Star 量已經超過 3400,在 medim 上的熱度更是達到了 9000+。

          Streamlit 網站:https://streamlit.io/

          GitHub地址:https://github.com/streamlit/streamlit/


          用 300 行 Python 代碼,編程一個可實時執行神經網絡推斷的語義搜索引擎。


          以我的經驗,每一個不平凡的機器學習項目都是用錯誤百出、難以維護的內部工具整合而成的。這些工具通常用 Jupyter Notebooks 和 Flask app 寫成,很難部署,需要對客戶端服務器架構(C/S 架構)進行推理,且無法與 Tensorflow GPU 會話等機器學習組件進行很好的整合。


          我第一次看到此類工具是在卡內基梅隆大學,之后又在伯克利、Google X、Zoox 看到。這些工具最初只是小的 Jupyter notebook:傳感器校準工具、仿真對比 app、激光雷達對齊 app、場景重現工具等。


          當一個工具越來越重要時,項目經理會介入其中:進程和需求不斷增加。這些單獨的項目變成代碼腳本,并逐漸發展成為冗長的「維護噩夢」……


          機器學習工程師創建 app 的流程(ad-hoc)。


          而當一個工具非常關鍵時,我們會組建工具團隊。他們熟練地寫 Vue 和 React,在筆記本電腦上貼滿聲明式框架的貼紙。他們的設計流程是這樣式的:



          工具團隊構建 app 的流程(干凈整潔,從零開始)。


          這簡直太棒了!但是所有這些工具都需要新功能,比如每周上線新功能。然而工具團隊可能同時支持 10 多個項目,他們會說:「我們會在兩個月內更新您的工具。」


          我們返回之前自行構建工具的流程:部署 Flask app,寫 HTML、CSS 和 JavaScript,嘗試對從 notebook 到樣式表的所有一些進行版本控制。我和在 Google X 工作的朋友 Thiago Teixeira 開始思考:如果構建工具像寫 Python 腳本一樣簡單呢?


          我們希望在沒有工具團隊的情況下,機器學習工程師也能構建不錯的 app。這些內部工具應該像機器學習工作流程的副產品那樣自然而然地出現。寫此類工具感覺就像訓練神經網絡或者在 Jupyter 中執行點對點分析(ad-hoc analysis)!同時,我們還想保留強大 app 框架的靈活性。我們想創造出令工程師驕傲的好工具。


          我們希望的 app 構建流程如下:



          Streamlit app 構建流程。


          與來自 Uber、Twitter、Stitch Fix、Dropbox 等的工程師一道,我們用一年時間創造了 Streamlit,這是一個針對機器學習工程師的免費開源 app 框架。不管對于任何原型,Streamlit 的核心原則都是更簡單、更純粹。


          Streamlit 的核心原則如下:


          1. 擁抱 Python


          Streamlit app 是完全自上而下運行的腳本,沒有隱藏狀態。你可以利用函數調用來處理代碼。只要你會寫 Python 腳本,你就可以寫 Streamlit app。例如,你可以按照以下代碼對屏幕執行寫入操作:

          import streamlit as stst.write('Hello, world!')
          

          2. 把 widget 視作變量


          Streamlit 中沒有 callback!每一次交互都只是自上而下重新運行腳本。該方法使得代碼非常干凈:

          import streamlit as stx = st.slider('x')
          st.write(x, 'squared is', x * x)
          

          3 行代碼寫成的 Streamlit 交互 app。


          3. 重用數據和計算


          如果要下載大量數據或執行復雜計算,怎么辦?關鍵在于在多次運行中安全地重用信息。Streamlit 引入了 cache primitive,它像一個持續的默認不可更改的數據存儲器,保障 Streamlit app 輕松安全地重用信息。例如,以下代碼只從 Udacity 自動駕駛項目(https://github.com/udacity/self-driving-car)中下載一次數據,就可得到一個簡單快速的 app:



          使用 st.cache,在 Streamlit 多次運行中保存數據。代碼運行說明,參見:https://gist.github.com/treuille/c633dc8bc86efaa98eb8abe76478aa81#gistcomment-3041475。



          運行以上 st.cache 示例的輸出。


          簡而言之,Streamlit 的工作流程如下:


          1. 每次用戶交互均需要從頭運行全部腳本。
          2. Streamlit 根據 widget 狀態為每個變量分配最新值。
          3. 緩存保證 Streamlit 重用數據和計算。


          如下圖所示:



          用戶事件觸發 Streamlit 從頭開始重新運行腳本。不同運行中僅保留緩存。


          感興趣的話,你可以立刻嘗試!只需運行以下行:


          網頁瀏覽器將自動打開,并轉向本地 Streamlit app。如果沒有出現瀏覽器窗口,只需點擊鏈接。


          這些想法很簡潔,但有效,使用 Streamlit 不會妨礙你創建豐富有用的 app。我在 Zoox 和 Google X 工作時,看著自動駕駛汽車項目發展成為數 G 的視覺數據,這些數據需要搜索和理解,包括在圖像數據上運行模型進而對比性能。我看到的每一個自動駕駛汽車項目都有整支團隊在做這方面的工具。


          在 Streamlit 中構建此類工具非常簡單。以下 Streamlit demo 可以對整個 Udacity 自動駕駛汽車照片數據集執行語義搜索,對人類標注的真值標簽進行可視化,并在 app 內實時運行完整的神經網絡(YOLO)。




          這個 300 行代碼寫成的 Streamlit demo 結合了語義視覺搜索和交互式神經網絡推斷。


          整個 app 只有 300 行 Python 代碼,其中大部分是機器學習代碼。事實上,整個 app 里只有 23 次 Streamlit 調用。你可以試試看:


          我們與機器學習團隊合作,為他們的項目而努力時,逐漸意識到這些簡單的想法會帶來大量重要的收益:


          Streamlit app 是純 Python 文件。你可以使用自己喜歡的編輯器和 debugger。



          我用 Streamlit 構建 app 時喜歡用 VSCode 編輯器(左)和 Chrome(右)。


          純 Python 代碼可與 Git 等源碼控制軟件無縫對接,包括 commits、pull requests、issues 和 comment。由于 Streamlit 的底層語言是 Python,因此你可以免費利用這些協作工具的好處。



          Streamlit app 是 Python 腳本,因此你可以使用 Git 輕松執行版本控制。


          Streamlit 提供即時模式的編程環境。當 Streamlit 檢測出源文件變更時,只需點擊 Always rerun 即可。



          點擊「Always rerun」,保證實時編程。


          緩存簡化計算流程。一連串緩存函數自動創建出高效的計算流程!你可以嘗試以下代碼:



          Streamlit 中的簡單計算流程。運行以上代碼,參見說明:https://gist.github.com/treuille/ac7755eb37c63a78fac7dfef89f3517e#gistcomment-3041436。


          基本上,該流程涉及加載元數據到創建摘要等步驟(load_metadata → create_summary)。該腳本每次運行時,Streamlit 僅需重新計算該流程的子集即可。



          為了保證 app 的可執行性,Streamlit 僅計算更新 UI 所必需的部分。


          Streamlit 適用于 GPU。Streamlit 可以直接訪問機器級原語(如 TensorFlow、PyTorch),并對這些庫進行補充。例如,以下 demo 中,Streamlit 的緩存存儲了整個英偉達 PGGAN。該方法可使用戶在更新左側滑塊時,app 執行近乎即時的推斷。




          該 Streamlit app 使用 TL-GAN 展示了英偉達 PGGAN 的效果。


          Streamlit 是免費開源庫,而非私有 web app。你可以本地部署 Streamlit app,不用提前聯系我們。你甚至可以在不聯網的情況下在筆記本電腦上本地運行 Streamlit。此外,現有項目也可以漸進地使用 Streamlit。



          漸進地使用 Streamlit 的幾種方式。


          以上只是 Streamlit 功能的冰山一角而已。它最令人興奮的一點是,這些原語可以輕松組成復雜 app,但看起來卻只是簡單腳本。這就要涉及架構運作原理和功能了,本文暫不談及。



          Streamlit 組件圖示。


          我們很高興與社區分享 Streamlit,希望它能夠幫助大家輕松將 Python 腳本轉化為美觀實用的機器學習 app。


          原文鏈接:https://towardsdatascience.com/coding-ml-tools-like-you-code-ml-models-ddba3357eace


          參考文獻:


          [1] J. Redmon and A. Farhadi, YOLOv3: An Incremental Improvement (2018), arXiv.

          [2] T. Karras, T. Aila, S. Laine, and J. Lehtinen, Progressive Growing of GANs for Improved Quality, Stability, and Variation (2018), ICLR.

          [3] S. Guan, Controlled image synthesis and editing using a novel TL-GAN model (2018), Insight Data Science Blog.


          主站蜘蛛池模板: 无码人妻精品一区二区三区在线| 欧洲精品一区二区三区在线观看| 国产精品日韩欧美一区二区三区 | 国产日韩AV免费无码一区二区| 无码少妇一区二区三区| 成人精品一区二区激情| 乱码精品一区二区三区 | 国产精品无码一区二区在线观| 精品一区二区三区在线观看| 精品人妻少妇一区二区三区不卡| 精品日产一区二区三区手机| 无码精品蜜桃一区二区三区WW| 加勒比无码一区二区三区| 任你躁国语自产一区在| 亚洲一区二区三区AV无码| 无码精品前田一区二区| 国产视频福利一区| 日本精品一区二区三本中文| 亚洲一区二区三区91| 一区二区三区观看免费中文视频在线播放 | 精品在线一区二区三区| 国产日本亚洲一区二区三区| 久久久久女教师免费一区| www亚洲精品少妇裸乳一区二区| 日韩一区在线视频| 精品乱码一区二区三区在线 | 丰满人妻一区二区三区视频| 免费萌白酱国产一区二区| 精品福利一区3d动漫| 一区二区三区四区视频在线| 一区三区三区不卡| 免费看一区二区三区四区| 亚洲韩国精品无码一区二区三区| 国产伦精品一区二区三区视频猫咪| 丰满岳妇乱一区二区三区| 国产AV午夜精品一区二区三| 亚洲AV综合色一区二区三区| 农村乱人伦一区二区| 无码国产精品一区二区免费I6| 性盈盈影院免费视频观看在线一区| 国产精品亚洲一区二区在线观看 |