mosdns icon indicating copy to clipboard operation
mosdns copied to clipboard

[Bug] lazy cache导致dnsmasq CPU占用率过高

Open GreatMichaelLee opened this issue 1 year ago • 9 comments

在提交之前,请确认

  • [X] 我已经尝试搜索过 Issue ,但没有找到相关问题。
  • [X] 我正在使用最新的 mosdns 版本(或者最新的 commit),问题依旧存在。
  • [X] 我仔细看过 wiki 后仍然无法自行解决该问题。
  • [X] 我非常确定这是 mosdns 核心的问题。(如果是通过第三方衍生软件使用 mosdns 核心,不确定问题源头时,请先向衍生软件开发者提交问题。)

mosdns 版本

v5.1.3

操作系统

Openwrt LEDE 当前最新仓库代码+PW最新版本

Bug 描述和复现步骤

如题所示,5.1.3如果设置为dnsmasq上游,且启用lazy cache的时候,在main sequence里查询lazy cache,会导致dnsmasq 周期性的CPU浪涌,关掉cache能减缓这种现象。通过openwrt上netdata和htop可以观测到(htop就不贴了)

image

使用的配置文件

log:
  level: error
  file: "/mnt/sdc1/mosdns/mosdns.log"

# API 入口设置
api:
  http: "0.0.0.0:9091"

include: []

