惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

设计模式-备忘录模式 - OXOXTECH 牛牛技术客栈 设计模式-中介者模式 - OXOXTECH 牛牛技术客栈 Linux【Ubuntu】修改ssh默认端口 - OXOXTECH 牛牛技术客栈 设计模式-迭代器模式 - OXOXTECH 牛牛技术客栈 scheduled定时任务的三种基本实现方式 - OXOXTECH 牛牛技术客栈 Apriori - 基于关联规则的推荐算法(三) - OXOXTECH 牛牛技术客栈 Apriori - 基于关联规则的推荐算法(二) - OXOXTECH 牛牛技术客栈 Apriori - 基于关联规则的推荐算法(一) - OXOXTECH 牛牛技术客栈 基于JavaFX的桌面端网络调试工具 - OXOXTECH 牛牛技术客栈 Golang Channel的原理介绍 - OXOXTECH 牛牛技术客栈 Go语言Map的原理分析 - OXOXTECH 牛牛技术客栈 Go语言错误处理(panic)的最佳实践 - OXOXTECH 牛牛技术客栈 设计模式-解释器模式 - OXOXTECH 牛牛技术客栈 Redis报错Redis is configured to save RDB snapshots, but it's currently unable to persist to disk. go-webpbin库在Linux报错failed to encode image to WebP: exit status 1.......的问题 exe4j 打包加密的jar - OXOXTECH 牛牛技术客栈 Go生成图形验证码示例 - OXOXTECH 牛牛技术客栈 澳门一天游:一日尽享东方与西方的交融之美 - OXOXTECH 牛牛技术客栈 设计模式-命令模式 - OXOXTECH 牛牛技术客栈 别再自己瞎写工具类了,SpringBoot内置工具类应有尽有 - OXOXTECH 牛牛技术客栈 中山一日游 - OXOXTECH 牛牛技术客栈 设计模式-责任链模式 - OXOXTECH 牛牛技术客栈 起舞吧,齐舞吧 - OXOXTECH 牛牛技术客栈 设计模式-组合模式 - OXOXTECH 牛牛技术客栈 Go语言Web开发|GoFrame框架入门笔记 - OXOXTECH 牛牛技术客栈 Java打包exe教程 - OXOXTECH 牛牛技术客栈 设计模式-代理模式 - OXOXTECH 牛牛技术客栈 MySQL存储过程的优缺点有哪些? - OXOXTECH 牛牛技术客栈 前端渲染优化有哪些? - OXOXTECH 牛牛技术客栈 HTTP状态码及其含义 - OXOXTECH 牛牛技术客栈 从浏览器地址栏输入url到显示页面的步骤 - OXOXTECH 牛牛技术客栈 TypeScript事件派发管理器 - OXOXTECH 牛牛技术客栈 MQTT保留消息的使用方法 - OXOXTECH 牛牛技术客栈 世界工程-港珠澳大桥游 - OXOXTECH 牛牛技术客栈 Golang逃逸分析 - OXOXTECH 牛牛技术客栈 设计模式-享元模式 - OXOXTECH 牛牛技术客栈 牛牛成长记录 - OXOXTECH 牛牛技术客栈 ffmpeg常用命令 - OXOXTECH 牛牛技术客栈 设计模式-外观模式 - OXOXTECH 牛牛技术客栈 设计模式-装饰器模式 - OXOXTECH 牛牛技术客栈 设计模式-桥接模式 - OXOXTECH 牛牛技术客栈 5周年恋爱纪念日 - OXOXTECH 牛牛技术客栈 2024新年快乐,龙腾四海 - OXOXTECH 牛牛技术客栈 迎接新年:除夕的美好时刻 - OXOXTECH 牛牛技术客栈 设计模式-适配器模式 - OXOXTECH 牛牛技术客栈 设计模式-原型模式 - OXOXTECH 牛牛技术客栈 设计模式-建造者模式 - OXOXTECH 牛牛技术客栈 设计模式-工厂模式 - OXOXTECH 牛牛技术客栈 设计模式-单例模式 - OXOXTECH 牛牛技术客栈 SpringBoot在Linux环境下发送163邮件失败(No appropriate protocol (protocol is disabled or cipher suites are inappropriate)) 海与日落 - OXOXTECH 牛牛技术客栈 Swagger比较常用的注解 - OXOXTECH 牛牛技术客栈 猫🐱牛 - OXOXTECH 牛牛技术客栈 2023年最后一个晚霞 - OXOXTECH 牛牛技术客栈 Linux(Centos)部署Nginx教程 - OXOXTECH 牛牛技术客栈 Linux MySQL下载安装详细教程(CentOS版) - OXOXTECH 牛牛技术客栈 JavaFx打包成exe - OXOXTECH 牛牛技术客栈 Flux脚本语言入门教程 - OXOXTECH 牛牛技术客栈 演唱会出图 - OXOXTECH 牛牛技术客栈 Netty TCP解决粘包拆包 - OXOXTECH 牛牛技术客栈 SpringBoot实现订单超时取消的几种方案 - OXOXTECH 牛牛技术客栈 详解Java并发中的各种锁 - OXOXTECH 牛牛技术客栈 SpringBoot集成支付宝支付 - OXOXTECH 牛牛技术客栈 雪花算法:分布式系统唯一ID生成算法 - OXOXTECH 牛牛技术客栈 Java解决空指针的神器Optional - OXOXTECH 牛牛技术客栈 与兴一起 - OXOXTECH 牛牛技术客栈 Java17新特性详解与安装 - OXOXTECH 牛牛技术客栈 Jdk17安装+环境配置详细教程 - OXOXTECH 牛牛技术客栈 孤注一掷 - OXOXTECH 牛牛技术客栈 解决WinSCP经常断线重连 - OXOXTECH 牛牛技术客栈 内存不足导致Tomcat崩溃问题排查与解决办法 - OXOXTECH 牛牛技术客栈 influxDB初识,一个高效的时序数据库 - OXOXTECH 牛牛技术客栈 SpringBoot 服务接口限流方案 - OXOXTECH 牛牛技术客栈 Docker 安装 Portainer - OXOXTECH 牛牛技术客栈 Linux 安装Docker - OXOXTECH 牛牛技术客栈 物料宣传 - OXOXTECH 牛牛技术客栈 Java使用EMQX实现MQTT通信 - OXOXTECH 牛牛技术客栈 Java实现常见的排序算法 - OXOXTECH 牛牛技术客栈 FreeSwitch Windows安装教程 - OXOXTECH 牛牛技术客栈 MQTT单向SSL数据加密 - OXOXTECH 牛牛技术客栈 随性 - OXOXTECH 牛牛技术客栈 mysql报错Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre的解决方案 Git Push项目报 push to origin/master was rejected 错误解决方案 游行记——珠海金沙滩与金湖公园之行 - OXOXTECH 牛牛技术客栈 Tomcat:解决Tomcat启动警告:"无法将资源添加到Web应用程序缓存中....请考虑增加缓存空间" 的问题 - OXOXTECH 牛牛技术客栈 励骏庞都广场,迷一般的皇宫 - OXOXTECH 牛牛技术客栈 Docker 常用命令集合 - OXOXTECH 牛牛技术客栈 ElasticSearch Windows版-安装教程 - OXOXTECH 牛牛技术客栈 Java去除对象中为null的字段 - OXOXTECH 牛牛技术客栈 我和我的青春 - OXOXTECH 牛牛技术客栈 Java实现螺旋矩阵算法: - OXOXTECH 牛牛技术客栈 Java直接内存分配和释放的理解 - OXOXTECH 牛牛技术客栈 FreeSwitch将默认数据库迁移至MySQL - OXOXTECH 牛牛技术客栈 别错过路上的风景,别错过刹那间的深情! - OXOXTECH 牛牛技术客栈 Viewer.js:一款强大的图片预览组件 - OXOXTECH 牛牛技术客栈 Java JDK Proxy和CGLib动态代理示例 - OXOXTECH 牛牛技术客栈 redis常用命令 - OXOXTECH 牛牛技术客栈 SpringBoot查询IP归属地 - OXOXTECH 牛牛技术客栈 Spring 事务失效的六种情况 - OXOXTECH 牛牛技术客栈 #张艺兴每时每刻# - OXOXTECH 牛牛技术客栈
记一次 Nacos 导致的 CPU 飙高问题 !
Mr.Potato · 2023-01-11 · via

