欧美亚洲韩国_av电影院在线看_久久久久97_台湾佬中文娱乐网欧美电影

站長資訊網
最全最豐富的資訊網站

一文聊聊Node.js中的cluster(集群)

一文聊聊Node.js中的cluster(集群)

日常工作中,對 Node.js 的使用都比較粗淺,趁未羊之際,來學點稍微高級的,那就先從 cluster 開始吧。

尼古拉斯張三說過,“帶著問題去學習是一個比較好的方法”,所以我們也來試一試。

當初使用 cluster 時,一直好奇它是怎么做到多個子進程監聽同一個端口而不沖突的,比如下面這段代碼:

const cluster = require('cluster') const net = require('net') const cpus = require('os').cpus()  if (cluster.isPrimary) {   for (let i = 0; i < cpus.length; i++) {     cluster.fork()   } } else {   net     .createServer(function (socket) {       socket.on('data', function (data) {         socket.write(`Reply from ${process.pid}: ` + data.toString())       })       socket.on('end', function () {         console.log('Close')       })       socket.write('Hello!n')     })     .listen(9999) }
登錄后復制

該段代碼通過父進程 fork 出了多個子進程,且這些子進程都監聽了 9999 這個端口并能正常提供服務,這是如何做到的呢?我們來研究一下。【相關教程推薦:nodejs視頻教程、編程教學】

準備調試環境

學習 Node.js 官方提供庫最好的方式當然是調試一下,所以,我們先來準備一下環境。注:本文的操作系統為 macOS Big Sur 11.6.6,其他系統請自行準備相應環境。

編譯 Node.js

  • 下載 Node.js 源碼

git clone https://github.com/nodejs/node.git
登錄后復制

然后在下面這兩個地方加入斷點,方便后面調試用:

// lib/internal/cluster/primary.js function queryServer(worker, message) {   debugger;   // Stop processing if worker already disconnecting   if (worker.exitedAfterDisconnect) return;    ... }
登錄后復制

// lib/internal/cluster/child.js send(message, (reply, handle) => {   debugger   if (typeof obj._setServerData === 'function') obj._setServerData(reply.data)    if (handle) {     // Shared listen socket     shared(reply, {handle, indexesKey, index}, cb)   } else {     // Round-robin.     rr(reply, {indexesKey, index}, cb)   } })
登錄后復制

  • 進入目錄,執行

./configure --debug make -j4
登錄后復制

之后會生成 out/Debug/node

準備 IDE 環境

使用 vscode 調試,配置好 launch.json 就可以了(其他 IDE 類似,請自行解決):

{   "version": "0.2.0",   "configurations": [     {       "name": "Debug C++",       "type": "cppdbg",       "program": "/Users/youxingzhi/ayou/node/out/Debug/node",       "request": "launch",       "args": ["/Users/youxingzhi/ayou/node/index.js"],       "stopAtEntry": false,       "cwd": "${workspaceFolder}",       "environment": [],       "externalConsole": false,       "MIMode": "lldb"     },     {       "name": "Debug Node",       "type": "node",       "runtimeExecutable": "/Users/youxingzhi/ayou/node/out/Debug/node",       "request": "launch",       "args": ["--expose-internals", "--nolazy"],       "skipFiles": [],       "program": "${workspaceFolder}/index.js"     }   ] }
登錄后復制

其中第一個是用于調式 C++ 代碼(需要安裝 C/C++ 插件),第二個用于調式 JS 代碼。接下來就可以開始調試了,我們暫時用調式 JS 代碼的那個配置就好了。

Cluster 源碼調試

準備好調試代碼(為了調試而已,這里啟動一個子進程就夠了):

debugger const cluster = require('cluster') const net = require('net')  if (cluster.isPrimary) {   debugger   cluster.fork() } else {   const server = net.createServer(function (socket) {     socket.on('data', function (data) {       socket.write(`Reply from ${process.pid}: ` + data.toString())     })     socket.on('end', function () {       console.log('Close')     })     socket.write('Hello!n')   })   debugger   server.listen(9999) }
登錄后復制

很明顯,我們的程序可以分父進程和子進程這兩部分來進行分析。

首先進入的是父進程:

執行 require('cluster') 時,會進入 lib/cluster.js 這個文件:

const childOrPrimary = 'NODE_UNIQUE_ID' in process.env ? 'child' : 'primary' module.exports = require(`internal/cluster/${childOrPrimary}`)
登錄后復制

會根據當前 process.env 上是否有 NODE_UNIQUE_ID 來引入不同的模塊,此時是沒有的,所以會引入 internal/cluster/primary.js 這個模塊:

... const cluster = new EventEmitter(); ... module.exports = cluster  const handles = new SafeMap() cluster.isWorker = false cluster.isMaster = true // Deprecated alias. Must be same as isPrimary. cluster.isPrimary = true cluster.Worker = Worker cluster.workers = {} cluster.settings = {} cluster.SCHED_NONE = SCHED_NONE // Leave it to the operating system. cluster.SCHED_RR = SCHED_RR // Primary distributes connections. ... cluster.schedulingPolicy = schedulingPolicy  cluster.setupPrimary = function (options) { ... }  // Deprecated alias must be same as setupPrimary cluster.setupMaster = cluster.setupPrimary  function setupSettingsNT(settings) { ... }  function createWorkerProcess(id, env) {   ... }  function removeWorker(worker) {  ... }  function removeHandlesForWorker(worker) {  ... }  cluster.fork = function (env) {   ... }
登錄后復制

該模塊主要是在 cluster 對象上掛載了一些屬性和方法,并導出,這些后面回過頭再看,我們繼續往下調試。往下調試會進入 if (cluster.isPrimary) 分支,代碼很簡單,僅僅是 fork 出了一個新的子進程而已:

// lib/internal/cluster/primary.js cluster.fork = function (env) {   cluster.setupPrimary()   const id = ++ids   const workerProcess = createWorkerProcess(id, env)   const worker = new Worker({     id: id,     process: workerProcess,   })    ...    worker.process.on('internalMessage', internal(worker, onmessage))   process.nextTick(emitForkNT, worker)   cluster.workers[worker.id] = worker   return worker }
登錄后復制

cluster.setupPrimary():比較簡單,初始化一些參數啥的。

createWorkerProcess(id, env)

// lib/internal/cluster/primary.js function createWorkerProcess(id, env) {   const workerEnv = {...process.env, ...env, NODE_UNIQUE_ID: `${id}`}   const execArgv = [...cluster.settings.execArgv]    ...    return fork(cluster.settings.exec, cluster.settings.args, {     cwd: cluster.settings.cwd,     env: workerEnv,     serialization: cluster.settings.serialization,     silent: cluster.settings.silent,     windowsHide: cluster.settings.windowsHide,     execArgv: execArgv,     stdio: cluster.settings.stdio,     gid: cluster.settings.gid,     uid: cluster.settings.uid,   }) }
登錄后復制

可以看到,該方法主要是通過 fork 啟動了一個子進程來執行我們的 index.js,且啟動子進程的時候設置了環境變量 NODE_UNIQUE_ID,這樣 index.jsrequire('cluster') 的時候,引入的就是 internal/cluster/child.js 模塊了。

