﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-笨笨的思想片断-随笔分类-Java Service Request Broker</title><link>http://www.blogjava.net/zhugf000/category/20696.html</link><description>零碎片断，杂七杂八。</description><language>zh-cn</language><lastBuildDate>Sat, 22 Dec 2007 03:08:52 GMT</lastBuildDate><pubDate>Sat, 22 Dec 2007 03:08:52 GMT</pubDate><ttl>60</ttl><item><title>JSRB设计思想－无状态的,粗粒度的SERVICE</title><link>http://www.blogjava.net/zhugf000/archive/2007/12/20/168346.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Thu, 20 Dec 2007 06:23:00 GMT</pubDate><guid>http://www.blogjava.net/zhugf000/archive/2007/12/20/168346.html</guid><wfw:comment>http://www.blogjava.net/zhugf000/comments/168346.html</wfw:comment><comments>http://www.blogjava.net/zhugf000/archive/2007/12/20/168346.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/zhugf000/comments/commentRss/168346.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhugf000/services/trackbacks/168346.html</trackback:ping><description><![CDATA[<h1>JSRB设计思想－无状态的,粗粒度的SERVICE</h1>
出于提高性能和负载均衡实现的考虑，JSRB 采取了无状态的，粗粒度的SERVICE请求和响应机制。<br />
该思想与有状态的ORB(如CORBA或EJB Container)的设计思想截然相反.本文将详述原因.<br />
<br />
<br />
<h2>JSRB定位与想要解决的问题</h2>
JSRB定位于传统的SERVICE REQUEST BROKER地位,就是原始意义上的中间件的位置: 负责将大量客户端(N千或N万)的请求,排队到几十或几百个的请求处理进程(线程)中,最优化的使用系统资源,从而达到吞吐量最大化的目的.<br />
从这个角度来看, EJB Container和CORBA ORB是标准的中间件. Java Web Container由于内建了线程池,也算是中间件(前端协议HTTP,后端协议是JDBC).<br />
<br />
<h2>无状态vs有状态,远程调用的选择.</h2>
有状态要求服务器在远程调用之间保存对应客户端的Session数据,这种设计思想会简化程序代码,有助于将分布式的程序写得更<strong><span style="color: #ff0000;"><span style="color: red;">像</span></span></strong>非分布式程序.<br />
<br />
但是在某些情况下,这种设计会带来严重的性能问题.在金融的在线交易系统中,业务系统需要处理十万至千万级别的用户信息(例如网银系统),而中间件服务器较为合适的session池数量不过万.要在中间件服务器的JVM内存中处理如此巨量的数据,肯定会将系统撑爆; 而如果存储大部分数据到硬盘(钝化技术)来应对,则就会面临IO性能还不如 RDBMS 的窘境. RDBMS 在目前阶段始终是最快速的数据存储方案.<br />
<br />
当业务系统面临大数据量的问题时,需要采用应用相关的解决方案(数据分区,存储过程等等)解决.将问题推给应用服务器固然方便,但是却会带来系统的性能和可扩展性的问题.远程调用的代价本来就很大,不必要让ORB再承担session数据的重担了.与之相反,无状态的远程调用在可扩展性和负载均衡方面的实现要简单得多,也没有session迁移的问题.<br />
<br />
<br />
<h2>SERVICE的粒度问题</h2>
SERVICE远程调用的粒度需要粗一点,在保证SERVICE可重用的前提下,应该尽量减少SERVICE的调用次数, 因为SERVICE的调用开销非常大(一般的远程调用都是以毫秒记,而普通方法的执行时间是以微秒或纳秒为单位的). <br />
有状态SERVICE的一个副作用就是容易出现过细粒度的设计(同时由于Stub/Skeleton的生成很方便,这种设计就更加容易出现了),导致交互次数过多,会严重降低业务系统的性能.<br />
<br />
这方面一个鲜明的对比是大型机的智能终端和telnet协议.智能终端只有等到用户填充完一个表单并确认发送后,才会将请求数据发送到主机,并且自行解释和显示主机返回的数据(非常像Broswer/HTTP), 而telnet协议则将每个按键事件发送到主机,主机处理保存有所有的session数据. 主机可以毫不费劲的处理N万个并发的客户端,而UNIX主机在连接了几千个telnet客户端后,自身的正常运行都会出问题了.<br />
<br />
顺便说一句, 类似的, 从个人项目经历来看, 由于 Hibernate 隐藏JDBC调用很成功,查询或更新数据库非常方便, 程序员就很容易滥用; 有可能导致程序从逻辑上来看毫无问题, 但是运行起来却出现性能低下, 并且这种性能问题还很难改正(性能低下是由于数据库查询过多引起的,要调整的代码遍布整个项目).<br />
<br />
<br />
<h2>其它</h2>
<ol>
    <li>本文的一些思想来源于MidWay(midway.sourceforge.net)和个人的项目经验,仅为一家之言.</li>
    <li>大型项目(企业级)和小项目(部门级)的区别主要就在于,大项目在各个阶段都要将非功能性的要求(性能,容错,恢复,分布式,响应时间,事务等等)放在设计/实现/测试首要考虑的位置,而小项目则几乎无需考虑这样的问题.</li>
    <li>本文和JSRB主要集中在真正的中间层( Service/Object Request Broker/EJB Container).<br />
    </li>