前言

今天下午突然 出现 测试环境 cpu飙高,干到了 60%,其他项目 响应时间明显变长。。。有点吓人,不想背锅

项目背景

出问题的项目是 需要连接各个不同nacos 和不同的 namespace 进行对应操作的 一个项目,对nacos的操作都是httpClient 调用的api接口,「httpClient方法 没有问题,不用质疑这个」

定位问题

首先 这 cpu高了,直接top -Hp 看看定位到 进程id,然后 执行 jstack 进程id -> 1.txt,看到堆栈信息 ,下面提示信息有很多

"com.alibaba.nacos.client.config.security.updater" #2269 daemon prio=5 os_prio=0 tid=0x00007fa3ec401800 nid=0x8d85 waiting on condition [0x00007fa314396000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000f7f3eae0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

根据关键字找找 是哪里打印的,「关键字 com.alibaba.nacos.client.config.security.updater」

ServerHttpAgent 类的方法

// init executorService
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setName("com.alibaba.nacos.client.config.security.updater");
        t.setDaemon(true);
        return t;
    }
});

这是构造方法啊,应该只初始化一次的啊,往上debug,我靠,NacosConfigService 类中调用了,「debug 看什么时候调用了 不就行了嘛」

项目初始化的时候 调用了一次,业务系统依赖nacos嘛,ok 可以理解

再就是漫长的等待,30s后 发现又是一次调用,我去,怎么可能。。。

往回debug,代码如下

