Java服务器编程模型

通常,我们的应用程序不需要并行处理成千上万的用户,也不需要在一秒钟内处理成千上万的消息。我们只需要应付数十或数百个并发连接的用户,就可以在内部应用程序或某些微服务应用程序中承受如此大的负担。

在这种情况下,我们可以使用某些高级框架/库,这些框架/库在线程模型/已用内存方面没有得到优化,并且仍然可以承受一些合理的资源和相当快的交付时间。

但是,有时会遇到这样的情况,即我们的系统部分需要比其他应用程序更好地扩展。用传统的方式或框架编写系统的这一部分可能会导致巨大的资源消耗,并且需要启动同一服务的许多实例来处理负载。导致能够处理数万个连接的能力的算法和方法也称为  C10K问题

在本文中,我将主要关注可以通过TCP Connections / Traffic进行的优化,以优化您的(微)服务实例以浪费尽可能少的资源,更深入地研究OS如何与TCP和套接字,以及最后但并非最不重要的一点,是如何深入了解所有这些内容。让我们开始吧。

I / O编程策略

让我们描述一下我们目前拥有什么样的I / O编程模型,以及在设计应用程序时需要选择哪些选项。首先,没有好的或坏的方法,只有更适合我们当前用例的方法。选择错误的方法可能在将来带来非常不便的后果。这可能会浪费资源,甚至可能从头开始重写应用程序。

通过阻塞处理来阻塞I / O

每连接线程服务器

这种方法背后的思想是,没有任何专用/空闲线程,则不接受套接字连接(我们将在后面显示其含义)。在这种情况下,阻塞意味着该特定线程已绑定到该连接,  并且总是在从该连接读取或写入该连接时阻塞。

套接字服务器的最简单版本, 它从端口5050开始 ,以阻塞方式进行读取  InputStream 和写入  OutputStream。当我们需要通过单个连接传输少量对象,然后在需要时关闭它时,启动一个新对象很有用。

  • 即使没有任何高级库也可以实现它。

  • 使用阻塞流进行读取/写入(等待阻塞  InputStream 读取操作,该操作由当时TCP接收缓冲区中可用的字节填充提供的字节数组, 并返回字节数或-1-流的末尾)并消耗字节,直到我们有足够的数据来构建请求。

  • 当我们开始以无限方式为传入连接创建线程时,可能会出现一个大问题和效率低下。我们将为非常昂贵的线程创建和内存影响付出代价,这是将一个Java线程映射到一个内核线程时产生的。

  • 除非我们确实需要一个内存不足的应用程序并且不想加载很多属于某些框架的类,否则它不适合“实际”生产。

具有阻塞处理功能的非阻塞I / O

基于线程池的服务器

这是大多数知名企业HTTP服务器所属的类别。通常,此模型使用多个线程池  来使处理在多CPU环境中更有效,并且更适合企业应用程序。有多种方法可以配置线程池,但是基本概念在所有HTTP服务器中都完全相同。请参阅  HTTP Grizzly I / O策略  ,以了解通常可以基于基于线程池的非阻塞服务器配置的所有可能策略。

 

优点

 

 

缺点

 

 

如何设置线程池

好的,我们有一个或多个线程池来处理阻塞的业务操作。但是,线程池的最佳大小是多少?我们会遇到两个问题:

 

 

我会参考Brian Goetz的一本很棒的书《Java Concurrency in Practice》 ,其中说确定线程池的大小并不是一门精确的科学,它更多地是关于了解环境和任务性质的。

 

 