</ol>
<br />
<br />
<img src ="http://www.blogjava.net/zhugf000/aggbug/168346.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhugf000/" target="_blank">笨笨</a> 2007-12-20 14:23 <a href="http://www.blogjava.net/zhugf000/archive/2007/12/20/168346.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java Service Request Broker简介</title><link>http://www.blogjava.net/zhugf000/archive/2007/12/12/167098.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Tue, 11 Dec 2007 16:15:00 GMT</pubDate><guid>http://www.blogjava.net/zhugf000/archive/2007/12/12/167098.html</guid><wfw:comment>http://www.blogjava.net/zhugf000/comments/167098.html</wfw:comment><comments>http://www.blogjava.net/zhugf000/archive/2007/12/12/167098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhugf000/comments/commentRss/167098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhugf000/services/trackbacks/167098.html</trackback:ping><description><![CDATA[<h1>Java Service Request Broker 简介</h1>
Java Service Request Broker(JSRB)是一个 Java/C/C++ 的开源项目<br />
Project URL http://jsrb.sourceforge.net<br />
<br />
项目目标按照优先顺序依次是:<br />
1 高效,透明的通讯框架,屏蔽本地/远程网络架构的复杂性(高效来源于基于poll/epoll的NIO通讯框架,透明来源于多个JSRB Server之间的动态级联机制).<br />
2 高效率,稳定的服务请求处理机制(高效来源于服务端为C语言实现,稳定来源于对服务进程的不间断监控和自动重启动机制)<br />
3 分布式事务处理能力(JSRB 作为分布式事务管理器,初步实现了DTP XA协议,还在开发过程中).<br />
4 客户端语言中立(语言无关通讯协议,客户端提供Java或C API库).<br />
<br />
JSRB 大致架构如下:<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/jsrb/jsrb_overview.gif" height="543" width="796" /><br />
<br />
<br />
<h2>JSRB SERVICE 特性/访问方式</h2>
1 SERVICE 无状态,通过二进制数据传递输入输出数据<br />
2 运行时,可以有多个SERVICE实现进程, JSRB会平衡调度这些进程.<br />
<br />
SERVICE支持同步/异步两种访问方式:<br />
SERVICE之间也支持forward和嵌套调用两种方式<br />
<br />
同步访问SERVICE: <br />
<em><span style="font-family: Courier;">Response Data = JsrbConection.syncCall("SERVICE NAME",Request Data);</span></em><br />
当客户端从syncCall中返回时,它已经获得SERVICE的返回数据<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/jsrb/jsrb_call_svc.gif" height="310" width="412" /><br />
<br />
<br />
异步访问SERVICE<br />
<em><span style="font-family: Courier;">long key = JsrbConnection.asyncCall("SERVICE",Request Data);<br />
...<br />
Response Data = JsrbConnection.fetchReply(key);<br />
</span></em>客户端可以提交服务请求后,过一段时间再去尝试获取数据, 便衣客户端同时提交多个服务请求,增加并发性.<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/jsrb/jsrb_acall_svc.gif" height="310" width="412" /><br />
<br />
<br />
<br />
SERVICE FORWARD<br />
客户端访问SVC1, SVC1完成后将该请求forward到SVC2, SVC2完成后直接返回客户端数据.<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/jsrb/jsrb_forward_svc.gif" height="310" width="412" /><br />
<br />
<br />
SERVICE的嵌套调用<br />
SVC1 调用SVC2 并获得SVC2的返回数据.<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/jsrb/jsrb_nest_svc.gif" height="310" width="668" /><br />
<br />
<br />
<br />
<br />
<br />
<br />
一般问题:<br />
1 为什么会选择用Java 实现Service Request Broker<br />
答: Java跟C语言相比, 代码执行速度其实并不慢. 我们一般感觉J2EE 应用慢,主要是由于IO(特别是socket和JDBC)慢造成的.<br />
Java 在多线程编程, 开发的方便性方面比C/C++强.<br />
JSRB在实现过程中,自行定义和实现了一套NIO框架, 增加了对于Linux epoll(Edge Triggered Mode)的支持, 同时为了实现与C进程的高效通讯,自行实现了Sysv IPC和创建子进程方面的Native代码.<br />
<br />
<br />
2 为什么要用C实现业务代码,作为Service的实现语言.<br />
从企业端的应用来看, 企业应用必定要跟数据库打交道, 实际上C语言访问数据库要比Java访问数据库快1到两个数量级. 甚至可以说, J2EE应用响应的大部分的延迟时间都耗费在JDBC上. <br />
从大型项目的实施经验来看, 将这部分代码放在C进程中, 尽管要多付出通讯方面的代价,总体还是要比纯Java的方案快得多.<br />
<br />
<br />
3 为什么分布式事务的优先级最低<br />
从大型项目的实施经验来看, 分布式事务由于运行代价过高, 业务系统中用到的概览很小(直接用数据库的事务). 对于CICS/TUXEDO应用而言,首先还是将CICS/TUXEDO 作为一个高效/稳定的通讯和服务请求处理排队框架来用.<br />
如果真要有分布式的交易的需求,一般采用流水对帐+冲正处理方式解决.<br />
<br />
<br />
4 为什么选择无状态方式实现SERVICE<br />
无状态是提高并发效率, 实现透明故障迁移的最佳方式. Server端资源有限,为并发的成千上万个用户同时维护状态是非常困难的,这样也会造成集群实现的困难.<br />
由于Client端是有状态的,所以这在实现上其实问题不大.<br />
<br />
<br />
<br />
今后得空还会慢慢写更多文档介绍JSRB的一些组件的实现方式和特性.<br />
<br />
<br />
<img src ="http://www.blogjava.net/zhugf000/aggbug/167098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhugf000/" target="_blank">笨笨</a> 2007-12-12 00:15 <a href="http://www.blogjava.net/zhugf000/archive/2007/12/12/167098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DTP/XA 规范及XA API调用研究</title><link>http://www.blogjava.net/zhugf000/archive/2007/12/06/165645.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Thu, 06 Dec 2007 06:07:00 GMT</pubDate><guid>http://www.blogjava.net/zhugf000/archive/2007/12/06/165645.html</guid><wfw:comment>http://www.blogjava.net/zhugf000/comments/165645.html</wfw:comment><comments>http://www.blogjava.net/zhugf000/archive/2007/12/06/165645.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/zhugf000/comments/commentRss/165645.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhugf000/services/trackbacks/165645.html</trackback:ping><description><![CDATA[DTP/XA 规范及XA API调用研究<br />
<br />
分布式事务(Distributed Transaction Processing/XA)规范是一个业界标准规范，它定义了分布式事务中各方角色和标准两阶段提交的协议规范(XA Protocol)，该规范为广为业界所支持(CICS/TUXEDO/Enica，后来的OTS/JTS规范以及微软的MTS的莫不源于此。<br />
<br />
XA规范中关键角色简述如下<br />
AP: 客户应用程序，负责连接TM,RM，使用RM的提供的API访问和更改数据，声明分布式事务的开始和结束阶段点(Transaction Demarcation)。<br />
TM: 事务管理器，负责管理、协调、准备和提交分布式事务，对AP的接口标准为TX接口, 并非所有的 TM 实现都遵循这个标准, 但是都会提供类似的接口函数.<br />
RM: 资源管理器，在AP访问数据时，关联事务相关的数据修改，并根据TM的命令提交或回滚数据修改，通常为数据库, IBM MQSeries实现了RM接口。<br />
RM分为静态和动态两种,静态RM需要TM明确调用xa_start/xa_end关联事务与RM的联系. 动态RM在数据发生更改时,会自动回调TM提供的ax_reg/ax_unreg函数,动态关联到当前活动的分布式事务中.<br />
<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/zhugf000/xa/aptmrm.gif" border="0" height="225" width="462" /><br />
<br />
XA API中定义的xa_****和ax_****函数。<br />
ax_reg&nbsp; &nbsp;&nbsp;&nbsp; 向事务管理器注册资源管理器。<br />
ax_unreg &nbsp;&nbsp;&nbsp; 向事务管理器取消注册资源管理器。<br />
xa_close &nbsp;&nbsp;&nbsp; 终止应用程序对资源管理器的使用。<br />
xa_commit &nbsp;&nbsp;&nbsp; 通知资源管理器提交事务分支。<br />
xa_complete &nbsp;&nbsp;&nbsp; 测试异步 xa 操作是否完成。<br />
xa_end &nbsp;&nbsp;&nbsp; 取消线程与事务分支的关联。<br />
xa_forget &nbsp;&nbsp;&nbsp; 允许资源管理器丢弃启发完成的事务分支的信息。<br />
xa_open &nbsp;&nbsp;&nbsp; 初始化资源管理器，供应用程序使用。<br />
xa_prepare &nbsp;&nbsp;&nbsp; 请求资源管理器准备提交事务分支。<br />
xa_recover &nbsp;&nbsp;&nbsp; 获取资源管理器已准备或启发完成的事务标识符 (XID) 列表。<br />
xa_rollback &nbsp;&nbsp;&nbsp; 通知资源管理器回滚事务分支。<br />
xa_start &nbsp;&nbsp;&nbsp; 启动或恢复事务分支；将 XID 与资源管理器请求线程的未来工作关联。<br />
<br />
ax_ 例程可让资源管理器调用事务管理器；所有事务管理器必须提供这些例程。在 DTP 环境中操作时，xa_ 例程由资源管理器提供，并由事务管理器调用。当应用程序调用事务管理器以启动全局事务时，事务管理器可以使用 xa_ 接口通知事务分支的资源管理器。<br />
<br />
分布式事务各个阶段相关API调用如下：<br />
1 AP 通知TM打开RM连接， AP--&gt;TM tx_open()<br />
TM 会在该函数中调用RM提供的xa_open函数，打开到RM的连接。<br />
在TUXEDO SERVICE中，需要在tpsvrinit()函数中调用tpopen()函数完成这项工作。<br />
<br />
2&nbsp;AP 声明事务开始 AP--&gt;TM tx_begin()<br />
在声明后，该线程后续对RM的所有访问和更新均属于该事务。<br />
对于static RM, TM 需要调用xa_start() 明确关联事务和RM。<br />
<br />
在TUXEDO SERVICE/CLIENT中，tpbegin()函数完成类似工作.<br />
当TUXEDO SERVICE被调用时, 如果已经处于事务中, TUXEDO 会自动调用与SERVICE关联的RM的xa_start()函数(只对于 static RM).<br />
<br />
3&nbsp;AP访问RM，使用RM规定的API访问，XA规范未作定义。<br />
对于dynamic RM, 如果访问时发生了数据更改,例如提交一个UPDATE SQL 语句,&nbsp; RM会自动回调TM的ax_reg函数关联到当前事务.<br />
<br />
4 AP声明事务分支结束<br />
在TUXEDO SERVICE调用完成后,&nbsp;自动调用 RM 的xa_end()函数(对于static RM和未调用ax_unreg的dynamic RM)。<br />
<br />
说明: 根据业务需要,上述2-4步骤会在不同的进程(TUXEDO SERVICE)中重复出现, 只要事务ID( Global XID )相同,这多个事务分支(Branch) 均被认为属于同一个事务.<br />
<br />
5&nbsp;AP 要求提交或回滚事务(TM tx_commit/tx_rollback )<br />
AP要求提交事务时, TM 需要检查事务状态, 确定事务并未标记为MARKED_ROLLBACK(只能回滚),否则会回滚并报告错误.<br />
<br />
TUXEDO CLIENT/SERVICE 调用 tpcommit/tpabort 提交或回滚事务.<br />
在TUXEDO中,由于实现的原因,所有xa_prepare/xa_commit/xa_rollback都是由单独的TMS进程发起调用的, TUXEDO SERVICE 进程不会发起相关调用.<br />
TUXEDO配置文件中,每个TUXEDO SERVICE GROUP可以关联一个RM和多个TMS,每个GROUP内的SERVICE 进程和TMS进程启动时都会使用相同的 XA OpenInfo String打开到RM的连接.<br />
<br />
<br />
标准两阶段事务提交过程:<br />
1 (准备)更改事务状态为PREPARING, 依次调用事务关联RM的xa_prepare(), 任意RM返回错误则进入回滚过程, RM都PREPARE完成事务状态改变为PREPARED.<br />
2 (提交)更改事务状态为COMMITTING, 记录事务日志到硬盘中, 依次调用RM的xa_commit方法,再更新事务日志, 更改事务状态为COMMITTED.事务提交完成.<br />
3 (回滚)更改事务状态为ROLLING_BACK, 依次调用事务关联RM的的xa_rollback,更改事务状态为ROLLED_BACK<br />
<br />
简化一阶段事务提交过程:<br />
1&nbsp;(提交)更改事务状态为COMMITTING, 记录事务日志到硬盘中, 调用RM的xa_commit(TMONEPHASE)方法,再更新事务日志, 更改事务状态为COMMITTED.事务提交完成.<br />
<br />
启发式事务提交和回滚:<br />
部分RM支持启发式提交或回滚, xa_commit/xa_rollback 返回时,可能会返回XA_HEUR***的值, 表明RM执行了启发式优化.<br />
此时TM需要后续调用RM的xa_forget(), 让RM彻底释放该事务相关的资源.<br />
<br />
<br />
目前JSRB(Java Service Request Broker)已经部分实现上述TM的功能, 项目继续进展中...: http://jsrb.sourceforge.net<br />
<br />
参考资料：<br />
Distributed Transaction Processing_ The XA Specification<br />
<br />
IBM WebSphere 开发者技术期刊: 在中间件环境中配置和使用 XA<br />
http://www.ibm.com/developerworks/cn/websphere/techjournal/0704_sood/0704_sood.html<br />
<br />
XA接口的一阶段提交与两阶段提交有何区别？
<br />
http://www-1.ibm.com/support/docview.wss?uid=csc148256d65004dc82448256d65004276f0<br />
<br />
<img src ="http://www.blogjava.net/zhugf000/aggbug/165645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhugf000/" target="_blank">笨笨</a> 2007-12-06 14:07 <a href="http://www.blogjava.net/zhugf000/archive/2007/12/06/165645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>