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

Node.js DNS 模塊的小優化

開發 前端
c-ares 支持緩存 DNS 響應,具體的緩存時間取決于 DNS 響應報文的 ttl 和 c-ares 的配置。下面是處理 DNS 響應時記錄緩存的代碼。

這幾天看到了一個關于緩存 Node.js DNS 結果的 PR,然后看了下 c-ares 的代碼,發現 Node.js DNS 模塊也有些可以改進的小地方,所以提交了兩個 PR 嘗試進行優化,本文簡單介紹下相關的內容。

c-ares

c-ares 庫是一個異步的 DNS 解析庫,在 Node.js 中的工作原理如下。

  1. Node.js 調用 c-ares 發起一個 DNS 查詢,并注冊回調。
  2. c-ares 創建一個 socket,通知 Node.js 監聽該 socket 的讀事件。
  3. 該 socket 可讀,Node.js 通知 c-ares,c-ares 讀取響應,并通知 Node.js。
  4. Node.js 調 c-ares 接口解析 DNS 響應。
  5. c-ares 回調 Node.js。

另外 Node.js 還會定時調 c-ares 函數,c-ares 會判斷是否查詢請求是否超時。大致了解 c-ares 的基礎后,接下來看看相關的內容。

1. DNS 緩存

c-ares 支持緩存 DNS 響應,具體的緩存時間取決于 DNS 響應報文的 ttl 和 c-ares 的配置。下面是處理 DNS 響應時記錄緩存的代碼。

static ares_status_t ares_qcache_insert_int(ares_qcache_t           *qcache,
                                            ares_dns_record_t       *qresp,
                                            const ares_dns_record_t *qreq,
                                            const ares_timeval_t    *now)
{
  ares_qcache_entry_t *entry;
  unsigned int         ttl;
  // DNS 響應報文信息
  ares_dns_rcode_t     rcode = ares_dns_record_get_rcode(qresp);
  ares_dns_flags_t     flags = ares_dns_record_get_flags(qresp);
  // 獲取 DNS 響應報文的 ttl
  ttl = ares_qcache_calc_minttl(qresp);
  // 和用戶配置的 ttl 比較,取最小值
  if (ttl > qcache->max_ttl) {
    ttl = qcache->max_ttl;
  }
  // 插入緩存
  entry->dnsrec    = qresp;
  entry->expire_ts = (time_t)now->sec + (time_t)ttl;
  entry->insert_ts = (time_t)now->sec;

  entry->key = ares_qcache_calc_key(qreq);
  ares_htable_strvp_insert(qcache->cache, entry->key, entry);
  ares_slist_insert(qcache->expire, entry);
  return ARES_SUCCESS;

}

下面是 DNS 查詢時緩存的處理。

if (!(flags & ARES_SEND_FLAG_NOCACHE)) {
    status = ares_qcache_fetch(channel, &now, dnsrec, &dnsrec_resp);
    // 存在緩存直接返回
    if (status != ARES_ENOTFOUND) {
      callback(arg, status, 0, dnsrec_resp);
      return status;
    }
  }

但是 c-ares 1.31.0 后自動開啟了緩存,這對于用戶來說可能不是預期的行為,所以 Node.js 提交了 PR 關閉了緩存能力,保證了兼容性。同時,Node.js 后續會提供選項讓用戶可以自定義配置緩存的時間。具體可以參考以下 PR。

在了解這個 PR 的同時,也發現了兩個 Node.js DNS 模塊的優化點。

2. 定時器的超時時間

Node.js 會定時調用 c-ares 函數,讓 c-ares 判斷查詢請求是否超時,目前 Node.js DNS 模塊的定時器邏輯如下。

void ChannelWrap::StartTimer() {
  int timeout = timeout_;
  if (timeout == 0) timeout = 1;
  if (timeout < 0 || timeout > 1000) timeout = 1000;
  uv_timer_start(timer_handle_, AresTimeout, timeout, timeout);
}

可以看到當 timeout 小于 0 時,定時間隔為 1000ms,也就是說 Node.js 會每隔 1000ms 回調 c-ares 判斷查詢是否超時,而當 timeout 等于 0 時,Node.js 設置的定時間隔為 1ms,但是在 c-ares 中當 timeout 等于 -1 和等于 0 時的邏輯是一樣的,都是使用默認的超時時間 2s,相關代碼如下。

if (optmask & ARES_OPT_TIMEOUTMS) {
    // 小于 0 則使用默認值
    if (options->timeout <= 0) {
      optmask &= ~(ARES_OPT_TIMEOUTMS);
    } else {
      channel->timeout = (unsigned int)options->timeout;
    }
}

if (channel->timeout == 0) {
  channel->timeout = DEFAULT_TIMEOUT; // 2s
}

所以如果用戶設置 timeout = 0,Node.js 就會頻繁地調用(每隔 1ms)c-ares 判斷是否超時,但這是沒必要的。優化后的代碼如下。