worker.process.on('internalMessage', internal(worker, onmessage)):監聽子進程傳遞過來的消息并處理。

接下來就進入了子進程的邏輯:

前面說了,此時引入的是 internal/cluster/child.js 模塊,我們先跳過,繼續往下,執行 server.listen(9999) 時實際上是調用了 Server 上的方法:

// lib/net.js Server.prototype.listen = function (...args) {   ...       listenInCluster(         this,         null,         options.port | 0,         4,         backlog,         undefined,         options.exclusive       ); }
登錄后復制

可以看到,最終是調用了 listenInCluster

// lib/net.js function listenInCluster(   server,   address,   port,   addressType,   backlog,   fd,   exclusive,   flags,   options ) {   exclusive = !!exclusive    if (cluster === undefined) cluster = require('cluster')    if (cluster.isPrimary || exclusive) {     // Will create a new handle     // _listen2 sets up the listened handle, it is still named like this     // to avoid breaking code that wraps this method     server._listen2(address, port, addressType, backlog, fd, flags)     return   }    const serverQuery = {     address: address,     port: port,     addressType: addressType,     fd: fd,     flags,     backlog,     ...options,   }   // Get the primary's server handle, and listen on it   cluster._getServer(server, serverQuery, listenOnPrimaryHandle)    function listenOnPrimaryHandle(err, handle) {     err = checkBindError(err, port, handle)      if (err) {       const ex = exceptionWithHostPort(err, 'bind', address, port)       return server.emit('error', ex)     }      // Reuse primary's server handle     server._handle = handle     // _listen2 sets up the listened handle, it is still named like this     // to avoid breaking code that wraps this method     server._listen2(address, port, addressType, backlog, fd, flags)   } }
登錄后復制

由于是在子進程中執行,所以最后會調用 cluster._getServer(server, serverQuery, listenOnPrimaryHandle)

// lib/internal/cluster/child.js // 這里的 cb 就是上面的 listenOnPrimaryHandle cluster._getServer = function (obj, options, cb) {   ...   send(message, (reply, handle) => {     debugger     if (typeof obj._setServerData === 'function') obj._setServerData(reply.data)      if (handle) {       // Shared listen socket       shared(reply, {handle, indexesKey, index}, cb)     } else {       // Round-robin.       rr(reply, {indexesKey, index}, cb)     }   })    ... }
登錄后復制

該函數最終會向父進程發送 queryServer 的消息,父進程處理完后會調用回調函數,回調函數中會調用 cblistenOnPrimaryHandle。看來,listen 的邏輯是在父進程中進行的了。

接下來進入父進程:

父進程收到 queryServer 的消息后,最終會調用 queryServer 這個方法:

// lib/internal/cluster/primary.js function queryServer(worker, message) {   // Stop processing if worker already disconnecting   if (worker.exitedAfterDisconnect) return    const key =     `${message.address}:${message.port}:${message.addressType}:` +     `${message.fd}:${message.index}`   let handle = handles.get(key)    if (handle === undefined) {     let address = message.address      // Find shortest path for unix sockets because of the ~100 byte limit     if (       message.port < 0 &&       typeof address === 'string' &&       process.platform !== 'win32'     ) {       address = path.relative(process.cwd(), address)        if (message.address.length < address.length) address = message.address     }      // UDP is exempt from round-robin connection balancing for what should     // be obvious reasons: it's connectionless. There is nothing to send to     // the workers except raw datagrams and that's pointless.     if (       schedulingPolicy !== SCHED_RR ||       message.addressType === 'udp4' ||       message.addressType === 'udp6'     ) {       handle = new SharedHandle(key, address, message)     } else {       handle = new RoundRobinHandle(key, address, message)     }      handles.set(key, handle)   }    ... }
登錄后復制

可以看到,這里主要是對 handle 的處理,這里的 handle 指的是調度策略,分為 SharedHandleRoundRobinHandle,分別對應搶占式和輪詢兩種策略(文章最后補充部分有關于兩者對比的例子)。

Node.js 中默認是 RoundRobinHandle 策略,可通過環境變量 NODE_CLUSTER_SCHED_POLICY 來修改,取值可以為 noneSharedHandle) 或 rrRoundRobinHandle)。

SharedHandle

首先,我們來看一下 SharedHandle,由于我們這里是 TCP 協議,所以最后會通過 net._createServerHandle 創建一個 TCP 對象掛載在 handle 屬性上(注意這里又有一個 handle,別搞混了):

// lib/internal/cluster/shared_handle.js function SharedHandle(key, address, {port, addressType, fd, flags}) {   this.key = key   this.workers = new SafeMap()   this.handle = null   this.errno = 0    let rval   if (addressType === 'udp4' || addressType === 'udp6')     rval = dgram._createSocketHandle(address, port, addressType, fd, flags)   else rval = net._createServerHandle(address, port, addressType, fd, flags)    if (typeof rval === 'number') this.errno = rval   else this.handle = rval }
登錄后復制

createServerHandle 中除了創建 TCP 對象外,還綁定了端口和地址:

// lib/net.js function createServerHandle(address, port, addressType, fd, flags) {   ...   } else {     handle = new TCP(TCPConstants.SERVER);     isTCP = true;   }    if (address || port || isTCP) {       ...       err = handle.bind6(address, port, flags);     } else {       err = handle.bind(address, port);     }   }    ...   return handle; }
登錄后復制

然后,queryServer 中繼續執行,會調用 add 方法,最終會將 handle 也就是 TCP 對象傳遞給子進程:

// lib/internal/cluster/primary.js function queryServer(worker, message) {   ...   if (!handle.data) handle.data = message.data    // Set custom server data   handle.add(worker, (errno, reply, handle) => {     const {data} = handles.get(key)      if (errno) handles.delete(key) // Gives other workers a chance to retry.      send(       worker,       {         errno,         key,         ack: message.seq,         data,         ...reply,       },       handle // TCP 對象     )   })   ... }
登錄后復制

之后進入子進程:

子進程收到父進程對于 queryServer 的回復后,會調用 shared

// lib/internal/cluster/child.js // `obj` is a net#Server or a dgram#Socket object. cluster._getServer = function (obj, options, cb) {   ...    send(message, (reply, handle) => {     if (typeof obj._setServerData === 'function') obj._setServerData(reply.data)      if (handle) {       // Shared listen socket       shared(reply, {handle, indexesKey, index}, cb)     } else {       // Round-robin.       rr(reply, {indexesKey, index}, cb) // cb 是 listenOnPrimaryHandle     }   })   ... }
登錄后復制

登錄后復制

shared 中最后會調用 cb 也就是 listenOnPrimaryHandle

// lib/net.js function listenOnPrimaryHandle(err, handle) {   err = checkBindError(err, port, handle)    if (err) {     const ex = exceptionWithHostPort(err, 'bind', address, port)     return server.emit('error', ex)   }   // Reuse primary's server handle 這里的 server 是 index.js 中 net.createServer 返回的那個對象   server._handle = handle   // _listen2 sets up the listened handle, it is still named like this   // to avoid breaking code that wraps this method   server._listen2(address, port, addressType, backlog, fd, flags) }
登錄后復制