如果我们的程序包含I / O或其他阻止操作,则您需要一个更大的池,因为不允许您的线程一直一直放置在CPU上。您需要估计等待时间的比率,以便使用一些探查器或基准测试来计算任务的时间,并观察生产工作负载不同阶段(高峰时间与非高峰时间)的CPU利用率。

 

  • 接受新连接的第一个线程池。如果一个线程能够管理传入连接的速度,它甚至可以是单线程池。通常有两个待办事项列表可以填写,而下一个传入连接则被拒绝。检查是否可以正确使用持久连接。

  • 第二个线程池,用于通过非阻塞方式(选择器线程或IO线程)从套接字读取/写入套接字。每个选择器线程都处理多个客户端(通道)。

  • 第三个线程池分隔请求处理的非阻塞和阻塞部分(通常称为工作线程)。该选择线程不能被一些阻塞操作被阻止,因为所有其他通道将无法取得任何进展(只有一个信道组线程,该线程将被阻止)。

  • 非阻塞读取/写入是使用缓冲区实现的,选择器线程会从套接字读取新字节并写入专用缓冲区(缓冲的缓冲区),只要不满足处理请求的特定线程(因为它们没有足够的数据来构造)例如HTTP请求)。

  • 我们需要澄清术语“ 非阻塞”:

    • 如果我们在Socket Server的上下文中进行讨论,则非阻塞意味着线程不与打开的连接绑定,并且不等待输入数据(甚至在TCP发送缓冲区已满时甚至写入数据),只要尝试读取并检查是否没有字节,则没有字节被添加到缓冲区中以进行进一步处理(构造请求),并且给定的选择器线程继续从另一个打开的连接中进行读取。

    • 但是,就处理请求而言,代码在大多数情况下是  BLOCKING,这意味着我们执行一些代码来阻塞当前线程,并且该线程等待I / O绑定处理的完成(数据库查询,HTTP调用) ,从磁盘中读取..)或某些持久的CPU绑定处理(计算散列/阶乘,加密挖掘等)。如果执行完成,则线程将被唤醒并继续执行某些业务逻辑。

  • BLOCKING  我们的业务逻辑的自然是最主要的原因,工人池如此巨大,我们只需要得到大量的线程发挥作用来提高吞吐量。 否则,在更高的负载(例如,更多的HTTP请求)的情况下,我们可能会导致所有线程处于阻塞状态,并且没有可用的线程来处理请求(没有处于Runnable状态的线程准备在CPU上执行)。

  • 即使请求的数量很高并且许多我们的工作线程在某些阻止操作中被阻止,我们也能够接受新的连接,即使我们可能无法立即处理它们的请求并且数据必须在TCP接收中等待缓冲区。

  • 许多框架/库(Spring Controllers,Jersey等)和HTTP Server(Jetty,Tomcat,Grizzly等)都使用此编程模型,因为这样很容易编写业务代码,并且如果确实使线程阻塞,需要。

  • 并行性通常不是由CPU的数量决定的,而是由阻塞操作的性质和工作线程的数量所限制。通常,这意味着如果阻塞操作(I / O)与进一步执行(在请求过程中)的时间比例太高,那么我们可以得出以下结论:

    • 在阻塞操作(数据库查询,..)上有很多阻塞线程,并且

    • 很多请求等待工作线程被处理,

    • 由于没有线程而无法充分利用的CPU可以继续执行

  • 更大的线程池导致上下文切换和CPU缓存使用效率低下

  • 线程池太小,我们没有足够的线程来覆盖所有线程被阻塞的时间,比如说等待I / O操作,而您的CPU没有得到有效利用。

  • 线程池太大,我们为许多实际上空闲的线程付出了代价(请参见下面,当我们运行很多线程时的价格)。

  • 您的环境有多少CPU和多少内存?

  • 任务主要执行计算,I / O还是某种组合?

  • 它们是否需要稀缺资源(JDBC连接)?线程池和连接池会相互影响,当我们充分利用连接池时,增加线程池以获得更好的吞吐量可能没有意义。 

具有非阻塞处理的非阻塞I / O

基于与CPU核心相同数量的线程的服务器

如果我们能够以非阻塞方式管理大部分工作负载,则此策略是最有效的。这意味着使用非阻塞算法来实现对套接字的处理(接受连接,读取,写入),但是即使业务处理也不包含任何阻塞操作。

此策略的典型代表是Netty Framework,因此让我们深入了解如何实现此框架的体系结构基础,以了解为什么它最适合解决C10K问题。如果您想详细了解其实际工作原理,那么我可以推荐以下资源:

 

Netty in Action-  由Netty Framework Norman Mauer的作者撰写。这是了解如何使用具有各种协议的处理程序基于Netty实现客户端或服务器的宝贵资源。

用户指南4.x的  - Netty中,显示所有基本原则,一个示例应用程序。