scheduler.schedule("定时校对灰度nacos 配置", () -> loadGrayConfig(grayFileName),
    1800, 1800, TimeUnit.SECONDS);
/**
 * 灰度配置更新 解决 网络隔离的问题
 *
 * @param grayFileName 灰度文件的名称
 */
private void loadGrayConfig(String grayFileName) {
    synchronized (this) {
        System.err.println("loadGrayConfig datetime: " + DateUtils.formatDate(new Date()));
        //刷一次 缓存 重新获取nacos 内容 赋值
        grayConfigManager.loadNoCache(grayFileName);
    }
}

4b9622458f8f513cd36eabcf551ec38f.png

等会,难道 小丑是我。。。。

这当时是为了灰度功能,定时数据校验用的 用了一个线程池,当时以为用了线程池 妥妥的。。。还特意调用的 Nocache 方法,让他创建新的nacos Config对象,做数据校对

「但是每调用一次 NacosFactory.createConfigService(properties) ,nacos config 构造器就会开一个线程,就导致了这个问题」

这里可能你要问了 你说 为了防止网络隔离 才加的这个调度任务,什么是网络隔离啊?

df1da7cc9dba9fe7ea7be1aa87e4fe91.png

我刚开始听说这个概念是 当时学习 Raft

假设一个Raft集群拥有三个节点,其中节点3的「网络被隔离」,那么按照「BasicRaft」的实现,集群会有以下动作:

  • 节点3由于网络被隔离,收不到来自Leader的Heartbeat和AppendEntries,所以节点3会进入选举过程,当然选举过程也是收不到投票的,所以节点3会反复超时选举;节点3的Term就会一直增大
  • 节点1与节点2会正常工作,并停留在当时的Term

网络恢复之后,Leader给节点3发送RPC的时候,节点3会拒绝这些RPC理由是发送方任期太小。

Leader收到节点3发送的拒绝后,会增大自己的Term,然后变成Follower。

随后,集群开始新的选举,大概率原本的Leader会成为新一轮的Leader。

网络隔离 Raft是怎么解决的呢?

多轮投票的安全问题是棘手的,必须避免同一高度不同轮数分别提交两个不同区块的情形。在Tendermint中,这个问题可以通过锁机制(locking mechanism)得到解决。

锁定规则:「预投票锁(Prevote-the-Lock)」

验证者只能「预投票(pre-vote)」 他们被锁定的区块。这样就阻止验证者在上一轮中预提交(pre-commit)一个区块,之后又预投票了下一轮的另一个区块。

· 波尔卡解锁(Unlock-on-Polka ):验证者只有在看到更高一轮(相对于其当前被锁定区块的轮数)的波尔卡之后才能释放该锁。这样就允许验证者解锁,如果他们预提交了某个区块,但是这个区块网络的剩余节点不想提交,这样就保护了整个网络的运转,并且这样做并没有损害网络安全性。

「解决方案是把term替换成(term, nodeid),并且按照字典序比较大小(a > b === a.term > b.term || a.term == b.term && a.nodeid > b. node_id). 这是paxos里的做法, 保证不会出现raft里的冲突.」

原理是, raft对voting的阶段有2个值来描述: term和当前投了哪个node_id, 即[term, nodeid], 由于raft不允许一个term vote2个不同的不同的node, 也就是说, vote_req.term > local.term && vote_req.nodeid == local.nodeid 才会grant这个vote请求.

把term替换成(term,nodeid)后, vote阶段的大小比较变成了: vote_req.term > local.term || vote_req.term == local.term && vote_req.nodeid >= local.nodeid, 条件边宽松了. 同一个term内, 较大nodeid的可以抢走较小nodeid 已经建立的leader.

而日志中原本记录的term也需要将其替换成(term, node_id), 因为这两项加起来才能唯一确定一个leader. 之前raft里只需一个term就可以唯一确定一个leader.

vote中比较最大log id相应的,从比较tuple (term, index) 改成比较tuple (term, node_id, index).

就这么点修改.

「总结下来就是 按照字典排序 和 预投票锁 保证 当多个 term 相同的 candidate 相遇后,肯定会有一个 获得多数派投票」

想法

我们如果出现 异常的网络隔离情况再回来,可能导致 数据的不一致,但是上面的 解决办法 因为 比较重,不适合我们,我们就单纯 引入 「定时校对的调度任务 进行比较(和 对账一样)」

修复

我对nacos config 连接进行 遍历查找 是否存活,不存活 我就shutdown,然后生成一个新的,而不是这种全部生成一边,毕竟人家 构造器开了线程。。。。

说回来还是因为 我当时自信了,没往这个调用下面看,在子类中 写的开线程 哈哈,行吧,改改 ,跑到测试环境 看看效果(CPU)

image.png

嗯嗯 稳定了,明天再看看,应该没问题了

彩蛋

好像 测试环境响应时间 变长,和我没关系。。。。是别人压测呢,把带宽吃了。。。。。「看透不说透」