這里會把 handle 賦值給 server._handle,這里的 serverindex.jsnet.createServer 返回的那個對象,并調用 server._listen2,也就是 setupListenHandle

// lib/net.js function setupListenHandle(address, port, addressType, backlog, fd, flags) {   debug('setupListenHandle', address, port, addressType, backlog, fd)   // If there is not yet a handle, we need to create one and bind.   // In the case of a server sent via IPC, we don't need to do this.   if (this._handle) {     debug('setupListenHandle: have a handle already')   } else {     ...   }    this[async_id_symbol] = getNewAsyncId(this._handle)   this._handle.onconnection = onconnection   this._handle[owner_symbol] = this    // Use a backlog of 512 entries. We pass 511 to the listen() call because   // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);   // which will thus give us a backlog of 512 entries.   const err = this._handle.listen(backlog || 511)    if (err) {     const ex = uvExceptionWithHostPort(err, 'listen', address, port)     this._handle.close()     this._handle = null     defaultTriggerAsyncIdScope(       this[async_id_symbol],       process.nextTick,       emitErrorNT,       this,       ex     )     return   } }
登錄后復制

首先會執行 this._handle.onconnection = onconnection,由于客戶端請求過來時會調用 this._handle(也就是 TCP 對象)上的 onconnection 方法,也就是會執行lib/net.js 中的 onconnection 方法建立連接,之后就可以通信了。為了控制篇幅,該方法就不繼續往下了。

然后調用 listen 監聽,注意這里參數 backlog 跟之前不同,不是表示端口,而是表示在拒絕連接之前,操作系統可以掛起的最大連接數量,也就是連接請求的排隊數量。我們平時遇到的 listen EADDRINUSE: address already in use 錯誤就是因為這行代碼返回了非 0 的錯誤。

如果還有其他子進程,也會同樣走一遍上述的步驟,不同之處是在主進程中 queryServer 時,由于已經有 handle 了,不需要再重新創建了:

