我扮演的关键角色之一是在本地社区中传播Akka。 作为讨论的一部分,人们通常会想到的问题/疑问是Akka如何针对编写良好的Java / JEE应用程序提供更好的可伸缩性和并发性。

由于底层硬件/ JVM保持不变,因此参与者模型如何比传统的JEE应用程序发挥更多的功能? 为了展示怀疑者,我们决定在现有的JEE Web应用程序中进行小型测试,对业务逻辑进行重新建模以利用参与者模型,并对该模型进行测试。


日交易者应用

DayTrader是围绕在线股票交易系统范例构建的基准应用程序。 该应用程序允许用户登录,查看其投资组合,查找股票报价以及买卖股票。 DayTrader不仅是功能测试的出色应用程序,而且还提供了一组标准的工作负载,用于表征和衡量应用程序服务器和组件级别的性能。
DayTrader建立在一组Java EE技术的核心之上,这些技术包括用于表示层和Java数据库连接(JDBC)的Java Servlet和JavaServer Page(JSP),Java消息服务(JMS),企业JavaBeans(EJB)和消息驱动的Bean。 (MDB)用于后端业务逻辑和持久层。 有关DayTrader的更多信息,请点击这里

DayTrader似乎是测试我们理论的应用的合适之选。 我们决定使用JSP-> JDBC模型来使事情保持简单和可比性。 我们采用了2个用例,并对业务逻辑进行了重新建模以使用TypedActors。

场景1 –报价/交易屏幕–获取报价

在DayTrader应用程序的“报价/交易者”屏幕中,有一个工具,可通过单击“报价”按钮来选择报价列表的详细信息。 该股票的报价将被检索并显示给用户。

将涡轮增压器添加到JEE Apps

在标准流程中,获取报价请求由专用的TradeAction处理,该TradeAction在内部调用TradeDirectJEEE对象的getQuote()接口。 对于每个请求,都会创建一个TradeAction对象。

在更新的流程中,创建了一组工作人员角色,它们侦听来自各个模块的请求以获取报价详细信息。 TradeActionManager将在开始时创建Typed actor池,并且还将执行将传入请求路由到Typed actor的操作,Typeed actor包含TradeAction对象以调用getQuote函数。 由于使用了类型化角色,因此相同的TradeActionManager可以在现有应用程序中进行最小的更改的情况下满足其他TradeAction调用。

原始和修改后的DayTrader应用程序都由20个,50个,75个和100个Typed actor以及许多Trade Action对象执行。

将涡轮增压器添加到JEE Apps

该图显示了每种测试方案的相对吞吐量,深红色的长条表示原始应用程序的吞吐量值,其他长条表示不同角色池大小的Akka应用程序的吞吐量。

  • Akka Typed Actor的每秒吞吐量比原始DayTrader应用程序(对于较大的actor池大小)要好,并且具有较少的内存使用(尤其是700和300个用户*每个请求2个)。
  • 原始应用程序需要额外的168 MB来处理1400个请求(700个用户,每个请求2个请求),而对于Typed Actor池大小为50个actor的修改后的应用程序,用于服务相同类型请求量的额外内存被观察为104 MB, 提高了38% 对于75和100个类型的actor,观察到额外的内存使用量在126MB-136MB之间。
将涡轮增压器添加到JEE Apps

该图显示了每种测试方案的相对吞吐量,深红色的条表示原始应用程序的吞吐量值,其他条表示不同的参与者池大小使用Akka的应用程序的吞吐量。

使用Jmeter对获取报价的呼叫模拟是在相同的高负载条件下,分别针对300个用户,分别针对100个和200个演员的不同系统和Akka设置进行的,大约需要45分钟。

  • 已观察到,在相同条件下,相对于原始应用程序,将Typed Actor的数量从100增加到200相对可以将吞吐量提高约15%和18%。
  • 还可以观察到,将堆大小增加到1024 MB,并将垃圾回收方法更改为并发标记清除,有助于提高高负载条件下的吞吐量。

方案2 – 4个屏幕–登录,主页,获取报价,购买

尝试了一个由4个用户屏幕组成的更复杂的用例,其中用户将使用四个步骤来完成用例场景。 四个步骤是

  1. 用户通过登录页面登录
  2. 提交登录凭据后,向用户显示主页。
  3. 获取股票的报价,其符号由用户在主页屏幕上输入。
  4. 在每个符号下方提交要购买的数量后,购买股票。

所有请求都使用TradeAction对象为请求提供服务。 TradeAction对象实现TradeService接口。 因此,在这种情况下,也应用了为报价/交易屏幕实现的相同TypedActor模型–在上一种情况下确定的“获取报价”业务情景,而且在TradeAction模块中几乎没有或没有任何更改。

使用Jmeter对包含四个屏幕的用例进行了模拟,为300个具有不同Typed Actor池大小的用户创建了用例。 用户数量设置为在60秒内增加到最多300个用户,并且测试运行了15分钟。

将涡轮增压器添加到JEE Apps

可以观察到,将actor的数量从0增加到300可将吞吐量提高大约8%。

超过300个Typed actor的任何增加都显示出较小的改进。

将涡轮增压器添加到JEE Apps

与原始应用程序的内存使用量相比,使用相同类型的actor的应用程序的峰值内存使用率在相同吞吐量(100个类型化的actor)的情况下提高了约30-40%。

结论

即使进行了简单的更改,运行在标准笔记本电脑上的应用程序仍能够提供更好的吞吐量( + 8% ),并且整体内存使用率下降了38% ,这表明actor模型的效率以及Akka对内存和线程的处理。

测试环境详情

  • 处理器– Intel Core i5-2410M CPU @ 2.30 GHz
  • 内存– 4 GB
  • 操作系统– Windows 7 Enterprise
  • 应用程序服务器– Apache Geronimo v2.2.1
  • 编译器和构建工具– Apache Maven v2.2.1
  • Java版本– 1.7.0_03
  • Akka版本– Akka 2.0.2
  • 数据库– Apache Derby

我们可以做的其他优化:

  • 基于请求模式进行分组的Akka未类型化参与者池。 说一个小池仅满足不那么频繁使用的请求,而一个大池(或多个池)满足更频繁使用的请求(例如获取报价或获取帐户)。 可以基于请求模式更改池大小的比率,以获得更好的吞吐量。
  • 使用actor的PreStart和PostStart函数为数据库添加初始化任务,例如获得连接和关闭连接或任何其他初始化任务。
  • Akka无类型演员,用于并发处理持股,同一帐户和会话的多个报价。
  • 使用Akka actor层次结构,以便有多个级别的actor,而更高级别的supervisor actor将一个任务划分为较小的子任务,并委派给下一级别的子actor。
  • 优化actor系统的Akka调度程序线程池大小。

我想对我的同事Chintu Vijay表示感谢,他进行并运行了测试。

参考: Akka Essentials博客上的JCG合作伙伴 Munish K Gupta 向JEE Apps添加了涡轮增压器

翻译自: https://www.javacodegeeks.com/2013/01/adding-turbochargers-to-jee-apps.html

相关文章: