摘要查找
1. 心跳超时:Nacos 集群中的各个节点之间通过心跳机制进行通信和状态同步。如果某个节点无法及时响应心跳请求,其他节点可能会将其标记为不可用,从而导致整个集群不可用。确保网络连接正常,并检查节点之间的延迟和性能,以避免心跳超时问题。
2. 数据一致性:Nacos 集群中的节点需要保持数据的一致性。如果其中一个节点上的数据与其他节点不一致,可能会导致整个集群无法正常工作。此时,可以尝试使用 Nacos 提供的恢复机制,如手动执行数据同步或重新启动节点来恢复一致性。
3. 故障转移:Nacos 支持主备模式和多主模式的高可用配置。确保正确配置了节点的角色和相关参数,使得当一个节点故障时,其他节点能够接替其功能并继续提供服务。这样即使一个节点挂掉,整个 Nacos 集群仍然可用。
为了复现故障情况,可以尝试模拟节点故障,例如暂停节点上的 Nacos 进程、断开网络连接等。这将导致集群中的节点无法正常通信,从而产生类似于实际故障的情况。
请注意,在生产环境中进行故障复现可能会对服务产生影响。因此,请务必在非生产环境中进行测试,并确保备份和恢复机制可以及时生效以避免数据丢失或服务中断。
问题日志
ERROR 1 --- [ XNIO-1 task-2] c.f.icsa.cache.component.CacheOperate : Get jedis from ableNodes error1 at IP:PORT :Could not get a resource since the pool is exhausted
...
com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: One record is expected, but the query result is multiple records
...
Caused by: java.net.SocketTimeoutException: timeout
ERROR 1 --- [ XNIO-1 task-2] c....impl.XXUserInfoServiceImpl : nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
ERROR 1 --- [ XNIO-1 task-2] c....cache.component.CacheOperate : Get jedis from ableNodes error1 at IP:PORT :Could not get a resource since the pool is exhausted
Exception in thread "com.alibaba.nacos.client.naming.updater" Exception in thread "Keep-Alive-Timer" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.addConditionWaiter(AbstractQueuedSynchronizer.java:1855)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2068)
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)
java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "Thread-10" java.lang.OutOfMemoryError: GC overhead limit exceeded
ERROR 1 --- [ XNIO-1 task-4] c.f.icsa.cache.component.CacheOperate : Get jedis from ableNodes error1 at IP:PORT :Could not get a resource since the pool is exhausted
ERROR 1 --- [ XNIO-1 task-9] c.f.icsa.cache.component.CacheOperate : Get jedis from ableNodes error1 at IP:PORT :Could not get a resource since the pool is exhausted
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2681)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3156)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:863)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:358)
修复问题
具体问题具体分析,归咎于代码缺陷…,恰好缓冲失效导致,反序列化内存溢出…已处理恢复
流为关闭
IOUtils.closeQuietly((InputStream)ois);
import org.apache.commons.io.IOUtils;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayOutputStream;
public class CacheSerializeUtil
{
public static byte[] serialize(final Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
return baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
IOUtils.closeQuietly((OutputStream)oos);
IOUtils.closeQuietly((OutputStream)baos);
}
return null;
}
public static Object unserialize(final byte[] bytes) {
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
if (bytes != null && bytes.length > 0) {
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
return ois.readObject();
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
IOUtils.closeQuietly((InputStream)ois);
IOUtils.closeQuietly((InputStream)bais);
}
return null;
}
}
Nacos 客户端 Worker 异常的解析与处理
1. 异常介绍
在使用 Nacos 客户端时,有时候会遇到 com.alibaba.nacos.client.Worker 异常,该异常是由一个名为 mysql-cj-abandoned-co 的线程引起的。这种异常通常表明 Nacos 客户端与 MySQL 数据库的连接出现问题,导致连接被废弃。
2. 异常原因
在 Nacos 客户端中,数据库连接池是通过 [HikariCP]( 实现的。当连接池中的连接长时间未被使用时,就会被标记为废弃,这时会有一个线程负责关闭这些废弃连接,该线程的名称就是 mysql-cj-abandoned-co。如果在关闭废弃连接的过程中发生异常,就会抛出 com.alibaba.nacos.client.Worker 异常。
3. 解决方案
遇到 com.alibaba.nacos.client.Worker 异常时,需要分析具体的异常堆栈信息,找出引发异常的根本原因。根据我们的经验,常见的引发该异常的原因有:
数据库连接超时:Nacos 客户端默认的数据库连接超时时间为30秒,如果数据库连接超时,则会抛出异常。可以通过增加 db.num、db.url、db.user 和 db.password 这些配置项来解决连接超时的问题。
数据库连接数不足:如果 Nacos 客户端需要大量的数据库连接来处理请求,但数据库连接池中的连接数不够用,就会出现连接不足的情况。可以通过调整 db.connectionPoolNum 配置项来增加数据库连接池的大小。
MySQL 服务不可用:如果 MySQL 数据库服务不可用,或者由于网络问题无法连接到 MySQL 服务器,就会导致无法获取数据库连接,从而抛出异常。可以通过检查 MySQL 服务状态和网络连接状态来解决该问题。
参考查询
com.alibaba.nacos.client.Worker" Exception in thread "mysql-cj-abandoned-co
深入浅出 对象序列化EOF异常(java.io.EOFException)
JedisCluster:“由于池已耗尽而无法获取资源”和“等待空闲对象超时”