function queryServer(worker, message) {   debugger;   // Stop processing if worker already disconnecting   if (worker.exitedAfterDisconnect) return;    const key =     `${message.address}:${message.port}:${message.addressType}:` +     `${message.fd}:${message.index}`;   let handle = handles.get(key);   ... }
登錄后復制

以上內容整理成流程圖如下:

一文聊聊Node.js中的cluster(集群)

所謂的 SharedHandle,其實是在多個子進程中共享 TCP 對象的句柄,當客戶端請求過來時,多個進程會去競爭該請求的處理權,會導致任務分配不均的問題,這也是為什么需要 RoundRobinHandle 的原因。接下來繼續看看這種調度方式。

RoundRobinHandle

// lib/internal/cluster/round_robin_handle.js function RoundRobinHandle(   key,   address,   {port, fd, flags, backlog, readableAll, writableAll} ) {   ...   this.server = net.createServer(assert.fail)    ...   else if (port >= 0) {     this.server.listen({       port,       host: address,       // Currently, net module only supports `ipv6Only` option in `flags`.       ipv6Only: Boolean(flags & constants.UV_TCP_IPV6ONLY),       backlog,     })   }   ...   this.server.once('listening', () => {     this.handle = this.server._handle     this.handle.onconnection = (err, handle) => {       this.distribute(err, handle)     }     this.server._handle = null     this.server = null   }) }
登錄后復制

如上所示,RoundRobinHandle 會調用 net.createServer() 創建一個 server,然后調用 listen 方法,最終會來到 setupListenHandle

// lib/net.js function setupListenHandle(address, port, addressType, backlog, fd, flags) {   debug('setupListenHandle', address, port, addressType, backlog, fd)   // If there is not yet a handle, we need to create one and bind.   // In the case of a server sent via IPC, we don't need to do this.   if (this._handle) {     debug('setupListenHandle: have a handle already')   } else {     debug('setupListenHandle: create a handle')      let rval = null      // Try to bind to the unspecified IPv6 address, see if IPv6 is available     if (!address && typeof fd !== 'number') {       rval = createServerHandle(DEFAULT_IPV6_ADDR, port, 6, fd, flags)        if (typeof rval === 'number') {         rval = null         address = DEFAULT_IPV4_ADDR         addressType = 4       } else {         address = DEFAULT_IPV6_ADDR         addressType = 6       }     }      if (rval === null)       rval = createServerHandle(address, port, addressType, fd, flags)      if (typeof rval === 'number') {       const error = uvExceptionWithHostPort(rval, 'listen', address, port)       process.nextTick(emitErrorNT, this, error)       return     }     this._handle = rval   }    this[async_id_symbol] = getNewAsyncId(this._handle)   this._handle.onconnection = onconnection   this._handle[owner_symbol] = this    ... }
登錄后復制

且由于此時 this._handle 為空,會調用 createServerHandle() 生成一個 TCP 對象作為 _handle。之后就跟 SharedHandle 一樣了,最后也會回到子進程:

// lib/internal/cluster/child.js // `obj` is a net#Server or a dgram#Socket object. cluster._getServer = function (obj, options, cb) {   ...    send(message, (reply, handle) => {     if (typeof obj._setServerData === 'function') obj._setServerData(reply.data)      if (handle) {       // Shared listen socket       shared(reply, {handle, indexesKey, index}, cb)     } else {       // Round-robin.       rr(reply, {indexesKey, index}, cb) // cb 是 listenOnPrimaryHandle     }   })   ... }
登錄后復制

登錄后復制

不過由于 RoundRobinHandle 不會傳遞 handle 給子進程,所以此時會執行 rr

function rr(message, {indexesKey, index}, cb) {   ...   // Faux handle. Mimics a TCPWrap with just enough fidelity to get away   // with it. Fools net.Server into thinking that it's backed by a real   // handle. Use a noop function for ref() and unref() because the control   // channel is going to keep the worker alive anyway.   const handle = {close, listen, ref: noop, unref: noop}    if (message.sockname) {     handle.getsockname = getsockname // TCP handles only.   }    assert(handles.has(key) === false)   handles.set(key, handle)   debugger   cb(0, handle) }
登錄后復制

可以看到,這里構造了一個假的 handle,然后執行 cb 也就是 listenOnPrimaryHandle。最終跟 SharedHandle 一樣會調用 setupListenHandle 執行 this._handle.onconnection = onconnection

RoundRobinHandle 邏輯到此就結束了,好像缺了點什么的樣子。回顧下,我們給每個子進程中的 server 上都掛載了一個假的 handle,但它跟綁定了端口的 TCP 對象沒有任何關系,如果客戶端請求過來了,是不會執行它上面的 onconnection 方法的。之所以要這樣寫,估計是為了保持跟之前 SharedHandle 代碼邏輯的統一。

此時,我們需要回到 RoundRobinHandle,有這樣一段代碼:

// lib/internal/cluster/round_robin_handle.js this.server.once('listening', () => {   this.handle = this.server._handle   this.handle.onconnection = (err, handle) => {     this.distribute(err, handle)   }   this.server._handle = null   this.server = null })
登錄后復制

listen 執行完后,會觸發 listening 事件的回調,這里重寫了 handle 上面的 onconnection

所以,當客戶端請求過來時,會調用 distribute 在多個子進程中輪詢分發,這里又有一個 handle,這里的 handle 姑且理解為 clientHandle,即客戶端連接的 handle,別搞混了。總之,最后會將這個 clientHandle 發送給子進程:

// lib/internal/cluster/round_robin_handle.js RoundRobinHandle.prototype.handoff = function (worker) {   ...    const message = { act: 'newconn', key: this.key };   // 這里的 handle 是 clientHandle   sendHelper(worker.process, message, handle, (reply) => {     if (reply.accepted) handle.close();     else this.distribute(0, handle); // Worker is shutting down. Send to another.      this.handoff(worker);   }); };
登錄后復制

而子進程在 require('cluster') 時,已經監聽了該事件:

// lib/internal/cluster/child.js process.on('internalMessage', internal(worker, onmessage)) send({act: 'online'})  function onmessage(message, handle) {   if (message.act === 'newconn') onconnection(message, handle)   else if (message.act === 'disconnect')     ReflectApply(_disconnect, worker, [true]) }
登錄后復制

最終也同樣會走到 net.js 中的 function onconnection(err, clientHandle) 方法。這個方法第二個參數名就叫 clientHandle,這也是為什么前面的 handle 我想叫這個名字的原因。

還是用圖來總結下:

一文聊聊Node.js中的cluster(集群)

SharedHandle 不同的是,該調度策略中 onconnection 最開始是在主進程中觸發的,然后通過輪詢算法挑選一個子進程,將 clientHandle 傳遞給它。

為什么端口不沖突

cluster 模塊的調試就到此告一段落了,接下來我們來回答一下一開始的問題,為什么多個進程監聽同一個端口沒有報錯?

網上有些文章說是因為設置了 SO_REUSEADDR,但其實跟這個沒關系。通過上面的分析知道,不管什么調度策略,最終都只會在主進程中對 TCP 對象 bind 一次。

我們可以修改一下源代碼來測試一下:

// deps/uv/src/unix/tcp.c 下面的 SO_REUSEADDR 改成 SO_DEBUG if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
登錄后復制

編譯后執行發現,我們仍然可以正常使用 cluster 模塊。

那這個 SO_REUSEADDR 到底影響的是啥呢?我們繼續來研究一下。

SO_REUSEADDR

首先,我們我們知道,下面的代碼是會報錯的:

const net = require('net') const server1 = net.createServer() const server2 = net.createServer() server1.listen(9999) server2.listen(9999)
登錄后復制

但是,如果我稍微修改一下,就不會報錯了:

const net = require('net') const server1 = net.createServer() const server2 = net.createServer() server1.listen(9999, '127.0.0.1') server2.listen(9999, '10.53.48.67')
登錄后復制

原因在于 listen 時,如果不指定 address,則相當于綁定了所有地址,當兩個 server 都這樣做時,請求到來就不知道要給誰處理了。

我們可以類比成找對象,port 是對外貌的要求,address 是對城市的要求。現在甲乙都想要一個 port1米7以上 不限城市的對象,那如果有一個 1米7以上 來自 深圳 的對象,就不知道介紹給誰了。而如果兩者都指定了城市就好辦多了。

那如果一個指定了 address,一個沒有呢?就像下面這樣:

const net = require('net') const server1 = net.createServer() const server2 = net.createServer() server1.listen(9999, '127.0.0.1') server2.listen(9999)
登錄后復制

結果是:設置了 SO_REUSEADDR 可以正常運行,而修改成 SO_DEBUG 的會報錯。

還是上面的例子,甲對城市沒有限制,乙需要是來自 深圳 的,那當一個對象來自 深圳,我們可以選擇優先介紹給乙,非 深圳 的就選擇介紹給甲,這個就是 SO_REUSEADDR 的作用。

補充

SharedHandleRoundRobinHandle 兩種模式的對比

先準備下測試代碼:

// cluster.js const cluster = require('cluster') const net = require('net')  if (cluster.isMaster) {   for (let i = 0; i < 4; i++) {     cluster.fork()   } } else {   const server = net.createServer()   server.on('connection', (socket) => {     console.log(`PID: ${process.pid}!`)   })   server.listen(9997) }
登錄后復制

// client.js const net = require('net') for (let i = 0; i < 20; i++) {   net.connect({port: 9997}) }
登錄后復制

RoundRobin先執行 node cluster.js,然后執行 node client.js,會看到如下輸出,可以看到沒有任何一個進程的 PID 是緊挨著的。至于為什么沒有一直按照一樣的順序,后面再研究一下。

PID: 42904! PID: 42906! PID: 42905! PID: 42904! PID: 42907! PID: 42905! PID: 42906! PID: 42907! PID: 42904! PID: 42905! PID: 42906! PID: 42907! PID: 42904! PID: 42905! PID: 42906! PID: 42907! PID: 42904! PID: 42905! PID: 42906! PID: 42904!
登錄后復制

Shared

先執行 NODE_CLUSTER_SCHED_POLICY=none node cluster.js,則 Node.js 會使用 SharedHandle,然后執行 node client.js,會看到如下輸出,可以看到同一個 PID 連續輸出了多次,所以這種策略會導致進程任務分配不均的現象。就像公司里有些人忙到 996,有些人天天摸魚,這顯然不是老板愿意看到的現象,所以不推薦使用。

PID: 42561! PID: 42562! PID: 42561! PID: 42562! PID: 42564! PID: 42561! PID: 42562! PID: 42563! PID: 42561! PID: 42562! PID: 42563! PID: 42564! PID: 42564! PID: 42564! PID: 42564! PID: 42564! PID: 42563! PID: 42563! PID: 42564! PID: 42563!
登錄后復制

贊(0)
分享到: 更多 (0)
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
主站蜘蛛池模板: 国产精品欧美亚洲 | 亚洲蜜桃av一区二区 | 中文字幕精品在线 | 免费观看av毛片 | 欧美激情视频在线观看 | 成人自拍网站 | 国产又粗又猛又爽又黄的 | 亚洲欧美日韩免费 | 亚洲美女视频在线观看 | 亚洲天堂美女视频 | 欧美一区二区在线观看 | 66m—66摸成人免费视频 | 日韩av有码| 高h乱l高辣h文短篇h | 亚洲一区二区三区在线播放 | 欧美激情午夜 | 91视频网址入口 | 草操网 | 一级欧美一级日韩片 | 国产色片在线观看 | 欧洲亚洲视频 | 亚洲深夜| 亚洲男人的天堂在线 | 性生活三级视频 | 在线黄av | 六月综合网 | 瑟瑟视频在线免费观看 | 亚洲精品视频在线观看视频 | 国产精品国产三级国产a | 中年夫妇大白天啪啪高潮不断 | 国产做a视频 | 亚洲视频欧美视频 | 色综合天天网 | 黑人与日本少妇高潮 | 欧美第一视频 | 亚洲狠| 国产伦精品一区二区三区视频孕妇 | 国产精品午夜在线 | 中文字幕av中文字幕 | 亚洲性片 | 91成人在线观看高潮 | 自拍愉拍 | 欧美久久成人 | 亚洲天堂一区二区 | 国模三级 | 久久精品这里有 | 国产亚洲精品久久久久四川人 | 欧美精品一区二区在线播放 | 免费的理伦片在线播放 | 日韩视频免费在线 | 黄色片视频在线观看免费 | 成年人免费黄色 | 中文字幕在线视频观看 | 国产20页 | 伊人网综合在线 | 国产成人精品av久久 | 亚洲国产免费av | 波多野结衣 一区 | 黑丝袜av| 毛片在线网址 | 国产精品久久久久久69 | 国产成人精品一区二区三区在线 | 黄色高清在线观看 | 日韩黄 | 日本一区二区三区在线观看视频 | 特级淫片裸体免费看 | 亚洲免费婷婷 | 亚洲日本韩国在线 | 午夜一本 | a天堂在线观看 | 嫩草视频在线免费观看 | 国产精品3区| 久久狠狠高潮亚洲精品 | 蜜臀久久99精品久久久久久宅男 | 亚洲最大福利视频网 | 精品国产一区二区三区久久久蜜月 | 九九精品免费视频 | 亚洲激情视频在线观看 | 女同性做爰全过程 | 国产成人免费在线视频 | 中文字幕在线观看一区 | 欧美日韩一区二区三区四区 | 亚洲视频国产一区 | 97超视频在线观看 | 加勒比精品在线 | 精品在线视频免费 | 91视频免费观看网站 | 精品一区中文字幕 | 一区二区中文字幕 | 深爱激情综合网 | 免费久久| 日本免费一区视频 | 亚洲一区二区少妇 | 最新中文字幕一区 | 99国产精品一区二区三区 | 永久免费看mv网站入口亚洲 | 欧美片17c07.com | 久久九九视频 | 黄色私人影院 | 国产女人爽到高潮a毛片 | 国产三级精品视频 | 久热精品在线观看 | 综合激情婷婷 | 色网址在线 | www插插| 亚洲va韩国va欧美va精品 | 国产观看| 亚洲国产精品99久久久久久久久 | 国产成人av网站 | 奇米四色影视 | 国产啊啊啊啊 | 国产专区一区二区 | 国产激情亚洲 | 丁香婷婷网 | √天堂资源地址在线官网 | 黄色av免费 | 亚洲国产精品久久久久爰性色 | 91麻豆产精品久久久久久夏晴子 | 国产不卡在线 | 国产98在线| 高h喷水荡肉少妇爽多p视频 | 日韩精品中文字幕一区二区三区 | 日韩一区二区中文字幕 | 91精品国产综合久久久密臀九色 | 高清免费视频日本 | 亚洲污片| 国产在线观看精品 | 亚洲春色网 | 69影院少妇在线观看 | 99视屏 | 国内成人精品2018免费看 | 精彩视频一区二区 | 日韩社区| 国产调教 | 福利一区视频 | 久久午夜鲁丝片午夜精品 | 国产精品久久不卡 | 日本在线观看免费 | 国产123| 久久久男人的天堂 | 91精品国产亚洲 | 天堂婷婷 | 中文字幕――色哟哟 | 亚洲黄在线 | 一级二级三级视频 | 国产精品成人久久 | 国产一级aa大片毛片 | 一区二区三高清 | 国产精品第72页 | 天天射天天爽 | 亚洲最大福利视频网 | 在线播放国产一区 | 久久国内视频 | 女同亚洲精品一区二区三 | 操干网 | 麻豆久久99久久精品 | 日韩av一区二区三区在线观看 | 99久久精品一区二区三区 | www.久久.com | 欧美日韩精品 | 亚洲欧洲成人 | 国产精品国产三级国产专区53 | 亚洲三级在线免费 | 亚洲性猛交xxxx乱大交 | 新91视频在线观看 | 午夜黄色在线 | 91热久久| 91天天操| a在线观看免费 | 中文字幕24页 | 亚洲无av在线中文字幕 | 日韩三级一区二区三区 | 亚洲精品一二区 | 曰韩黄色一级片 | 在线观看亚洲视频 | 欧美在线观看免费高清 | 亚av| av毛片大全 | 日日干夜夜骑 | 久草成人网 | 狠狠做深爱婷婷综合一区 | 日韩三级视频在线 | 国产成人在线免费 | 91桃色在线观看 | 日本一级淫片 | 久久一区亚洲 | 亚洲图区综合 | 在线日韩 | 一级特黄高清 | 国产3区 | 日本一区二区三区四区视频 | 日批在线观看 | 天天草天天爽 | 国产伦乱视频 | 激情文学88 | 美女18毛片| 在线免费一级片 | 国产亚洲精品久久777777 | 禁断介护av一区二区 | 亚洲国产97在线精品一区 | 伊人久久香 | 国产伦子伦对白在线播放观看 | 欧美一级黄色片子 | 国产女主播一区二区 | www.色日本 | 九九热精品在线观看 | 亚洲欧美综合另类自拍 | 国产欧美精品一区二区色综合 | 日韩久久综合 | 少妇一级淫片免费放 | 国产成人激情 | 日韩国产欧美一区二区 | 色网站在线看 | 日韩精品一区二区三区四区 | 超碰啪啪 | 国产一级一区 | 超碰在线一区 | 欧美有码在线 | 日日操夜夜操视频 | 国产黄a三级三级三级 | 1024国产在线 | 欧洲av在线 | 91成人午夜| 亚洲精品视频在线观看免费视频 | 欧美精品乱码久久久久久按摩 | 免费黄色在线 | 国产女人视频 | 国产精品v亚洲精品v日韩精品 | 德国性经典xxxx性hd | 成人免费网站在线观看 | 自拍偷在线精品自拍偷无码专区 | 欧美少妇15p | 中文字幕一区二区不卡 | 色婷婷激情五月 | 三级黄色网| 欧美日韩激情在线观看 | 激情777 | 国产一区二区 | 精品久久免费视频 | 成人黄色激情小说 | 最新四季av在线 | 日本新japanese乱熟 | 日韩91| 亚洲男人的天堂av | 波多野结衣视频网址 | 色久综合网 | 18国产一二三精品国产 | 色又黄又爽 | 在线午夜影院 | 亚洲精品二区三区 | 一级特黄aaaaaa大片 | 国产呻吟久久久久久久92 | 91美女免费视频 | 日本免费一级片 | 男女激情网 | 成人高潮片免费网站 | 久久精品三 | 91免费视频网站 | 99视屏 | 婷婷激情四射 | 欧美亚洲另类图片 | 久久人人爽人人爽 | 国产一区二区三区精品视频 | 中文字幕在线永久 | 日本精品久久久 | 亚洲图区欧美 | 黄色小说视频 | 欧美日韩第一页 | 精品一区二区三区在线观看 | 亚洲第一黄色网址 | 天天综合网在线观看 | 日韩视频在线观看一区 | 欧美疯狂做受 | 日本色区| 波多野结衣在线一区二区 | 亚洲免费一级片 | 久久久夜色精品亚洲 | 在线日韩一区 | 裸体男女树林做爰 | 国产福利不卡 | 亚洲国产精品入口 | 国产精品zjzjzj在线观看 | 都市激情av| 成人久久免费视频 | 欧美一级淫片bbb一84 | 污黄视频在线观看 | 日本在线二区 | 亚洲小说综合网 | 国产精品国产三级国产 | 尤物在线视频观看 | 最近最经典中文mv字幕 | jzzijzzij亚洲成熟少妇在线播放 一区二区视频在线播放 | 久久精品综合 | 久久久久久少妇 | 亚洲午夜精选 | 在线视频观看你懂得 | 日韩一级成人 | 麻豆国产精品777777在线 | 久久久久99啪啪免费 | 日日夜夜91 | www.youjizz.com久久| 91久久精品日日躁夜夜躁欧美 | 国产日韩视频在线 | 色姑娘综合 | 欧美黑人疯狂性受xxxxx野外 | 精品久久久久久久久久久久 | 超碰在线人 | avtt在线观看 | 手机在线小视频 | 婷婷丁香激情五月 | 五月天在线 | 欧美成人中文字幕 | 日韩视频在线观看一区 | 中文在线观看免费高清 | 9色视频| 99久久免费精品国产免费高清 | 91精品国产色综合久久不卡粉嫩 | 91看片免费 | 国产亚洲精品美女久久久 | 亚洲精品大全 | 亚洲国产成人精品久久 | 国产黄色美女视频 | 日韩精品一区二区三区视频 | 青草伊人久久 | 久久艹精品 | 亚洲一区二区三区四区在线 | 日韩成人av在线播放 | 久久精品久久久久久久 | 黄色网址大全免费 | 免费视频中文字幕 | 99人人爽 | 成人综合免费视频 | 操人视频免费 | 曰本三级日本三级日本三级 | 日日射视频 | 久久久久久久久亚洲 | 午夜精品久久久久久久99 | 欧洲色区| 色噜噜网站 | 丁香在线视频 | 成年人小视频在线观看 | 69视频免费在线观看 | 成人欧美一区二区三区黑人冫 | 久久久久久久国产视频 | 男人天堂导航 | 黄色工厂这里只有精品 | 色综合中文网 | 中文字幕日韩在线视频 | 香蕉综合在线 | 成人午夜小视频 | 国产人人精品 | 国产乱人伦精品一区二区 | 97超碰在| 欧美激情婷婷 | 久久久久久久久久久一区二区 | 免费黄色视屏 | 国产大片中文字幕 | 日韩国产在线观看 | 亚洲第三区 | 欧美在线看 | 日韩极品在线 | www.aaaav| 91久久天天躁狠狠躁夜夜 | 一起操网址 | 一级人爱视频 | 亚洲性图第一页 | 欧美精产国品一二三区 | 可以看av的网站 | 99久久精品国产亚洲 | 福利网址在线观看 | 欧美综合在线视频 | 爱情岛亚洲论坛入口福利 | 天天添| 非洲黄色片 | 综合精品久久久 | 成人毛片基地 | 亚洲精品乱码久久久久久麻豆不卡 | 2024av在线播放 | 亚洲 自拍 另类 欧美 丝袜 | 久久男女视频 | www视频在线 | 毛片手机在线 | 91午夜精品亚洲一区二区三区 | 日韩综合在线 | 日韩 欧美 精品 | 天天摸天天碰 | 国产精品99久久99久久久二 | 成人7777 | www.精品国产 | 黄色在线免费观看网站 | 一二三区中文字幕 | 91精品久久久久久久 | 在线视频啪 | 一区二区视频欧美 | 波多野吉衣一区二区三区 | 四虎福利视频 | 五月天婷婷在线观看 | 国产精品成人一区二区 | 99亚洲视频 | 天天做夜夜操 | 天天插天天操天天干 | 亚洲国产成人精品无色码 | 五月婷婷免费视频 | 激情四射综合网 | 久热国产区二三四 | 夜夜躁日日躁狠狠久久av | 午夜精品久久久久久久久久久久久蜜桃 | 2017日日夜夜 | 天堂在线观看视频 | 午夜精品久久久久久久久久久久久蜜桃 | 日日躁夜夜躁狠狠躁 | 一区精品在线观看 | 三级黄色小视频 | 婷婷伊人五月 | 超碰69| 丁香婷婷视频 | 天天综合一区 | 午夜激情一区 | 欧美在线视频免费播放 | 曰女同女同中文字幕 | 绯色av一区二区三区在线观看 | 日韩网站在线 | 天堂bt在线 | 国产精品系列在线播放 | 福利视频在线播放 | 亚洲成人一二三 | 精品一区中文字幕 | 男女无遮挡网站 | 亚洲va欧美va久久久久久久 | 青青成人在线 | 激情一区| 亚洲区视频 | 围产精品久久久久久久 | 久久综合88 | 17c在线| 欧美激情网站 | 欧美一区二区在线观看 | 国产成人一区二区三区视频 | 中文字幕系列 | 播放黄色一级片 | 粉嫩绯色av一区二区在线观看 | 天堂网在线中文 | 日本欧美在线视频 | 精品国产一区一区二区三亚瑟 | 久久久香蕉| 成人激情视频在线 | 3344av| 伊人草草 | 午夜影院h| av网站网址 | 亚洲美女高潮久久久 | 青青国产精品视频 | 懂色av懂色av粉嫩av分享吧 | 欧美亚洲影院 | 激情男女视频 | 一级特级毛片 | 91精品国产高清一区二区三区蜜臀 | 丁香在线视频 | 亚洲男女视频 | 夜夜嗨av一区二区三区四季av | 日本人妻换人妻毛片 | 国产私拍福利 | 五月天综合久久 | 黄色国产在线视频 | 国产视频一二三 | 欧美高清hd18日本 | 中日韩乱码一二新区 | 国产三级国产精品国产普男人 | 在线视频观看免费 | 欧美三级色图 | 天天综合天天干 | 国产噜噜噜噜噜久久久久久久久 | 91在线免费播放 | 国产91看片 | 国产精品久久久久久久久久蜜臀 | 都市激情校园春色亚洲 | 日韩精品一二三四 | 最新精品国产 | 久久久性高潮 | 亚洲字幕成人中文在线观看 | 国产aa| 欧美黑人一区二区三区 | 国产xxxx性hd极品 | 亚洲自拍第二页 | av2018| 国产一二区在线观看 | 亚洲天堂午夜 | 久久久精品免费 | 亚洲精品美女在线观看 | 91麻豆精品国产91 | 日本在线中文字幕专区 | 亚洲欧美综合网 | 亚洲最大成人在线 | 色婷婷六月 | 色爽爽爽 | 污网站在线观看免费 | 国产午夜视频在线播放 | 精品在线不卡 | www.色涩| 五月天久久婷婷 | 亚洲一区欧美日韩 | 国产欧美综合视频 | 欧美黄色大片免费看 | 超薄肉色丝袜一区二区 | 免费的黄色的视频 | 午夜天堂网| 亚洲精品久久久久avwww潮水 | 日韩欧美日韩 | av丁香| 69视频免费观看 | 成人网在线观看 | 天堂网va| 性色av一区二区三区 | av基地网 | 成人春色影视 | 成人欧美性 | 中国女人毛片 | a国产| 乱视频在线观看 | 国产精美视频 | 日本黄色网页 | 加勒比综合网 | 一区二区三区美女视频 | 伊人蕉 | 日韩国产亚洲欧美 | 亚洲欧美精品在线 | 中文字幕网站免费观看 | 国产小视频在线免费观看 | 国产成人亚洲精品自产在线 | av在线免费观看网址 | 日韩美女视频一区 | 亚洲视频在线播放 | 亚洲成色www久久网站瘦与人 | 在线三区 | 尤物视频在线观看国产 | 日韩中文字幕不卡 | 欧美色图狠狠干 | 女人性做爰100部免费 | 国产成人午夜精品5599 | 国产精品久久久久久中文字 | 看看屋午夜伦理 | 91视频地址 | 97在线免费 | 福利一区三区 | 国产福利一区二区三区 | 国产群p | 老司机成人网 | 成人深夜视频在线观看 | 青青免费在线视频 | 91在线一区 | 国产一级av毛片 | 免费欧美一级 | 亚洲精品一区二区三区中文字幕 | 在线免费观看你懂的 | 午夜国产一级一片 | 徐锦江一级淫片免费看 | jizz国产精品| 亚洲第一页在线观看 | 日韩在线影视 | 日本精品不卡 | 色欧美在线 | 亚洲天堂一 | www.亚洲激情 | 99久久影院 | 天天色综合久久 | 欧美一区二区精品 | 日本在线视频中文字幕 | 天堂网av2014| 黄色一级大片在线免费看国产一 | 日韩三级免费观看 | 欧美 变态 另类 人妖 | 99精品热视频 | 日韩精品一区二区三区免费视频 | 亚洲三级网| 日韩一卡二卡在线 | 天堂一区| 在线观看中文字幕 | 97在线视频免费 | 91在线网站| 午夜免费剧场 | 在线播放日韩 | 中国女人av | 久久久婷 | 欧美不在线 | 人人亚洲| 男人激情网 | 午夜精品一二三区 | 日韩精品网站 | 黄色正能量网站 | 成人免费看| 欧美性xxxx | 日韩三级在线 | 久久伊人在 | 国产精品二区在线观看 | 激情网页 | 国产深夜视频 | 根深蒂固在线观看 | 日日夜夜艹 | 国产馆av | 亚洲精品久久久久久久久久久久久久 | 狠狠躁夜夜躁人人爽天天高潮 | 一色综合 | 欧美日韩免费高清一区色橹橹 | 欧美黑人做爰爽爽爽 | 手机看片日韩日韩 | 日日夜夜操操操 | 影音先锋中文字幕一区 | 一区二区三区黄色 | 午夜婷婷在线观看 | 日本天堂影院 | 99黄色片 | 精品一区二区三区免费 | 亚洲麻豆国产 | 国产免费无遮挡 | 亚洲一区无 | 日日操日日 | 久久国产香蕉 | 视频一区中文字幕 | 亚洲图片小说视频 | 色一情一乱一伦一区二区三区 | 亚洲欧美强伦一区二区 | 午夜啪啪网 | 国产探花一区 | 精品中文字幕一区 | 亚洲国产精品18久久久久久 | 日本黄色录象 | 精产国品一二三产区区别在线观看 | 天天操狠狠操 | 激情小视频 | 欧美黑人狂野猛交老妇 | 男女拍拍拍 | 天天草av| 久久久久久久久久久久久女国产乱 | 成人伊人网 | 星空大象mv高清在线观看 | 四虎永久在线精品免费网址 | 亚州黄色 | 亚洲午夜免费 | 性xxxx摔跤视频 | 国产最新网址 | 97色在线| 黄色永久网站 | 一级片日韩| 偷偷操不一样的久久 | 新毛片基地 | 91入囗| 日韩1024| 伊人成人在线视频 | 伊人黄色片 | 日批视频免费 | 成年人黄色录像 | 国产一级中文字幕 | 国产精品国产一区二区三区四区 | 欧美一及片 | 成人性生交大片免费看中文 | 日韩人体视频 | 成人黄色激情小说 | 啦啦啦免费高清视频在线观看 | www日本高清| 成人一区二区三区免费视频 | 在线观看黄色av网站 | 999免费视频 | 91在线无精精品一区二区 | 日韩一区三区 | 日本三级在线 | 青娱乐毛片 | 久久久久久免费 | 91免费在线| 五月天综合激情 | 超碰超碰97 | 国产精品区一区二区三 | 亚洲自拍偷拍色 | 黄色一级a毛片 | 成人在线视频网 | 污污的视频网站在线观看 | 中文字幕久久久久久久 | 灌满闺乖女h高h调教尿h | a级在线免费观看 | 亚洲网站在线观看 | 欧美一级免费看 | 亚洲视频成人 | 日日精| 色四月婷婷 | 一区二区三区免费观看 | 北条麻纪在线观看aⅴ | 亚洲精品一区二区三区不 | 欧美系列第一页 | 久久久综合久久 | 亚洲欧美日韩天堂 | 97福利社 | 麻豆综合网 | 在线视频精品观看 | 国产粉嫩在线 | 夜夜操夜夜骑 | www.com日本| 日韩国产三级 | 啪视频在线观看 | 亚洲最大黄色网址 | 在线一区二区三区 | 美脚丝袜一区二区三区在线观看 | 亚洲黄色小说网 | 好吊操精品视频 | 永久免费看mv网站入口78 | 粉红女士1977年 | 极品少妇一区 | 国产天天射 | 免费一二区| 女人叫床很黄很污句子 | 亚洲视频精品在线 | 男人舔女人下部高潮全视频 | 日本精品视频 | 毛片.com| 91麻豆精品在线 | 欧美精品一二区 | 日韩成人在线免费视频 | 日本少妇色视频 | 亚洲视频中文字幕 | 男人天堂黄色 | 神马久久久久久久 | 国产玖玖 | 伊人手机在线视频 | 一区二区伊人 | 国产精品国产精品国产专区不片 | 视频在线91 | 成人欧美激情 | 色网站免费观看 | 在线欧美色 | 理论片午午伦夜理片影院99 | 精品一区二区三区免费视频 | 亚洲一区欧美一区 | 日韩精品一二三 | 一级 黄 色 片69 | 久久婷婷色 | 日韩黄色av | 欧美视频区 | 国内偷拍第一页 | 久久澡| 日韩中文字幕在线观看 | 国产精品v欧美精品v日韩 | 天天操天天射天天爽 | 国产第一页第二页 | 国产福利91精品 | 日韩精品一区二区三区视频 | 欧美一区二区三区视频 | 日韩天堂| 亚洲精品视频久久久 | 毛茸茸日本熟妇高潮 | 黄色特级大片 | 小视频在线看 | 国产一区二区在线视频观看 | 国产69精品久久久久777 | 91成人精品 | 青青久在线| 国产乱淫av片免费观看 | 亚洲国产欧美另类 | 国产午夜精品久久久久久免费视 | 免费a级片在线观看 | 91网站免费入口 | 你懂的欧美| 特黄视频免费看 | 成人性生活免费视频 | 日韩在线一区二区三区四区 | 亚洲第一色站 | 成人在线h | 国产一区一区 | 尤物精品视频 | 亚洲视频一二 | 亚洲一区二区精品视频在线观看 | 中文字幕在线播放一区二区 | 网站在线免费观看 | 一本色道久久综合精品竹菊 | 少妇精品高潮欲妇又嫩中文字幕 | 国产哺乳奶水91在线播放 | 另类视频一区 | 龚玥菲三级露全乳视频 | 齐天大性床战铁扇公主 | 午夜国产一区二区 | 精品视频一区二区 | 俄罗斯女人裸体性做爰 | 国产黄a三级三级三级看三级男男 | 亚洲午夜精品视频 | 久久久夜色精品亚洲 | 日韩看片 | 69sese| 国产视频一区二 | 国产激情av| 特级毛片爽www免费版 | 亚洲天堂中文字幕 | 日韩成人不卡 | 欧美成人三区 | 综合激情麻豆 | 国产精品5| 最近国语视频在线观看免费播放 | 亚洲国产三级在线观看 | 日韩精品在线免费 | 毛片的网站| 用力操av| 亚洲视频在线观看免费 | 久久伊人操 | 国产一区h | 亚洲午夜久久久久久久国产 | 欧美一区二区在线观看 | 2019国产精品 | 国产精品视频播放 | www天堂在线 | av噜噜噜 | 亚洲天堂系列 | 午夜www| 五月婷在线视频 | 国产特黄大片aaaa毛片 | 久久91久久久久麻豆精品 | 国产高清一区二区三区 | 亚洲午夜精品一区二区三区 | 日本黄色精品 | 国产亚洲va综合人人澡精品 | 美少妇av| 精品在线视频免费 | 国产片高清在线观看 | 台湾佬在线 | 国产乱码在线 | 国产又黄又粗又长 | 日韩在线第二页 | 2024国产精品 | 日本在线小视频 | 中文字幕一区二区在线视频 | 91偷拍网| 国产亚洲一区精品 | 久久久久久伊人 | 欧美精品日韩少妇 | 高清乱码免费看污 | 三级自拍视频 | 欧美自拍区 | 伊人久久久久久久久久 | 久艹在线视频 | 亚洲视频网址 | av成人在线观看 | 色av网站 | 狠狠操在线 | 奇米网在线观看 | 中日韩黄色片 | 国产精品99久久久久久久久久久久 | 欧美成人一二三区 | 天天干天天草 | 日日摸日日添日日躁av | 91久久天天躁狠狠躁夜夜 | 中文字幕在线视频第一页 | 茄子av| 免费的黄色小视频 | www.亚洲天堂| 久草视频福利在线 | 国产欧美日韩在线播放不了吗 | 欧美精品一区二区视频 | 性做久久久久久 | 中文字幕久热 | 亚洲激情视频在线观看 | 色桃网 | 神马久久网站 | 国产在线观看av | 最近中文字幕免费av | 成人免费三级 | 超碰精品在线观看 | 夜夜高潮夜夜爽国产伦精品 | 久久久久久毛片精品免费不卡 | 国产一区二区三区视频在线播放 | av成人动漫 | 天天做天天爱夜夜爽 | 天天综合天天干 | 丰满岳妇乱一区二区三区 | 尤物av午夜精品一区二区入口 | av在线天堂网 | 爱蜜臀av| 免费特黄视频 | 美日韩一级 | 男女午夜免费视频 | av在线免费资源 | 黄色另类小说 | 毛片一区二区三区 | 少妇综合网| av福利院 | 国产精品激情av久久久青桔 | 中文字幕免费一区 | 国内精品久久久久久久久 | 九色丨蝌蚪丨成人 | 永久黄网站| 中国成人av | 日韩三级成人 | 伊人79| 天堂中文在线视频 | 欧美午夜不卡 | 日韩欧美网站 | 午夜伦理在线观看 | 国产无毛av | 欧美一级大片在线观看 | 五月天婷婷在线视频 | 欧美夜夜爽| 亚洲精品免费播放 | 天堂av资源在线观看 | 黄色的毛片 | 亚洲精品天堂在线 | 成人性生活免费视频 | 欧美人与禽zozzozzo | 永久免费精品影视网站 | 免费的一级片 | 成人午夜在线免费观看 | 国产黄色在线免费观看 | 亚欧视频在线观看 | 最近国语视频在线观看免费播放 | 国产精品久久久久不卡 | 午夜第一页 | 啪啪激情网| 国产超碰人人做人人爽 | 国产欧美久久久精品免费 | 精品九九九九九 | 国产精品成人国产乱一区 | 超碰婷婷 | 92看片淫黄大片看国产片 | 成人激情视频网站 | 综合成人| 国产呻吟久久久久久久92 | 欧美日本国产 | 91日日日 | 欧美精品免费看 | 四色网址 | 天天躁日日躁aaaa视频 | 99视频在线精品免费观看2 | 国产第一页在线播放 | fc2ppv在线观看 | 五月综合激情日本mⅴ | 天堂网在线最新版www中文网 | 人人爽人人爽人人片av | 波多野结衣视频在线 | 激情六月 | 欧美性大战久久久 | 国产精品视频免费 | 又色又爽的网站 | 国产三级三级三级 | 波多野结衣绝顶大高潮 | 伊人久久九 | 日本黄色不卡视频 | 亚洲欧美性受久久久999 | 波多野结衣黄色网址 | 天天干 夜夜操 | 久久免费在线观看 | 日韩亚洲视频 | 国产黄色自拍视频 | 人人澡人人澡人人 | 一本视频在线 | av免费毛片| 亚洲a一级| 天堂网一区 | 欧美在线性视频 | 人人爽人人澡 | 欧美日韩一区二区三区在线 | 欧美老肥妇做.爰bbww视频 | 香蕉污视频在线观看 | 日韩精品一区二区三区在线观看 | 国产日本在线视频 | 黄色大片网 | 久久无毛 | 丁香一区二区 | 五月天视频 | 香蕉视频污视频 | 青青青在线 | 91精品国产综合久久福利软件 | 丰满少妇一区 | baoyu116永久免费视频 | 四虎精品久久 | 久久久久久久久久久久久久免费看 | 91超碰在线免费观看 | 久久综合网址 | 亚洲国产日韩av | 日韩在线观看中文字幕 | 国产网红主播三级精品视频 | 欧美日本亚洲 | 亚洲精品中文在线观看 | 亚洲成av在线 | 岛国精品 | 成人啪啪 | 亚洲综合在线免费 | 黑人干亚洲 | 欧美日韩国产二区 | 69久久 | 女人洗澡一级特黄毛片 | 理论片av | 国产成人高清 | 国产美女无遮挡永久免费 | 久久一区二区三区四区 | 伊人论坛 | 特级a毛片 | 色婷婷激情av | 尤物视频在线观看 | 日韩插插 | 香蕉视频国产在线 | 精品国产鲁一鲁一区二区张丽 | 啪啪网站免费观看 | 色图社区 | h狠狠躁死你h高h | 奇米影视一区 | 欧美性视频网站 |