plugins:
  # 国内域名
  - tag: geosite_cn
    type: domain_set
    args:
      files:
        - "/var/mosdns/geosite_cn.txt"

  # 国内ip
  - tag: geoip_cn
    type: ip_set
    args:
      files:
        - "/var/mosdns/geoip_cn.txt"
  
  # Google CN
  - tag: geosite_google_cn
    type: domain_set
    args:
      files:
        - "/var/mosdns/geosite_google-cn.txt"	

  # 国外域名
  - tag: geosite_no_cn
    type: domain_set
    args:
      files:
        - "/var/mosdns/geosite_geolocation-!cn.txt"

  # 白名单 加入的域名始终允许使用 “本地 DNS” 进行解析
  - tag: whitelist
    type: domain_set
    args:
      files:
        - "/etc/mosdns/rule/whitelist.txt"

  # 黑名单 加入的域名将屏蔽 DNS 解析
  - tag: blocklist
    type: domain_set
    args:
      files:
        - "/etc/mosdns/rule/blocklist.txt"

  # 灰名单 加入的域名始终使用 “远程 DNS” 进行解析
  - tag: greylist
    type: domain_set
    args:
      files:
        - "/etc/mosdns/rule/greylist.txt"

  # DDNS域名 加入的域名始终使用 “本地 DNS” 进行解析,并且修改 TTL 为 5 秒,解析结果不进行缓存
  - tag: ddnslist
    type: domain_set
    args:
      files:
        - "/etc/mosdns/rule/ddnslist.txt"

  # 自定义 Hosts 重写
  - tag: hosts
    type: hosts
    args:
      files:
        - "/etc/mosdns/rule/hosts.txt"

  # 重定向请求的域名
  - tag: redirect
    type: redirect
    args:
      files:
        - "/etc/mosdns/rule/redirect.txt"

  # PTR 黑名单 加入的域名将阻止 PTR 请求
  - tag: local_ptr
    type: domain_set
    args:
      files:
        - "/etc/mosdns/rule/local-ptr.txt"

  # 屏蔽失效/威胁 URL
  - tag: sp_low
    type: domain_set
    args:
      files:
        - "/usr/share/mosdns/sp_low.tdata"

  # 缓存
  - tag: lazy_cache
    type: cache
    args:
      size: 20000
      lazy_cache_ttl: 86400
      dump_file: "/etc/mosdns/cache.dump"
      dump_interval: 600

  # 转发至本地服务器
  - tag: forward_local
    type: forward
    args:
      upstreams:
        - addr: https://doh.pub/dns-query
          bootstrap: 223.5.5.5


  # 转发至远程服务器
  - tag: forward_remote
    type: forward
    args:
      upstreams:
        - addr: https://1.1.1.1/dns-query
          enable_pipeline: false

  # 修改ttl(默认0 不修改ttl)
  - tag: modify_ttl
    type: sequence
    args:
      - exec: ttl 0-0

  # 修改 ddns 域名 ttl(默认 5秒)
  - tag: modify_ddns_ttl
    type: sequence
    args:
      - exec: ttl 5-5

  # 国内解析
  - tag: local_sequence
    type: sequence
    args:
      - exec: $forward_local

  # 国外解析
  - tag: remote_sequence
    type: sequence
    args:
      - exec: prefer_ipv4
      - exec: $forward_remote

  # 有响应则修改 TTL 并终止返回
  - tag: has_resp_sequence
    type: sequence
    args:
      - matches: qname $ddnslist
        exec: $modify_ddns_ttl
      - matches: "!qname $ddnslist"
        exec: $modify_ttl
      - matches: has_resp
        exec: accept

  # fallback 用本地服务器 sequence
  # 返回非国内 ip 则 drop_resp
  - tag: query_is_local_ip
    type: sequence
    args:
      - exec: $local_sequence
      - matches: "!resp_ip $geoip_cn"
        exec: drop_resp

  # fallback 用远程服务器 sequence
  - tag: query_is_remote
    type: sequence
    args:
      - exec: $remote_sequence

  # fallback 用远程服务器 sequence
  - tag: fallback
    type: fallback
    args:
      primary: query_is_remote
      secondary: query_is_remote
      threshold: 500
      always_standby: true

  # 查询 DDNS 域名
  - tag: query_is_ddns_domain
    type: sequence
    args:
      - matches: qname $ddnslist
        exec: $local_sequence

   #查询国内Google域名
  - tag: query_is_google_cn_domain
    type: sequence
    args:
      - matches: qname $geosite_google_cn
        exec: $remote_sequence

  # 查询国内域名
  - tag: query_is_local_domain
    type: sequence
    args:
      - matches: qname $geosite_cn
        exec: $local_sequence

  # 查询国外域名
  - tag: query_is_no_local_domain
    type: sequence
    args:
      - matches: qname $geosite_no_cn
        exec: $remote_sequence

  # 查询白名单
  - tag: query_is_whitelist_domain
    type: sequence
    args:
      - matches: qname $whitelist
        exec: $local_sequence

  # 查询灰名单
  - tag: query_is_greylist_domain
    type: sequence
    args:
      - matches: qname $greylist
        exec: $remote_sequence

  # 拒绝名单
  - tag: query_is_reject_domain
    type: sequence
    args:
      - matches: qname $blocklist
        exec: reject 3
      - matches: qname $sp_low
        exec: reject 3
      - matches:
        - qtype 12
        - qname $local_ptr
        exec: reject 3
      - matches: qtype 65
        exec: reject 3

  # 主要的运行逻辑插件
  # sequence 插件中调用的插件 tag 必须在 sequence 前定义,
  # 否则 sequence 找不到对应插件。
  - tag: main_sequence
    type: sequence
    args:
      - exec: $hosts
      - exec: jump has_resp_sequence
      # 非 “拒绝名单” 或 “DDNS域名” 则启用缓存
      - matches:
        - "!qname $ddnslist"
        - "!qname $blocklist"
        - "!qname $sp_low"
        - "!qname $local_ptr"
        #exec: $lazy_cache
        exec: $redirect
      - exec: jump has_resp_sequence
      - exec: $query_is_ddns_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_whitelist_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_reject_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_greylist_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_google_cn_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_local_domain
      - exec: jump has_resp_sequence
      - exec: $query_is_no_local_domain
      - exec: jump has_resp_sequence
      - exec: $fallback

  # 启动 udp 服务器。
  - tag: udp_server
    type: udp_server
    args:
      entry: main_sequence
      listen: ":5335"

  # 启动 tcp 服务器。
  - tag: tcp_server
    type: tcp_server
    args:
      entry: main_sequence
      listen: ":5335"

