偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Node.js DNS 模塊的小優(yōu)化

開發(fā) 前端
c-ares 支持緩存 DNS 響應(yīng),具體的緩存時(shí)間取決于 DNS 響應(yīng)報(bào)文的 ttl 和 c-ares 的配置。下面是處理 DNS 響應(yīng)時(shí)記錄緩存的代碼。

這幾天看到了一個(gè)關(guān)于緩存 Node.js DNS 結(jié)果的 PR,然后看了下 c-ares 的代碼,發(fā)現(xiàn) Node.js DNS 模塊也有些可以改進(jìn)的小地方,所以提交了兩個(gè) PR 嘗試進(jìn)行優(yōu)化,本文簡單介紹下相關(guān)的內(nèi)容。

c-ares

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

  1. Node.js 調(diào)用 c-ares 發(fā)起一個(gè) DNS 查詢,并注冊(cè)回調(diào)。
  2. c-ares 創(chuàng)建一個(gè) socket,通知 Node.js 監(jiān)聽該 socket 的讀事件。
  3. 該 socket 可讀,Node.js 通知 c-ares,c-ares 讀取響應(yīng),并通知 Node.js。
  4. Node.js 調(diào) c-ares 接口解析 DNS 響應(yīng)。
  5. c-ares 回調(diào) Node.js。

另外 Node.js 還會(huì)定時(shí)調(diào) c-ares 函數(shù),c-ares 會(huì)判斷是否查詢請(qǐng)求是否超時(shí)。大致了解 c-ares 的基礎(chǔ)后,接下來看看相關(guān)的內(nèi)容。

1. DNS 緩存

c-ares 支持緩存 DNS 響應(yīng),具體的緩存時(shí)間取決于 DNS 響應(yīng)報(bào)文的 ttl 和 c-ares 的配置。下面是處理 DNS 響應(yīng)時(shí)記錄緩存的代碼。

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 響應(yīng)報(bào)文信息
  ares_dns_rcode_t     rcode = ares_dns_record_get_rcode(qresp);
  ares_dns_flags_t     flags = ares_dns_record_get_flags(qresp);
  // 獲取 DNS 響應(yīng)報(bào)文的 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 查詢時(shí)緩存的處理。

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 后自動(dòng)開啟了緩存,這對(duì)于用戶來說可能不是預(yù)期的行為,所以 Node.js 提交了 PR 關(guān)閉了緩存能力,保證了兼容性。同時(shí),Node.js 后續(xù)會(huì)提供選項(xiàng)讓用戶可以自定義配置緩存的時(shí)間。具體可以參考以下 PR。

在了解這個(gè) PR 的同時(shí),也發(fā)現(xiàn)了兩個(gè) Node.js DNS 模塊的優(yōu)化點(diǎn)。

2. 定時(shí)器的超時(shí)時(shí)間

Node.js 會(huì)定時(shí)調(diào)用 c-ares 函數(shù),讓 c-ares 判斷查詢請(qǐng)求是否超時(shí),目前 Node.js DNS 模塊的定時(shí)器邏輯如下。

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);
}

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

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

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

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

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

優(yōu)化的邏輯很簡單,保證 timeout 等于 0 和等于 -1 時(shí)的邏輯一致即可。通過測(cè)試大概 CPU 使用率下降 2% 左右,測(cè)試?yán)尤缦隆?/span>

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. 最大超時(shí)時(shí)間

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

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}`);
    });
});

例子中輸入的時(shí)間大概為 8s,說明不是等間隔重試的,但是有些時(shí)候我們希望可以快點(diǎn)重試,比如服務(wù)器宕機(jī)時(shí)快速感知超時(shí),服務(wù)重啟時(shí)快速獲取結(jié)果等,所以我們希望有一種方式可以控制每次重試時(shí)的超時(shí)時(shí)間,而不是使用 c-ares 的默認(rèn)算法,這個(gè)配置就是 c-ares 的 max timeout 配置,最近提了一個(gè) PR 支持該特性,測(cè)試?yán)尤缦隆?/span>

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 模塊是比較穩(wěn)定的模塊,功能上變化不大,但是仍然有一些小地方可以進(jìn)行優(yōu)化,也算是不斷完善 Node.js 的功能。

責(zé)任編輯:武曉燕 來源: 編程雜技
相關(guān)推薦

2021-09-26 05:06:04

Node.js模塊機(jī)制

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模塊內(nèi)存

2011-12-09 11:16:48

Node.js

2021-09-26 22:22:42

js模塊Node

2013-11-01 09:34:56

Node.js技術(shù)

2015-03-10 10:59:18

Node.js開發(fā)指南基礎(chǔ)介紹

2011-09-08 14:07:28

Node.js

2023-06-20 19:35:00

Node.js工具

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

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-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js

2011-09-02 14:47:48

Node

2011-09-09 14:23:13

Node.js
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)