Hessian分布式事务那些破事儿
小僧左思右想实在找不到一个妥协的解决Hessian的问题。
假如:一个web应用程序访问的方法调用了四个hessian,简称h1,h2,h3,h4
假设 h1,h2 操作成功,但是由于某些原因(程序bug或者数据库问题,手动错误修改了数据)导致h3 操作失败。
这里的h3操作失败应该让h1,h2两 个操作回滚,并且通知h4 在执行过程中出现了问题(或者直接return) 。后一个过程好解决,让h1,h2回滚怎么办?
hessian没有事务,直接调用hessian也不能用jta,因为hessian和webservice一样都是无状态的。如果是让直接其他操作库的话,JOTM做多库事务同步和回滚,可以做到不管是哪个环节出问题多个事务同时回滚。但是调用hessian或者webservice 直接调用不行,调用的hessian 是在另外一个系统完成的,数据库也可能是不同的数据库,不同的机器,甚至这个hessian的调用操作了几个库,hessian 最多给返回一个值,事务不在客户端!!!
小僧只想到一个最搓的方法,应用程序调用XXXAction.aMethod() 一次调用的四个hessian,h1,h2,h3,h4.
其中h1,h2,h3,h4为预提交方法 h11,h21,h31,h41为二次提交方法(不可回滚),当然事务要在全局变量,调用的时候生成,
aMethod 刚开始就在hessian.properties中写一个XXXAction.aMethod.state=0
然后调用h1,h1在h1中有自己的事务 aMethod要知道h1 的情况,h1 第一阶段提交(预提交)如果成功可以为XXXAction.aMethod.state=y1- 如果是失败就key值为y10- 后面一个0表示失败。
h2,h3,h4相同。aMethod中判断XXXAction.aMethod.state的值为y1-y2-y3-y4-的时候才去调用二次提交方法。否则调用h12,h22,h32,h42 各自的回滚方法。
hessian.properties做一个共享 最好是xml存储和解析 根节点是用户名 下面是各个状态值,每次请求的时候如果有了 就清空,没就创建该用户的节点结构。通过NFS 共享此文件,做到一个桥梁作用。
发现这样每一个hessian调用要做四件事情 1 写共享文件中每个方法的预提交状态。服务端三个方法:2 第一次提交方法,3 回滚方法, 4第二次提交方法。
hessian类似于webservice,例如:做一个处理返回给客户端的时候判断下调用服务端方法时间如果调用时间超过3s 就直接返回y10- 防止一直等待下去。一个操作超过3s等待就不让提交。
而事务必须是是全局变量,第一次请求,第二次请求,回滚方法用的事务必须是同一个事务,否则无法完成。
那服务端可以让Transition可以是一个吗? 静态的Transition? 如果Connection 是静态的那服务器也只有死的份了。不能考虑这个了。
网上没有找到针对hessian事务的处理,而这位了做到事务又增加了很多的麻烦,那么最妥协的方法也只能是用jta,也必须能对多个库直接操作。而不能只可以调用hessian,这样事务无法控制!
颗粒度太细了也会引发一些问题,设计是一个严重的问题,看来读写分离是更好的设计,而不是模块分库。
那么设计应该是写库一个,jta控制,读库N个库,同步到不同的模块库.
1 读写分离
为什么速写分离会更好?一方面读写的比例很明显,写和读的比例至少也是1:10.而读写都在一起的话,数据库性能明显降低,写的时候数据库表中行会加锁,在MS Server中甚至去锁整个表,那么读就得等待拿得锁,增删改查都在一起的话,主要是因为锁,那么没有锁好不?那数据会脏读,脏写。而读写分离做到了读就用读库,写就在写库,大大将少了因为锁而等待的时间。那么写库会面临日益增多的数据写数据自然的效率自然会慢慢降下来。
解决:a 写库-历史库 b 读库-多个库
写库集中写,但是面临数据大的时候未免会导致写的速度降下来,那么弄历史库,一旦表的数据超过了xxx的量就移入历 史库去,分历史库和操作库,历史库可以分年的 分月的。读库根据各个模块进行拆分,可以拆分到很细的模块。
2 web server负载
3 jta-分布式事务。事务可以两阶段提交,如果第二阶段提交出现问题了怎么办?比如预提交成功,真正提交的第一个操作成功,第二个失败,那么真正提交也应该回滚。数据库事务回滚是基于日志的,第二次提交成功了啊,但是其他的操作不在这个库,怎么办?可以用savePoint,在第二阶段提交之前就savePoint,一旦第二阶段提交任何环节出现问题了,就回滚。
从这里也暴漏了我们架构出现的问题,感谢刘总和淘宝架构师给的建议,非常感谢。