久闻K8S的大名,一直想把业务都迁移到上面降低运维成本,但无奈业务迁移不可能一蹴而就,遂决定先将不那么重要的日志处理模块 Logstash 先行上云,这样即使出现了问题,也不会影响到核心业务的运行(虽然会丢一部分日志,但只要业务没问题其实还是可以接受的)。
构建镜像、起Pod、起Service都很顺利,但就在这时候日志中每隔几秒就出现 Connection Reset By Peer 的报错。
检查过程按下不表,直接说原因:
分析了一通后,通过抓包发现,是TKE中使用的CLB的 健康检测机制 导致的这个问题。虽然我并没有开启Service的健康检测,但CLB仍然默默的对其进行检测,并因此导致了报错。
我们都知道,正常的TCP过程是:三次握手,数据交换,四次挥手。
但这个流程对于健康检测来说有点太重了。
健康检测的原理其实很简单,与Service对应的后端Pod建立连接,然后断开即可,不涉及数据的传输。
TCP三次握手不能精简,数据传输已经砍掉了,那么下面能优化的,也就是四次挥手了。而正是这优化,导致了报错。
直接上抓包结果。
根据抓包可以看出,TCP三次握手后,K8S并没有按照正常的FIN四次挥手,而是直接发送了RST + ACK关闭了连接。这么做的确是有好处,降低了健康检测的系统占用,提升了性能,但对于Logstash就出现了很大的问题。
因为Logstash是插件化的东西,想解决问题只需要看插件的代码即可。
我这里使用的Logstash TCP Input,所以直接看上面的代码即可。
上图可以看见,TCP Input底层使用的是Java的Netty,对于错误的处理基本等于0,有错误(RST也算,毕竟是IOException)就写到日志里。同样的,Filebeats也是这个样子,基本所有的错误都写到日志了。
这就没什么办法了。只能改代码。
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
if (!(cause instanceof IOException)) {
logger.error("Error in Netty pipeline: " + cause);
}
ctx.close();
}
把上面的代码改成如下代码,即可解决问题(说白了就是忽略掉那个IOException报错)。
然后重新编译插件即可解决问题啦~
PS:TCP的图转自https://blog.csdn.net/weixin_30398227/article/details/98198288
现在基本所有业务都改成云原生了,省了好几台机器嘿嘿嘿~吹一波TKE~
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。