K8s watch长连接中Okhttp的坑《二》

背景

在上一次优化K8s watch长连接中Okhttp的坑过后,几个月没出现啥问题了

可是后来又开始出现这个异常情况,表现仍然是watch不更新数据了,也不重连了

现象

几次Watch出问题的时候对应master节点指标均有异常,具体表现在io很高、并且伴随有内存分配失败

image.png

因此准备在测试环境模拟产生这个主机异常

通过一番查阅后,决定同时将宿主机的io和内存打满

内存打满可以通过stress来模拟

stress --vm 20 --vm-bytes 500M --vm-keep

io打满可以通过dd命令来模拟,可以参考文档

经过多次试验,上述方式组合起来使用的时候有一定概率会出现watch不再更新的现象,具体表现是watch连接会一直处于FIN_WAIT2状态

tcp6       0      0 10.1.1.2:40890       10.1.1.1:6443       FIN_WAIT2 76179/java       off (0.00/0/0)
tcp6       0      0 10.1.1.2:40874       10.1.1.1:6443       FIN_WAIT2 76179/java       off (0.00/0/0)

这个状态会一直保持,直到重启进程才会重连

解决

上述链接可以看出是没有开启Tcp-Keepalive的,因此我们尝试给okhttp客户端开启Tcp-Keepalive

SocketFactory factory1 = new SocketFactory() {
 
    @Override
    public Socket createSocket() throws SocketException {
        Socket socket = new Socket();
        socket.setKeepAlive(true);
        return socket;
    }
 
    @Override
    public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
        Socket socket = new Socket(s, i);
        socket.setKeepAlive(true);
        return socket;
    }
 
    @Override
    public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
        Socket socket = new Socket(s, i, inetAddress, i1);
        socket.setKeepAlive(true);
        return socket;
    }
 
    @Override
    public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
        Socket socket = new Socket(inetAddress, i);
        socket.setKeepAlive(true);
        return socket;
    }
 
    @Override
    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
        Socket socket = new Socket(inetAddress, i, inetAddress1, i1);
        socket.setKeepAlive(true);
        return socket;
    }
};
OkHttpClient client = apiClient.getHttpClient().newBuilder().socketFactory(factory1).build();
apiClient.setHttpClient(client);

对官方的http客户端自定义一个SocketFactory ;重写所有方法,让他创建的Socket都设置上Tcp-Keepalive

经过这样设置后,多次实验,问题可以得到解决

原因分析

  • 之前升级到H2之后已经有了ping线程了,为什么还是没法从异常状态中恢复过来呢?
image.png

dump出来后可以看到ping线程的和watch线程一样,也卡死了,处理不了这种情形。

  • reflect线程为什么不更新了呢?
image.png

这里可以看到它一直再等待<0x00000005c51b7480> 这个锁被释放,但是这个锁被watch线程一直持有,不释放,怀疑是产生了死锁

image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容