什么是并发
tcp/ip连接
套接字
通道
最大并发是什么?
有多少tcp/ip 连接
如何测试
与多线程并发关系
服务器端
阻塞和非阻塞
1.阻塞
慢 逐一处理 //tomcat
2.非阻塞
快 同时处理
单线程和多线程
1.单线程
优点 速度快 空间少
缺点 并发问题存在
2.多线程
每个请求一个线程 //tomcat //总结 tomcat是阻塞,多线程
优点 没有并发问题
缺点 速度慢 空间多
客户端
阻塞和非阻塞
单线程和多线程
tomcat
1.旧版本
阻塞 多线程
2.新版本8
非阻塞 单线程 //最大并发连接数 10000
www.cnblogs.com/doit8791/p/…
二、三个参数:acceptCount、maxConnections、maxThreads
再回顾一下Tomcat处理请求的过程:在accept如果客户端与服务器发送请求,则在队列中接收连接(OS三次握手建立连接后,OS放入连接accept队列);在连接中获取要求的数据,生成request;调用servlet容器处理请求;返回response。
相对应的,Connector参数功能如下:
1、acceptCount
accept队列长度;当accept队列中连接的数量达到acceptCount队列满了,所有进来的请求都被拒绝了。默认值为100。
2、maxConnections
Tomcat在任何时候接收和处理最大连接数。Tomcat接收的连接数达到maxConnections时,Acceptor不读取线程accept此时accept直到队列中的线程被堵塞Tomcat接收的连接数小于maxConnections。若设置为-1,则连接数不受限制。
默认值与连接器使用有关:NIO默认值为1万(万级),APR/native默认值为8192,BIO的默认值为maxThreads200(如果配置的话Executor,则默认值是Executor的maxThreads)。
在windows下,APR/native的maxConnections该值将自动调整设置值以下1024的最大整数倍;如果设置为2000,则最大值实际上为1024。
3、maxThreads
最大数量的要求处理线程。默认值为200(Tomcat7和8都是的)(百级别)。如果该Connector绑定了Executor,这个值会被忽略,因为应该Connector绑定Executor,而不是内置的线程池来执行任务。
maxThreads规定的是最大的线程数目,并不是实际running的CPU数量;实际上,maxThreads的大小比CPU核心数量要大得多。这是因为处理要求的线程可能很少用于计算,大部分时间可能会被阻塞,比如等待数据库返回数据,等待硬盘读写数据。因此,在某个时刻,只有少数线程真正使用物理CPU,大多数线程都在等待;因此,线程数远大于物理核心数是合理的。
换句话说,Tomcat通过使用比CPU核心数量多的线程数可以使CPU忙起来,大大提高CPU的利用率。
总结
tomcat是服务器端。
nio netty grpc都是作为服务器端提供服务。
socket和nio channel
socket
最大并发连接数:?~几千个 主要受线程数量的影响 //具体实现 就是多线程 连接每个请求 创建线程
早期网络读写数据解决方案。
优点 使用简单
缺点 速度慢 因为堵塞。大空间 因为多线程。
nio channel
最大并发连接数:?万级别 单线程 //具体如何实现 看tomcat源代码-非阻塞模式 //如何测试?因为单机只有几千个线程 因此,测试数千个客户端连接 没问题 万级还没有测试 (注:多线程只是测试并发连接的解决方案) 。//如何测试万级?单机有成千上万个端口,但是jvm线程几千个 所以可以增加jvm内存使线程数量更多。待测试。//
新版本是nio。nio和socket没关系。////channel包含了字段-socket对象,socket获取当前连接的远程对象ip/port和本地ip/port
优点 速度快 因为没有阻塞。空间少 因为单线程。
缺点 使用复杂
附加
tomcat最大并发连接数?
tomcat基于阻塞io(百级连接数 连接每个线程, 百位数线程为上限)或非阻塞nio(万级连接数 ,所有连接的单线程处理)。
如何测试?网上找资料。
netty
最大并发连接数:单机百万连接。
如何测试?juejin.im/post/684490… 一万个连接。优化后。 可达100万个连接。//为什么连接数这么大?因为单线程 处理所有连接 非阻塞。
封装了java nio。使用起来更方便。
优点
缺点
代码
grpc
跨语言、跨平台远程服务。
基于netty 最大连接数和netty差不多。
如何测试?
代码?
打印日志
1000~2000线程/连接数量 会有连接重置-客户端
警告: RPC failed: Status{code=UNAVAILABLE, description=io exception, cause=java.io.IOException: Connection reset by peer
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:384)
at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1128)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:745)
}
复制代码
客户端通道相同
只能连接1次 然后关闭
[Console output redirected to file:/Users/gongzhihao/git/repository2/examples/2.log]
二月 13, 2019 2:52:36 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello wold //连1次 就关掉了
0
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
警告: RPC failed: Status{code=UNAVAILABLE, description=Channel shutdown invoked, cause=null} //第二次 通道关闭
2
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
警告: RPC failed: Status{code=UNAVAILABLE, description=Channel shutdown invoked, cause=null}
4
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
警告: RPC failed: Status{code=UNAVAILABLE, description=Channel shutdown invoked, cause=null}
6
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:52:37 下午 io.grpc.examples.helloworld.HelloWorldClient greet
警告: RPC failed: Status{code=UNAVAILABLE, description=Channel shutdown invoked, cause=null}
8
复制代码
不同客户端通道
互不影响
1000
1万
没有上限 //多线程方案:上限是1000~2000 会报错-连接重置-客户端
[Console output redirected to file:/Users/gongzhihao/git/repository2/examples/2.log]
二月 13, 2019 2:58:10 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello world
0
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello world
2
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello world
4
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello world
6
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Will try to greet world ...
二月 13, 2019 2:58:11 下午 io.grpc.examples.helloworld.HelloWorldClient greet
信息: Greeting: Hello world
8
复制代码
单机-单jvm进程最大线程数
千位数级别 5000 //一个jvm进程 创建5000个线程 jvm内存就不够用了 //单机 不管是服务器端还是客户端 都只能创建千位数级别的线程数
打印日志
4000 jvm内存不够 不能再创建线程
thread name:Thread-4069, thread id:4079
thread name:Thread-4070, thread id:4080
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread //jvm内存不够 不能再创建新的线程 因为没有空间了
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at demo.NIOClient.main(NIOClient.java:104)
java.io.IOException: Too many open files //linux系统 一个进程:最大1000个文件句柄 https://www.cnblogs.com/kongzhongqijing/articles/3735664.html
at sun.nio.ch.IOUtil.makePipe(Native Method)
at sun.nio.ch.KQueueSelectorImpl.(KQueueSelectorImpl.java:84)
at sun.nio.ch.KQueueSelectorProvider.openSelector(KQueueSelectorProvider.java:42)
at java.nio.channels.Selector.open(Selector.java:227)
at demo.NIOClient.initClient(NIOClient.java:35)
at demo.Task1.run(Task1.java:14)
at java.lang.Thread.run(Thread.java:748)
复制代码
测试代码
略