每个客户端关联的套接字都注册到服务器的选择器(Selector实例,处理操作系统接口,在套接字数据可用时发送通知给操作系统接口,传递给选择器处理)
当客户端发送请求,选择器会收到来自操作系统的请求事件
然后通知服务器线程池里的线程,特定客户端的IO可以读取。
某个线程开始读取数据,处理请求,发送响应,然后返回池中等待下一次请求处理。
有多个客户端情况下的扩展服务器链接是服务器性能的首要障碍
取决于服务器是否使用了非阻塞IO处理基本链接。
服务器线程池的优化的重要性源于客户端请求是有服务器线程池中的任意线程处理。
服务器框架在管理链接和相关线程池方式
基本模型会有一个或多个线程充当选择器,这些在IO可用时通知系统调用的线程
选择器线程通知客户端IO之后工作线程开始处理实际的请求和响应
优化服务器线程池的基本两个
1.需要足够多的工作线程来处理服务器所能处理的并发请求数(而非是并发链接数)
取决于请求本身是IO密集还是CPU密集
比如一个REST服务器对另一个资源进行出站调用,比如调用数据库,这个调用时阻塞调用。
那么每个并发的出站阻塞调用都需要一个线程。
服务器低效的原因——数据库永远是瓶颈
2.任何时间点需要作为选择器线程的数量——不止一个选择线程
选择器会执行select方法调用,找到套接字IO可用,并且通知工作线程处理客户端请求
然后返回继续调用select,重要的是认识到有一部分时间是脱离select方法处理其他
异步处理池和异步响应池
如果对请求线程池进行限流,那么新的请求会等待其轮次,线程池的队列会增加(实践发现)
队列中的大量等待任务大大降低了系统的吞吐量
1.client是一个共享对象,所有客户端对象都是线程安全的,实例化成本高的处理是少量的客户端对象
2.HTTP客户端可以正确的池化链接并使用keepalive保持链接开放。
HTTP/HTTPS通信打开套接字和SSL的开销驱动出了想JDBC一样复用的设计思路
JDK 8
HttpURLConnection 池化5个链接,超出则新建链接而没有进行限制,无限流作用
-Dhttp.maxConnections=N 设置池大小,但无法处理限流能力
JDK11
Djdk.httpclient.connectionPoolSize=N 设置池大小
输入的数据和解析器相关,程序从解析器拉去一系列标记token
输入的数据被转换为一个文档风格对象,应用程序可以在寻找数据片段是遍历对象。
遍历的接口是通用的面向文档的对象表示
通过使用一组能够反映数据结构的预定义类,将输入数据转换成这样的类对象
POJO(plain old java object)
解析器是应用程序逻辑来处理解析器提供的数据
文档模型和对象表示都必须依赖使用解析器来处理数据,但是内部提供了一种数据表示方式,可以处理更复杂的逻辑。
pros and cons
如果JSON对象模型对于你的应用程序来说耗费内存,直接解析处理JSON可以节省
如果处理JSON包含大量数据,直接解析会更高效
parser = factory.createParser(inputStream);
int idCount = 0;
while (parser.hasNext()) {Event event = parser.next();switch (event) {case KEY_NAME:String s = parser.getString();if (ID.equals(s)) {isID = true;}break;case VALUE_STRING:if (isID) {if (addId(parser.getString())) {idCount++;return;}isID = false;}continue;default:continue;}
}