使用OkHttpClient 3.6.0
我有一个100k通知流,用于相同的SSL证书和主机发送给APNS。应用程序读取此流,对它们进行排队并使用具有800个线程的执行程序服务进行同步调用,如下所示:
client.newCall(request).execute()
在过去的几天里,我发现我们正在创建大量的连接(因此有很多ReaderRunnable线程)。我知道这一点,通过查看连接数很高时的连接数和相应的堆栈跟踪。我看到许多来自ReaderRunnable的OkHttp api.push.apple.com
个线程。
"OkHttp api.push.apple.com" #84247 daemon prio=5 os_prio=0 tid=0x00002b3a7c022800 nid=0xefd3 runnable [0x00002b29f5e1e000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
- locked <0x00002b34f69a7728> (a java.lang.Object)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:930)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
- locked <0x00002b34f69a7f48> (a sun.security.ssl.AppInputStream)
at okio.Okio$2.read(Okio.java:138)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
at okio.RealBufferedSource.request(RealBufferedSource.java:66)
at okio.RealBufferedSource.require(RealBufferedSource.java:59)
at okhttp3.internal.http2.Http2Reader.nextFrame(Http2Reader.java:95)
at okhttp3.internal.http2.Http2Connection$ReaderRunnable.execute(Http2Connection.java:566)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.lang.Thread.run(Thread.java:745)
2018-03-20 19:58:02 - OkHttpClient Connection Pool Count is 336
2018-03-20 19:59:02 - OkHttpClient Connection Pool Count is 12182
2018-03-20 20:00:07 - OkHttpClient Connection Pool Count is 17081
2018-03-20 20:01:02 - OkHttpClient Connection Pool Count is 19700
2018-03-20 20:02:01 - OkHttpClient Connection Pool Count is 10
这导致我们有时会达到进程和应用程序OOM的线程限制。
问题
这里有两个问题:
为什么我们要建立这么多联系?我认为这是b / c APNS返回SETTINGS_MAX_CONCURRENT_STREAMS = 1.是否可以进行一些帧记录确认? [更新:我可以打印帧日志,但不能打印实际帧本身或设置。]
由于我只使用800个线程并发出同步请求,即使我们最终为每个请求建立一个新连接,为什么池中的连接数超过800或(810 w / idle buffer)任何给定的时间? 这是我在配置客户端时设置连接超时和连接池的方法:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS);
builder.connectionPool(new ConnectionPool(HTTP_CLIENT_MAX_CONNECTIONS, 10, TimeUnit.MINUTES));