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

Openresty的開發閉環初探

開發 開發工具
Nginx 作為現在使用最廣泛的高性能后端服務器,Openresty 為之提供了動態預言的靈活,當性能與靈活走在了一起,無疑對于被之前陷于臃腫架構,苦于提升性能的工程師來說是重大的利好消息。

1. 為什么值得入手?

Nginx 作為現在使用最廣泛的高性能后端服務器,Openresty 為之提供了動態預言的靈活,當性能與靈活走在了一起,無疑對于被之前陷于臃腫架構,苦于提升性能的工程師來說是重大的利好消息,本文就是在這種背景下,將初入這一未知的領域之后的一些經驗與大家分享一下,若有失言之處,歡迎指教。

Openresty的開發閉環初探

2. 安裝

現在除了能在 [Download](http://openresty.org/en/download.html )里面下載源碼來自己編譯安裝,現在連預編譯好的[包](http://openresty.org/en/linux-packages.html)都有了, 安裝也就分分鐘的事了。

3. hello world

/path/to/nginx.conf`, `conftent_by_lua_file 里面的路徑請根據 lua_package_path 調整一下。

  1. ``` 
  2.    location / { 
  3.        content_by_lua_file ../luablib/hello_world.lua; 
  4.    } 
  5.    ``` 
  6.  
  7. /path/to/openresty/lualib/hello_world.lua` 
  8.    ``` 
  9.    ngx.say("Hello World") 
  10.    ``` 

訪問一下, Hello World~.

  1. ``` 
  2.   HTTP/1.1 200 OK 
  3.   Connection: keep-alive 
  4.   Content-Type: application/octet-stream 
  5.   Date: Wed, 11 Jan 2017 07:52:15 GMT 
  6.   Server: openresty/1.11.2.2 
  7.   Transfer-Encoding: chunked 
  8.   Hello World 
  9.   ``` 

基本上早期的 Openresty 相關的開發的路數也就大抵如此了, 將 lua 庫發布到 lualib 之下,將對應的 nginx 的配置文件發布到 nginx/conf 底下,然后 reload 已有的 Openresty 進程(少數需要清空 Openresty shared_dict 數據的情況需要重啟 )。

如果是測試環境的話,那更是簡單了,在 http 段將 lua_code_cache 設為 off , Openresty 不會緩存 lua 腳本,每次執行都會去磁盤上讀取 lua 腳本文件的內容,發布之后就可以直接看效果了(當然如果配置文件修改了,reload 是免不了了)。是不是找到一點當初 apache 寫 php 的感覺呢:)

4. 開發語言 Lua 的大致介紹

環境搭建完畢之后,接下來就是各種試錯了。關于 Lua 的介紹,網上的資料比如:Openresty ***實踐(版本比較多,這里就不放了)寫的都會比較詳細,本文就不在這里過多解釋了,只展示部分基礎的Lua的模樣。

下面對 lua 一些個性有趣的地方做一下分享,可能不會涉及到 lua 語言比較全面或者細節的一些部分,作為補充,讀者可以翻閱官方的< >。

  1. ```lua 
  2.    -- 單行注釋以兩個連字符開頭 
  3.    --[[ 
  4. 行注釋 
  5.    --]] 
  6.    -- 變量賦值 
  7.    num = 13  -- 所有的數字都是雙精度浮點型。 
  8.    s = '單引號字符串' 
  9.    t = "也可以用雙引號" 
  10.    u = [[ 多行的字符串 
  11.           ]] 
  12.    -- 控制流程,和python最明顯的差別可能就是冒號變成了do, ***還得數end的對應 
  13.    -- while 
  14.    while n < 10 do 
  15.      nn = n + 1  -- 不支持 ++ 或 += 運算符。 
  16.    end 
  17.    -- for 
  18.    for i = 0, 9 do 
  19.      print(i) 
  20.    end 
  21.    -- if語句: 
  22.    f n == 0 then 
  23.      print("no hits") 
  24.    elseif n == 1 then 
  25.      print("one hit") 
  26.    else 
  27.      print(n .. " hits") 
  28.    end 
  29.    --只有nil和false為假; 0和 ''均為真! 
  30.    if not aBoolValue then print('false') end 
  31.    -- 循環的另一種結構: 
  32.    repeat 
  33.      print('the way of the future') 
  34.      numnum = num - 1 
  35.    until num == 0 
  36.    -- 函數定義: 
  37.    function add(x, y) 
  38.      return x + y 
  39.    end 
  40.    -- table 用作鍵值對 
  41.    t = {key1 = 'value1'key2 = false
  42.    print(t.key1)  -- 打印 'value1'. 
  43.    -- 使用任何非nil的值作為key: 
  44.    u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} 
  45.    print(u[6.28])  -- 打印 "tau" 
  46.    -- table用作列表、數組 
  47.    v = {'value1', 'value2', 1.21, 'gigawatts'} 
  48.    for i = 1, #v do  -- #v 是列表的大小 
  49.      print(v[i]) 
  50.    end 
  51.    -- 元表 
  52.    f1 = {a = 1b = 2}  -- 表示一個分數 a/b. 
  53.    f2 = {a = 2b = 3
  54.    -- 這會失敗: 
  55.    -- s = f1 + f2 
  56.    metafraction = {} 
  57.    function metafraction.__add(f1, f2) 
  58.      local sum = {} 
  59.      sum.b = f1.b * f2.b 
  60.      sum.a = f1.a * f2.b + f2.a * f1.b 
  61.      return sum 
  62.    end 
  63.    setmetatable(f1, metafraction) 
  64.    setmetatable(f2, metafraction) 
  65.    s = f1 + f2  -- 調用在f1的元表上的__add(f1, f2) 方法 
  66.    -- __index、__add等的值,被稱為元方法。 
  67.    -- 這里是一個table元方法的清單: 
  68.    -- __add(a, b)                     for a + b 
  69.    -- __sub(a, b)                     for a - b 
  70.    -- __mul(a, b)                     for a * b 
  71.    -- __div(a, b)                     for a / b 
  72.    -- __mod(a, b)                     for a % b 
  73.    -- __pow(a, b)                     for a ^ b 
  74.    -- __unm(a)                        for -a 
  75.    -- __concat(a, b)                  for a .. b 
  76.    -- __len(a)                        for #a 
  77.    -- __eq(a, b)                      for a == b 
  78.    -- __lt(a, b)                      for a < b 
  79.    -- __le(a, b)                      for a <= b 
  80.    -- __index(a, b)  <fn or a table>  for a.b 
  81.    -- __newindex(a, b, c)             for a.b = c 
  82.    -- __call(a, ...)                  for a(...) 
  83.    ``` 

以上參考了

[learn lua in y minute](https://learnxinyminutes.com/docs/zh-cn/lua-cn/ ) ,做了適當的裁剪來做說明。

4.1 Lua 語言個性的一面

4.1.1 ***道墻: 打印 table

作為 lua 里面唯一標準的數據結構, 直接打印居然只有一個 id 狀的東西,這里說這一點沒有抱怨的意思,只是讓讀者做好倒騰的心理準備,畢竟倒騰一個簡潔語言終歸是有代價的。

了解決定背后的原因,有時候比現成的一步到位的現成方案這也是倒騰的另一面好處吧,這里給出社區里面的[討論](http://luausers.org/wiki/TableSerialization)

舉個例子:

lua 里面一般使用 #table 來獲取 table 的長度,究其原因,lua 對于未定義的變量、table 的鍵,總是返回 nil,而不像 python 里面肯定是拋出異常, 所以 # 來計算 table 長度的時候只會遍歷到***個值為 nil 的地方,畢竟他不能一直嘗試下去,這時候就需要使用 table.maxn 的方式來獲取了。

4.1.2 Good or Bad ? 自動類型轉換

如果你在 python 里面去把一個字符串和數字相加,python 必定以異常回應。

  1. ```python 
  2. >>> "a" + 1 
  3. Traceback (most recent call last): 
  4.   File "<stdin>", line 1, in <module> 
  5. TypeError: cannot concatenate 'str' and 'int' objects 
  6. ``` 

但是 Lua 覺得他能搞定。

  1. ```lua 
  2. > = "20" + 10 
  3. 30 
  4. ``` 

如果你覺得 Lua 選擇轉換加號操作符的操作數成數字類型去進行求值顯得不可思議的,下面這種情況下,這種轉換又貌似是可以有點用的了 print("hello" .. 123) ,這時你不用手動去將所有參數手工轉換成字符串類型。

尚沒有定論說這項特性就是一無是處,但是這種依賴語言本身不明顯的特性的代碼筆者是不希望在項目里面去踩雷的。

4.1.3 多返回值

Lua 開始變得越來越與眾不同了:允許函數返回多個結果。

  1. ``` 
  2.     function foo0() end --無返回值 
  3.     function foo1() return 'a' end -- 返回一個結果 
  4.     function foo2() return 'a','b' end -- 返回兩個結果 
  5.     -- 多重賦值時, 函數調用是***一個表達式時 
  6.     -- 保留盡可能多的返回值 
  7.     x, y = foo2()     -- x='a'y='b' 
  8.     x = foo2()        -- x='a', 'b'被丟棄 
  9.     x,y,z = 10,foo2()    -- x=10y='a'z='b' 
  10.     -- 如果多重賦值時,函數調用不是***一個表達式時 
  11.     -- 只產生一個值 
  12.     x, y = foo2(),20   -- x='a'y=20    
  13.     x,y = foo0(), 20, 30 -- x=nily20,30被丟棄,這種情況當函數沒有返回值時,會用nil來補充。 
  14.     x,y,z = foo2() -- x='a'y='b'z=nil, 這種情況函數沒有足夠的返回值時也會用nil來補充。 
  15.     -- 同樣在函數調用、table聲明中 函數調用作為***的表達式,都會竟可能多的填充返回值,如果不是***,則只返回一個 
  16.     print(foo2(), 1)    --> a  1 
  17.     print(1, foo2())    --> 1  a  b 
  18.     t = {foo2(), 1}     --> {'a', 1} 
  19.     t = {1, foo2()}     --> {1, 'a', 'b'} 
  20.     -- 阻止這種參數順序搞事: 
  21.     print(1, (foo2())) -- 1 a 加一層括號,強制只返回一個值 
  22.     ``` 

4.1.4 真個性: 模式匹配

簡潔的 Lua 容不下行數比自己實現語言行數還多的正則表達式實現(無論是 POSIX ,還是 Perl 正則表達式),于是乎有了獨樹一幟的模式與匹配,下面只用模式匹配來做 URL 解碼、編碼功能實現的演示。

  1. ``` 
  2.   -- 解碼 
  3.   function unescape(s) 
  4.     s = string.gsub(s, "+", " ") 
  5.     s = string.gsub(s, "%%(%x%x)", function (h) 
  6.           return string.char(tonumber(h, 16)) 
  7.         end) 
  8.     return s   
  9.   end 
  10.   print(unescape("a%2Bb+%3D+c")) ---> a+b =c 
  11.   cgi = {} 
  12.   function decode(s) 
  13.     for name,value in string.gmatch(s, "([^&=]+)=([^&=]+)") do 
  14.       name = unescape(name) 
  15.       value = unescape(value) 
  16.       cgi[name] = value 
  17.     end 
  18.   end 
  19.   -- 編碼 
  20.   function escape(s) 
  21.     s = string.gsub(s, "[&=+%%%c]", function(c) 
  22.         return string.format("%%%02X", string.byte(c)) 
  23.       end) 
  24.     s = string.gsub(s, " ", "+") 
  25.     return s 
  26.   end   
  27.   function encode(t) 
  28.     local b = {} 
  29.     for k,v in pairs(t) do 
  30.       b[#b+1] = (escape(k) .. "=" .. escape(v)) 
  31.     end 
  32.     return table.concat(b,'&') 
  33.   end 
  34.   ``` 

模式匹配實現的功能是足夠強大,但是工程上是否值得投入還值得商榷,沒有通用性,只此 lua 一家用。

雖然正則表達式也是不好調試,但是至少知道了解的人多,可能到***筆者也不會多深入 lua 的模式匹配,但是如此單純為了減少代碼而放棄正則表達式現成的庫,自己又玩了一套,這也是沒誰了。

4.1.5 與 c 的天然親密

一言不合,就拿 c 寫一個庫給 lua 用,由此可見兩門語言是多么哥倆好了。如果舉個例子的話就是 lua5.1 里面的位操作符,luajit 就是這樣提供的解決方案 [Lua Bit Operations Module](http://bitop.luajit.org ),有興趣的讀者可以下載源碼看一下,完全就是用 lua 的 c api 包裝了 c 里面的位操作符出來用。

除了加了些限制的話(ex. 位移出來的必然是 32 位有符)。lua 除了數據結構上面的過于簡潔外,其他的控制結構、操作符這些語言特性基本該有的都有了,唯獨缺了位操作符。

5.1 為什么當時選擇了不實現位操作符呢?有知道出處或者原因的讀者歡迎留言告知。(順帶一提,lua5.2 里面有官方的 bit32 庫可以用,lua5.3 已經補上了位操作符,另外 Openresty 在 lua 版本的選擇上是選擇停留在 5.1,這點在 github 的 Issue 里面有回答過,且沒有升級的打算)。

4.1.6 雜

  • 只有 nil 、false 為布爾假。
  • lua 中的索引習慣以 1 開始。
  • 沒有整型,所有數字都是浮點數。
  • 當函數的參數是單引號或者雙引號的字符串或者 table 定義的時候,可以省略外面的 () , 所以 require "cookie" 并不是代表 require 是個關鍵字。
  • table[index] 等價于 table [index] 。

5. 構建公司層面完整的 Openresty 生態

5.1 開發助手:成長中的 resty 命令

習慣了動態語言的解釋器的立即反饋,哪怕是熟悉 lua 的同學,初入 Openresty 的時候似乎又想起了編譯->執行->修改的***循環的記憶,因為每次都需要修改配置文件、reload 、測試再如此重復個幾次才能寫對一段函數,resty 命令無疑期待,筆者也希望 resty 命令能夠更加完善、易用。

另外提一個小遺憾,現在 resty 命令不能玩 Openresty 里面的 shared_dict 共享內存, 這可能跟目前 resty 使用的 nginx 配置的模板是固定有關吧。

5.2 環境:可能不再需要重新編譯 Nginx

有過 Nginx 維護開發經驗的同學可能都熟悉這么一個過程,因為多半會做業務的拆分,除了小公司外,基本都不會把一個 Nginx 的所有可選模塊都編譯進去,每次有新的 Nginx 相關的功能的增減,都免不了重新編譯,重新部署上線。

Openresty 是基于 Nginx 的,如果是新增 Nginx 本身的功能,重新編譯增加功能沒什么好說的,如何優雅的更新 Nginx 服務進程,Nginx 有提供方案、各家也有各家的服務可靠性要求,具體怎么辦這里就不贅述了。

5.3 發布部署

Openresty 本身的發布部署跟 Nginx 本身沒有太大的不同,Openresty 本身的發布部署官方也推出了 linux 平臺的預編譯好的包,在這樣的基礎上構建環境就更加便捷。

環境之上,首先是 lua 腳本和 nginx 配置文件的發布,在版本管理之下,加上自動構建的發布平臺,Openresty 的應用分分鐘就可以上線了:)

這個流程本身無關 Openresty ,但是簡而言之一句話,當重復性的東西自動化之后,我們才有精力去解決更有趣的問題,不是么?

5.4 第三方庫的安裝、管理

(1)以前:自己找個第三方庫編譯之后扔到 Openresty 的 lualib 目錄,luajit 是否兼容、是否 lua5.1 兼容都得自己來測試一遍。

(2)之前:對于解決前一個問題,Openresty 是通過給出 lua 里面 Luarocks 的安裝使用來解決的,但是這種方式不能解決上面所說的第二個問題,所以現在這種方式已經不推薦使用了,下面貼一下官網的說明,只做內容收集、展示用, ***的具體說明參見[using luarocks](http://openresty.org/en/using-luarocks.html)。

  1. ``` 
  2. wget http://luarocks.org/releases/luarocks-2.0.13.tar.gz 
  3. tar -xzvf luarocks-2.0.13.tar.gz 
  4. cd luarocks-2.0.13/ 
  5. ./configure --prefix=/usr/local/openresty/luajit \ 
  6.     --with-lua=/usr/local/openresty/luajit/ \ 
  7.     --lua-suffix=jit \ 
  8.     --with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1 
  9. make 
  10. sudo make install 
  11. ``` 

安裝第三方庫示例:

  1. sudo /usr/local/openresty/luajit/luarocks install md5。 

(3)現在:Openresty 提供了解決這兩個問題的完整方案,自己的包管理的規范和倉庫[opm](https://opm.openresty.org/)。

詳細的標準說明, 請移步:https://github.com/openresty/opm#readme, 這里就不多做介紹了。

關于第三方庫的質量,Openresty 官網上也有了專門的[QA頁面](http://qa.openresty.org/),至少保證了第三方庫一些實現的下限,不像 python 里面安裝某些第三方包,比如 aerospike 的,里面安裝 python 客戶端,每次要去網上拉個 c 的客戶端下來之類的稀奇古怪的玩法,期待 opm 未來更加完善。

5.5 關于單元測試

關于自動化測試的話,就筆者的試用經驗而言,感覺還不是特別的順手,官方提供的 Test:Nginx 工具已經提供簡潔強大的功能,但是如果作為 TDD 開發中的測試驅動的工具而言,筆者覺得報錯信息的有效性上面可能是唯一讓人有點覺得有點捉雞的地方,尚不清楚是否是筆者用的有誤——

一般 Test:Nginx 的報錯多半無法幫助調試代碼,還是要走調試、修改的老路子。但是 Test:Nginx 的真正價值筆者覺得是講實例代碼和測試***的結合,由此養成了看每個 Openresty 相關的項目代碼都必先閱讀里面的 Test:Nginx 的測試,當然最多最豐富的還是 Openresty 本身的測試。

舉個實際的例子:

在使用 Test:Nginx 之前,之前對于 Nginx 的日志輸出,一切的測試依據,對于外面的運行環境跑的測試只能通過 http 的請求和返回來做測試的判斷條件,這時候對于一些情況就束手無策了, 比如處理某種錯誤情況可能需要在 log 里面記錄一下,這種測試就無法保證。

另外也有類似[lua-resty-test](https://github.com/membphis/lua-resty-test)這樣通過提供組件的方式來進行,但是我們一旦接觸的了 Test:Nginx 的測試方法之后,這些就顯得相形見絀了,我們舉個實際的例子。

  1. ``` 
  2.    # vim:set ftts=4 sw=4 et fdm=marker
  3.    use Test::Nginx::Socket::Lua; 
  4.    #worker_connections(1014); 
  5.    #master_process_enabled(1); 
  6.    #log_level('warn'); 
  7.    #repeat_each(2); 
  8.    plan tests => repeat_each() * (blocks() * 3 + 0); 
  9.    #no_diff(); 
  10.    no_long_string(); 
  11.    #master_on(); 
  12.    #workers(2); 
  13.    run_tests(); 
  14.    __DATA__ 
  15.    === TEST 1: lpush & lpop 
  16.    --- http_config 
  17.        lua_shared_dict dogs 1m; 
  18.    --- config 
  19.        location = /test { 
  20.            content_by_lua_block { 
  21.                local dogs = ngx.shared.dogs 
  22.                local len, err = dogs:lpush("foo", "bar") 
  23.                if len then 
  24.                    ngx.say("push success") 
  25.                else 
  26.                    ngx.say("push err: ", err) 
  27.                end 
  28.                local val, err = dogs:llen("foo") 
  29.                ngx.say(val, " ", err) 
  30.                local val, err = dogs:lpop("foo") 
  31.                ngx.say(val, " ", err) 
  32.                local val, err = dogs:llen("foo") 
  33.                ngx.say(val, " ", err) 
  34.                local val, err = dogs:lpop("foo") 
  35.                ngx.say(val, " ", err) 
  36.            } 
  37.        } 
  38.    --- request 
  39.    GET /test 
  40.    --- response_body 
  41.    push success 
  42.    1 nil 
  43.    bar nil 
  44.    0 nil 
  45.    nil nil 
  46.    --- no_error_log 
  47.    [error] 
  48.    ``` 

以上是隨便選取的lua-nginx-module的測試文件145-shdict-list.t中的一段做說明,測試文件分為3個部分:

  • __DATA__以上的部分編排測試如何運行,
  • __DATA__作為分隔符,
  • __DATA__以下的是各個測試的說明部分。

測試部分如果具體細分的話,

  • 一般由 ====TEST 1: name 開始到下一個測試的聲明;
  • 然后是配置 nginx 配置的 http_config、config、... 的部分;
  • 接著是模擬請求的部分,基本就是 http 請求報文的設定,功能不限于這里的 request 部分;
  • ***是輸出部分,這時候不僅是 http 報文的 body 部分之類的 http 響應、還有 nginx 的日志的輸出這樣的測試條件。

對于這樣清晰可讀、還能順帶把使用例子寫的清楚的單元測試的框架, pythoner 真的難道不羨慕么?

5.6 關于調試、性能調優

這一塊筆者還沒有深入研究過,所以這里就不多說了,這里就做一下相關知識的鏈接歸納,方便大家整理資料吧。lua 語言本身提供的調試就比較簡潔、加上 Openresty 是嵌入 Nginx 內部的,這就更給排查工作帶來了困難。

(1)[官方的調試頁面]

(http://openresty.org/en/debugging.html )

(2)[官方的性能調優頁面]

(http://openresty.org/en/profiling.html )

(3)[通過systemtap探查在線的Nginx work進程]

(https://github.com/agentzh/nginx-systemtap-toolkit)

(4)[額外的工具庫stap++]

(https://github.com/agentzh/stapxx )

(5)[工具火焰圖Flame Graphs的介紹]

(http://dtrace.org/blogs/brendan/2011/12/16/flame-graphs/ )

(6)[Linux Kernel Performance: Flame Graphs]

(http://dtrace.org/blogs/brendan/2012/03/17/linux-kernel-performance-flame-graphs/ )

【本文是51CTO專欄機構“豈安科技”的原創文章,轉載請通過微信公眾號(bigsec)聯系原作者】

戳這里,看該作者更多好文

責任編輯:趙寧寧 來源: 51CTO專欄
相關推薦

2011-06-16 10:25:29

AndroidAIR

2009-07-08 09:44:54

TDDViual Studi

2010-10-09 15:01:27

PhoneGapiPhoneAndroid

2012-03-16 13:43:29

2014-06-05 14:12:05

SwiftUI學習iOS

2024-06-05 09:22:43

2009-10-30 10:45:45

ScalaEclipseAndroid

2011-08-23 17:52:39

LUAWeb 開發

2016-08-23 14:37:21

2023-12-18 10:15:30

自動駕駛自然語言

2014-12-17 11:09:39

Hybrid AppWebView裝載頁面

2010-08-18 09:23:19

Flash Lite移動應用程序開發

2024-12-06 09:47:13

2010-08-03 10:32:42

Android 3.0Android 3.0Android開發

2016-11-28 09:19:27

2009-06-24 13:22:27

Glassfish

2010-06-03 12:57:06

Hadoop

2011-01-11 11:35:17

jQueryAndroidgoogle

2016-10-11 13:48:41

WebGLJavascriptWeb

2009-10-15 15:12:39

Equinox服務器端Equinox
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线免费观看黄网 | 紧缚调教一区二区三区视频 | 天天射网站 | 华人黄网站大全 | 蜜桃视频在线观看www社区 | 男女网站免费观看 | 午夜精品一区二区三区免费视频 | 天天玩夜夜操 | 日韩精品在线观看视频 | 国产高清一二三区 | 国产羞羞视频在线观看 | 国产欧美精品区一区二区三区 | 午夜视频网站 | 在线免费观看a级片 | 国产成人叼嘿视频在线观看 | 日韩免费三级 | 久久久妇女国产精品影视 | 欧美视频在线观看 | 欧美性久久 | 国产a级毛毛片 | 欧美一区二区三区的 | 久久精品欧美一区二区三区不卡 | av手机在线播放 | 精品一区二区三区在线视频 | 亚洲欧美日韩在线 | 久久毛片 | 免费在线一区二区 | 久久久久久久久久一区二区 | 国产精品成人69xxx免费视频 | 天天爽天天操 | 狠狠综合久久av一区二区老牛 | 91成人免费电影 | 成年人视频在线免费观看 | 国产三级| 精品亚洲一区二区三区四区五区高 | 91成人在线视频 | 性一交一乱一透一a级 | 国产欧美一区二区三区在线看蜜臀 | 日韩色视频 | 亚洲一区二区三区免费视频 | 97人人草|