mosdns 的 log 记录

日志设置成error最高级别,减少因为日志IO带来的问题判断干扰

2023-08-09T14:33:41.781Z	INFO	unpacking entry	{"tag": "cn", "length": 11543, "file": "/var/mosdns/geoip_cn.txt"}
2023-08-09T14:33:41.887Z	INFO	unpacking entry	{"tag": "cn", "length": 66054, "file": "/var/mosdns/geosite_cn.txt"}
2023-08-09T14:33:41.890Z	INFO	unpacking entry	{"tag": "geolocation-!cn", "length": 19212, "file": "/var/mosdns/geosite_geolocation-!cn.txt"}
2023-08-09T14:33:41.997Z	INFO	unpacking entry	{"tag": "google-cn", "length": 159, "file": "/var/mosdns/geosite_google-cn.txt"}

GreatMichaelLee avatar Aug 09 '23 14:08 GreatMichaelLee

lazy cache 是实验性功能,毕竟破坏了 dns 协议 ttl 的功能,不兼容是正常的。如果出问题建议直接关掉。

你的 mosdns 似乎是修改版。原版的 mosdns 应该不会打印上述 log。“unpacking entry”

IrineSistiana avatar Aug 10 '23 03:08 IrineSistiana

lazy cache 是实验性功能,毕竟破坏了 dns 协议 ttl 的功能,不兼容是正常的。如果出问题建议直接关掉。

你的 mosdns 似乎是修改版。原版的 mosdns 应该不会打印上述 log。“unpacking entry”

我感觉是cache本身的性能问题(或者是go的问题?),导致dnsmasq后端被阻塞,所以会有delta peak效应,暂时的workaround就是关掉mosdns的cache用dnsmasq端的cache。另外,是用的原版啊,我看了lede仓库的make file是用的这里的啊

image

GreatMichaelLee avatar Aug 10 '23 03:08 GreatMichaelLee

我感觉是cache本身的性能问题(或者是go的问题?),导致dnsmasq后端被阻塞,所以会有delta peak效应,暂时的workaround就是关掉mosdns的cache用dnsmasq端的cache。另外,是用的原版啊,我看了lede仓库的make file是用的这里的啊

阻塞不占 cpu,如果是 dnsmasq cpu 占用高,最可能的就是 mosdns 并发了大量请求打在了 dnsmasq 上。开 debug 日志可以看到 lazy cache 有没有往上游 dnsmasq 发送请求。

~~另外,我搜了源代码,mosdns 真不会打印 “unpacking entry” 然后报告载入了的列表有多少条。这功能我之前想加的但是鸽了。~~

搜到了。这是 v2dat 的日志。

IrineSistiana avatar Aug 10 '23 06:08 IrineSistiana

我就是出现了‘mosdns 并发了大量请求打在了 dnsmasq 上。开 debug 日志可以看到 lazy cache 有没有往上游 dnsmasq 发送请求。’ 导致出国查询dns失败,如何解决?

sunshineyxc avatar Aug 22 '23 22:08 sunshineyxc

更新到v5.2.1后,发现 lazy_cache 一直报 failed to update。是安装问题还是BUG呢?

cqjerry avatar Oct 01 '23 00:10 cqjerry

我直接建了个debian 用mosdns做了个服务 比在lede等op下 效率更高

CYaNu avatar Oct 02 '23 04:10 CYaNu

更新到v5.2.1后,发现 lazy_cache 一直报 failed to update。是安装问题还是BUG呢?

我也是,请问你现在解决了么?

asnon avatar Nov 12 '23 01:11 asnon

我也遇到这种情况了……关闭cache会好一些,并且版本从v4~v5都试过,cpu占用会相当的高

yishion819 avatar Feb 13 '24 11:02 yishion819

刷回21或者19版本的op,负载正常了

yishion819 avatar Feb 16 '24 15:02 yishion819