I / O处理,协议的实现以及所有其他处理程序都应该使用非阻塞操作来永不停止当前线程。我们总是可以使用其他线程池来阻止操作。然而,如果我们需要把我们的每一个要求,以阻止操作,那么我们几乎利用了Netty的电力专用线程池的开关处理,因为我们很有可能在相同的情况下结束了与非阻塞IO用封闭处理-一个大线程池只是在我们应用程序的不同部分中。


具有异步编程模型的I / O库

Netty是一个I / O库和框架,它简化了非阻塞IO编程,并为服务器和传入连接的生命周期中发生的事件提供了异步编程模型。我们只需要使用lambda连接到回调即可,然后免费获得所有内容。

许多协议都可以使用,而无需依赖某些庞大的库

开始使用纯JDK NIO构建应用程序是非常令人沮丧的,但是Netty包含使程序员处于较低级别的功能,并提供了使许多事情变得更加高效的可能性。Netty已经包含了大多数众所周知的协议,这意味着我们可以比带有许多样板的高级库(例如,用于HTTP / REST的Jersey / Spring MVC)中的协议更加高效。

确定正确的非阻塞用例,以充分利用Netty的功能 

 

 

在上面的图片中,我们可以看到Netty Architecture的主要组件

 

 

 

  • EventLoopGroup —收集事件循环并提供要注册到事件循环之一的通道。

  • EventLoop —处理给定事件循环的已注册通道的所有I / O操作。EventLoop仅在一个线程上运行。因此,一个事件循环的最佳数量  EventLoopGroup 是CPU的数量(发生Page Fault时,某些框架使用CPU数量  + 1  来具有附加线程)。

  • 管道-保留处理程序的执行顺序(在发生某些输入或输出事件时被排序和执行的组件,包含实际的业务逻辑)。管道和处理程序在所属的线程上执行因此,处理程序中的阻塞操作将阻塞给定上的所有其他处理/通道    EventLoopEventLoop 

  • 摘要

    感谢你阅读我的文章,请在下面发表评论。

  • 有什么问题可以加下qq:2062583349。也可添加vx:admindesire,有java、python、web等习资料和视频课程干货”。欢迎交流!