void ChannelWrap::StartTimer() {
  int timeout = timeout_;
  if (timeout <= 0 || timeout > 1000) timeout = 1000;
  uv_timer_start(timer_handle_, AresTimeout, timeout, timeout);
}

優化的邏輯很簡單,保證 timeout 等于 0 和等于 -1 時的邏輯一致即可。通過測試大概 CPU 使用率下降 2% 左右,測試例子如下。

const { Resolver } = require('dns');
const { createSocket } = require('dgram');
const socket = createSocket('udp4');
socket.bind(0, 'localhost', () => {
    const resolver = new Resolver({ timeout: 0, tries: 4 });
    resolver.setServers([`${socket.address().address}:${socket.address().port}`])
    resolver.resolve('nodejs.org', () => {
        socket.close();
    });
});

具體可以參考 PR:https://github.com/nodejs/node/pull/58441。

3. 最大超時時間

Node.js DNS 解析有 timeout 和 tries 兩個參數,timeout 表示對于一個 DNS 服務器,一個 DNS 首次查詢的超時時間,tries 表示超時次數,但是超時間隔是按照一定算法計算的(比如指數退避),而不是固定的。看一個例子。

const { Resolver } = require('dns');
const { createSocket } = require('dgram');
const socket = createSocket('udp4');
socket.bind(0, 'localhost', () => {
    const resolver = new Resolver({ timeout: 1000, tries: 3 });
    resolver.setServers([`${socket.address().address}:${socket.address().port}`])
    const start = Date.now();
    resolver.resolve('nodejs.org', () => {
        socket.close();
        console.log(`time: ${Date.now() - start}`);
    });
});

例子中輸入的時間大概為 8s,說明不是等間隔重試的,但是有些時候我們希望可以快點重試,比如服務器宕機時快速感知超時,服務重啟時快速獲取結果等,所以我們希望有一種方式可以控制每次重試時的超時時間,而不是使用 c-ares 的默認算法,這個配置就是 c-ares 的 max timeout 配置,最近提了一個 PR 支持該特性,測試例子如下。

const { Resolver } = require('dns');
const { createSocket } = require('dgram');
const socket = createSocket('udp4');
socket.bind(0, 'localhost', () => {
    const resolver = new Resolver({ timeout: 1000, tries: 3, maxTimeout: 1000 });
    resolver.setServers([`${socket.address().address}:${socket.address().port}`])
    const start = Date.now();
    resolver.resolve('nodejs.org', () => {
        socket.close();
        console.log(`time: ${Date.now() - start}`);
    });
});

上面代碼輸出是 4s 左右,說明每次重試間隔都是 1s。具體可以參考 PR:https://github.com/nodejs/node/pull/58440。

Node.js DNS 模塊是比較穩定的模塊,功能上變化不大,但是仍然有一些小地方可以進行優化,也算是不斷完善 Node.js 的功能。

責任編輯:武曉燕 來源: 編程雜技
相關推薦

2021-09-26 05:06:04

Node.js模塊機制

2020-04-15 15:48:03

Node.jsstream前端

2022-09-04 15:54:10

Node.jsAPI技巧

2019-12-17 11:40:44

Node.js模塊前端

2023-06-30 23:25:46

HTTP模塊內存

2011-12-09 11:16:48

Node.js

2021-09-26 22:22:42

js模塊Node

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2023-06-20 19:35:00

Node.js工具

2011-09-08 14:07:28

Node.js

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2012-02-03 09:25:39

Node.js

2020-05-29 15:33:28

Node.js框架JavaScript

2020-08-31 15:00:17

Node.jsrequire前端

2021-01-26 08:07:44

Node.js模塊 Async

2011-11-10 08:55:00

Node.js

2012-10-24 14:56:30

IBMdw

2011-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 综合网伊人 | 自拍偷拍第一页 | 中文字幕精品一区二区三区精品 | 国产美女精品视频 | 免费观看毛片 | 亚洲欧美一区二区三区国产精品 | 在线中文字幕视频 | 成人无遮挡毛片免费看 | 亚洲一级毛片 | 国内精品视频在线观看 | 亚洲精品电影网在线观看 | 中文字幕成人在线 | 国产精品美女久久久久久久网站 | 国产精品18hdxxxⅹ在线 | 国产a区| 国产日韩欧美综合 | 久久精品视频一区二区三区 | 人人九九精 | 国产精品区二区三区日本 | 亚洲自拍偷拍欧美 | 亚洲视频在线看 | 国产精品免费一区二区三区四区 | 久久高清 | 欧美国产日韩在线 | 日韩视频福利 | 在线中文字幕av | 午夜天堂精品久久久久 | 国产成人精品久久二区二区 | 国产在线高清 | 天天天操 | 天天干,夜夜操 | 老司机成人在线 | 久草视频网站 | 在线观看第一页 | 日韩精品免费视频 | 91精品观看 | 在线观看av网站永久 | 亚洲国产成人av好男人在线观看 | 中文字幕在线一区二区三区 | 亚洲一区二区在线 | 精品一区久久 |