java进行客户端的applet (小程序)开发的技术已广为使用,而用java进行服务器端的servlet(服务器小程序)开发则尚需揭开其神秘的面纱,本书正是基于这样的目的编写的。全书从java服务器的体系结构、开发工具和管理工具、编程技术、安全机制等四个方面全面介绍java服务器的升友技术。通过阅读本书,读者不仅能够知道用java服务器体系结构开发servlet与用传统cgi编写程序的好处,而且还能够掌握编写java servlet的各种技术和技巧。    本书适用于所有对java和web感兴趣的读者使用和参考。 第1部分 java服务器基础[/font] [/font] 第1章 java计算的体系结构[/font] [/font] 1.1 传统的计算模式[/font] 1.1.1 集式计算模式[/font] 1.1.2 胖客户机/服务器计算模式[/font] 1.1.3 瘦客户机/服务器计算模式[/font] 1.1.4 java desktop与x终端[/font] 1.2 java计算[/font] 1.3 小结[/font] [/font] 第2章 java服务器与servlet[/font] [/font] 2.1 java server的结构[/font] 2.1.1 服务[/font] 2.1.2 服务器[/font] 2.1.3 服务构架[/font] 2.1.4 服务器处理构架[/font] 2.1.5 http服务[/font] .2.1.6 核心servlet[/font] 2 1.7 acl[/font] 2.2 servlet及其功能[/font] 2.2.1 什么是servlet[/font] 2.2.2 servlet与applet的区别[/font] 2.2.3 servlet的应用[/font] 2.3 servlet与cgi的比较[/font] 2.3.1 cgi[/font] 2.3.2 servlet的优点[/font] 2.4 运行servlet[/font] 2.5 小结[/font] [/font] 第2部分 java服务器的开发工具和管理工具[/font] [/font] 第3章 使用java server与servlet开发工具[/font] [/font] 3.1 java web server的安装与启动[/font] 3.1.1 在windows 95或windows nt上安装[/font] 3.1.2 在unix上安装[/font] 3.1.3 java server环境变量的设置[/font] 3.1.4 启动java server[/font] 3.1.5 在端口80上启动java server[/font] 3.1.6 结束java serve的运行[/font] 3.1.7 删除java server[/font] 3.1.8 显示缺省主页[/font] 3.1.9 使用随机文档[/font] 3.2 servlet的加载和调用[/font] 3.2.1 加载servlet[/font] 3.2.2 servlet的标识[/font] 3.2.3 调用servlet[/font] 3.3 jsdk的安装与使用[/font] 3.3.1 servletrunner[/font] 3.3.2 在netscape服务器上安装jsdk[/font] 3.3.3 在apache服务器上安装[/font] 3.4 小结[/font] [/font] 第4章 java web server的管理[/font] [/font] 4.1 进入管理工具[/font] 4.2 设置[/font] 4.2.1 设置web service[/font] 4.2.2 设置proxy service[/font] 4.2.3 设置管理服务[/font] 4.3 监视[/font] 4.3.1 记录输出[/font] 4.3.2 记录统计[/font] 4.3.3 资源的使用[/font] 4.4 安全控制[/font] 4.4.1 用户管理[/font] 4.4.2 用户组[/font] 4.4.3 访问控制表[/font] 4.4.4 资源保护[/font] 4.5 servlet管理[/font] 4.5.1 增加servlet[/font] 4.5.2 设置servlet属性[/font] 4.5.3 修改servlet属性[/font] 4.5.4 删除servlet[/font] 4.6 小结[/font] [/font] 第3部分 java服务器编程[/font] [/font] 第5章 servlet包介绍[/font] [/font] 5.1 javax.servlet包[/font] 5.1.1 接口servlet[/font] 5.1.2 接口servletconfig[/font] 5.1.3 接口servletcontext[/font] 5.1.4 接口servletrequest[/font] 5.1.5 接口servletresponse[/font] 5.1.6 类genericservlet[/font] 5.1.7 类servletinputstream[/font] 5.1.8 类servletoutputstream[/font] 5.2 javax.servlet.http包[/font] 5.2.1 接口httpservletrequest[/font] 5.2.2 接口httpservletresponse[/font] 5.2.3 类httpservlet[/font] 5.2.4 类httputils[/font] 5.3 sun.servlet包介绍[/font] 5.3.1 接口servletconnection[/font] 5.3.2 类servletloader[/font] 5.4 小结[/font] [/font] 第6章 sun.servlet.http包介绍[/font] [/font] 6.1 类cookie[/font] 6.2 类httpdate[/font] 6.3 类httpinputstream[/font] 6.4 类httpoutputstream[/font] 6.5 类httprequest[/font] 6.6 类httpresponse[/font] 6.7 类httpserver[/font] 6.8 类httpserverhandler[/font] 6.9 类httpservletconfig[/font] 6.10 类messagebytes[/font] 6.11 类messagestring[/font] 6.12 类mimeheaderfield[/font] 6.13 类mimeheaders[/font] 6.14 小结[/font] [/font] 第7章 genericservlet编程[/font] [/font] 7.1 servlet编程的一个小例子[/font] 7.1.1 genericservlet在jsdk的地位[/font] 7.1.2 从hello world学习genericservlet编程[/font] 7.1.3 servlet的两个生命周期函数[/font] 7.2 servlet的对象[/font] 7.2.1 servlet的请求和应答对象[/font] 7.2.2 selvlet的servletconfig对象[/font] 7.3 servlet输出html文件[/font] 7.4 小结[/font] [/font] 第8章 httpservlet编程介绍[/font] [/font] 8.1 http简介[/font] 8.1.1 http协议基本概念及其特点[/font] 8.1.2 http协议的请求和应答[/font] 8.1.3 http协议的信息处理方法[/font] 8.2 httpservlet编程入门[/font] 8.2.1 一个简单例子[/font] 8.2.2 httpservlet的常用对象介绍[/font] 8.3 cookie编程介绍[/font] 8.3.1 cookie简介[/font] 8.3.2 一个cookie例子程序[/font] 8.4 小结[/font] [/font] 第9章 servlet高级编程[/font] [/font] 9.1 servlet与form[/font] 9.1.1 form简介[/font] 9.1.2 一个完整的form[/font] 9.2 编写一个shtml文本[/font] 9.3 异常处理[/font] 9.4 servlet与applet的通信[/font] 9.5 小结[/font] [/font] 第10章 聊天室[/font] [/font] 10.1 “聊天室”客户程序[/font] 10.2 “聊天室”服务器程序[/font] 10.3 “聊天”[/font] 10.4 小结[/font] [/font] 第11章 rmi与servlet[/font] [/font] 11.1 rmi概述[/font] 11.2 如何编写rmi[/font] 11.2.1 定义一个远程接口[/font] 11.2.2 实现远程接口[/font] 11.2.3 写一个applet[/font] 11.2.4 写html文本[/font] 11.2.5 编译和执行[/font] 11.3 rmi与servlet[/font] 11.3.1 定义远程接口[/font] 11.3.2 实现远程接口[/font] 11.3.3 调用rmi的servlet[/font] 11.3.4 调用servlet的applet[/font] 11.3.5 三个超文本文件[/font] 11.3.6 编译和执行[/font] 11.4 小结[/font] [/font] 第12章 servlet与jdbc[/font] [/font] 12.1 jdbc简介[/font] 12.1.1 实现jdbc[/font] 12.1.2 jdbc类细节[/font] 12.2 jdbc与servlet结合[/font] 12.2.1 基本过程[/font] 12.2.2 servlet的同步[/font] 12.2.3 应用举例[/font] 12.3 小结[/font] [/font] 第13章 开发服务[/font] [/font] 13.1 服务[/font] 13.2 实现服务的核心[/font] 13.3 安装服务[/font] 13.3.1 创建属性文件[/font] 13.3.2 创建jamfile[/font] 13.4 创建日志[/font] 13.4.1 日志文件类型[/font] 13.4.2 在自己的服务加入日志文件[/font] 13.5 服务的参数管理[/font] 13.5.1 系统参数[/font] 13.5.2 增加新的参数[/font] 13.5.3 创建存放参数的域[/font] 13.5.4 实现访问方法[/font] 13.5.5 构造器[/font] 13.5.6 update方法[/font] 13.6 使用realm来创建安全服务[/font] 13.6.1 查找realm[/font] 13.6.2 设置realm[/font] 13.6.3 收集用户数据的对象[/font] 13.6.4 给服务增加身份验证代码[/font] 13.7 小结[/font] [/font] 第14章 pagecompile[/font] [/font] 14.1 生成动态主页[/font] 14.1.1 创建第一个主页[/font] 14.1.2 从html文档到java源文件[/font] 14.2 语法[/font] 14.2.1 声明变量[/font] 14.2.2 条件语句[/font] 14.2.3 循环语句[/font] 14.2.4 注释[/font] 14.2.5 使用backquotes[/font] 14.2.6 使用servlet标记[/font] 14.2.7 输出java表达式[/font] 14.3 使用java类[/font] 14.3.1 重用java类[/font] 14.3.2 创建自己的类[/font] 14.3.3 访问request和response对象[/font] 14.4 servlet初始化参数[/font] 14.5 pagecompile使用的标记[/font] 14.6 小结[/font] [/font] 第4部分 java服务器安全机制[/font] [/font] 第15章 java web server的安全机制[/font] [/font] 15.1 安全综述[/font] 15.1.1 常见的攻击形式[/font] 15.1.2 java web server的安全机制[/font] 15.1.3 其他特点[/font] 15.1.4 unix上的独有特点[/font] 15.2 web realm机制[/font] 15.2.1 realm模型[/font] 15.2.2 用户和授权[/font] 15.2.3 用户组[/font] 15.3 访问控制表(acl)[/font] 15 3.1 访问控制表结构[/font] 15.3.2 计算权限的规则[/font] 15.3.3 例子[/font] 15.3.4 用法举例[/font] 15.4 ssl机制[/font] 15.4.1 什么是ssl[/font] 15.4.2 建立安全的web服务[/font] 15.4.3 使用认证许可[/font] 15.5 沙盒[/font] 15.6 小结[/font]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值