随笔 - 119  文章 - 290  trackbacks - 0

博客搬家了哦,请移步
叫我abc

常用链接

留言簿(12)

随笔分类

我的博客

搜索

  •  

积分与排名

  • 积分 - 302361
  • 排名 - 84

最新评论

阅读排行榜

全文来源: http://www.cppblog.com/darkdestiny/

1.服务器间的异步事务
上个月,最有收获的事情,大概就是这个了吧。
几个不同功能的服务器相互协作以实现一个角色登录场景的需求。这是一个异步的过程,异步令人讨厌的地方就是,他不是一个服务器能够顺序完成的事情,而你却不知道什么时候什么服务器会因为太阳风的异常活动而崩溃。如果你假设所有服务器都是稳定的,他们最多只有80%的时间如你所愿,剩下的就是boss的咆哮(2/8原则)。

一开始我并不了解异步事务的概念,所以角色登录场景的流程写得非常松散。用A,B,C,D合作烤苹果比方的话,就是
*A抓起一个苹果,交给B
*B把苹果切开,交给C
*C在苹果片抹上胡椒,交给D
*D把苹果烤熟
以人类的眼光看这个流程,是一个完美的流水线,而且中途谁因为天热而蒸发掉的话,大家也都很清楚的知道而作出恰当的反馈(暂停流水线,等待信春哥的某人满血满buff原地复活等等)。
但是这样的流程却完全不适合映射到程序上——多个服务器之间对彼此行为和状态的详细跟踪,是一件多么困难,复杂,不通用,吃力不讨好的事情。那么在程序上,烤苹果的工人之间就不是在一个大开间畅聊,而是被关在一个小黑屋里孤独的工作,彼此不能看到,并且传递苹果的空间非常不稳定,工人必须时刻用一只手等苹果,否则苹果就会变成香蕉。工头Master(M)为节省成本没有开空调,所以偶尔有人蒸发又复活什么的,但是流水线不会停下来,100个苹果也就烤出80个左右。

M觉得亏20个苹果没什么,但是因为吃不上苹果而流失的顾客是一个极大的损失。M决定改进流水线,亲自参加烤苹果。
*顾客想吃烤苹果,M向A索要苹果
*A抓起一个苹果,交给M
*M检查苹果,把苹果交给B
*B把苹果切开,交给M
*M把苹果片交给C
*C在苹果片抹上胡椒,交给M
*M把苹果交给D
*D把苹果烤熟,交给M
此时,M把热腾腾的烤苹果交给了顾客,顾客因为热腾腾引起了不好的联想,走掉了。
这一次,M对顾客要吃的每一个苹果都贴上一个唯一标签,设置一个5秒超时,如果超时则重新为顾客烤苹果,原来烤了一半的直接扔掉。

前面铺垫了那么多,其实就是想说明一件事情:处理服务器间的异步事务,最好设置一个master服务器,集中控制每一个步骤的运作,为每一个事务设置一个超时;在事务失败或者超时后作出反馈。

2.异步事务的实现方式
2.1状态机
第一次我是用状态机实现的,master等待每个worker反馈的过程作为一个状态,worker的反馈作为一个trigger,迫使master跳转到下个事务状态,执行step,接着等待新的反馈,直到事务结束。
基于状态机的形式听起来很直观,但实际上用起来并非如此顺手,总是觉得有些违和,修改的时候总会遭遇一些复杂情景,特别是在中间修改事务步骤的时候。
其中我所犯的一个错误就是给予每一个步骤设置设置步骤超时的机制,这非常不好做,容易出bug,最后才意识到一个事务一个超时的规则。

2.2C协程
协程可以认为是需要手动进行调度的线程,协程不像线程那样由OS调度,协程何时运行何时挂起都是由程序员控制的。
C的体系下是没有协程的,虽然找到了一些C协程的库,可是接口和实现都相当不雅。唯一一个我认可的,是一个基于少量多线程来实现协程功能的库,可是在服务器上使用多线程是谨慎事项之一。
其他语言体系下的同学,如果有好的协程支持(最好是基于多堆栈的),大可放心使用。

2.3lua协程
这是最后实现并决定的方式,如果今后不改变的话。lua支持多堆栈,所以lua有协程是理所当然的了。
用协程实现事务有哪些好处呢?可以将整个异步事务的代码写在一个函数中,就像一个程序内的同步操作一样,这是一件多么美好而具有可读性的事情,相比状态机而言。
如何用协程实现事务呢?执行一个事务时,协程函数运行,执行step,然后在等待反馈的时候挂起;master收到反馈以后,resume协程,在上次挂起的地方继续往下运行,执行下一个step,等待新反馈而挂起;如此反复,直至完成。

posted on 2009-07-05 18:46 LOGOS 阅读(5103) 评论(8)  编辑 收藏 引用 所属分类: month-flow

FeedBack:
# re: 服务器间异步事务处理 2009-07-07 22:14 懒人
lua thread用在处理服务器的对话框机制不错,等待一个用户输入,开启下一段文字  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-08 17:44 developer
博主 能详细介绍一下服务器异步事务的部分吗,我刚好也在做相关的内容,希望可以学习一下,谢谢了  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-08 19:44 LOGOS
@developer
我觉得我把重点的地方都说出来了。
不知道你指的是什么内容
  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-09 18:28 developer
是这样,多服务器间的异步事务会存在并行处理的情况,这时候可能需要多次分别提交,这样状态就会比较难控制.

比如,Server A做了一些数据库操作(没有提交),然后更新master的msg 1状态,等待server B的处理结果;Server B被触发后也执行了一些数据库操作(没有提交),然后更新master的msg 1状态去告诉Server A自己的执行结果;
那么,问题出现了,A和B如何相互确定对方已经成功获取了状态然后提交呢?

场景1: A获得了B的更新状态,于是继续执行并提交数据库,然后再更新通知B也提交,但B获取状态失败并超时回滚了,A却无法回滚数据库了;
场景2:A获得了B的更新状态,于是继续执行,然后再更新通知B提交;B提交后A提交却失败了,而B无法回滚了;

我感觉这种场景下,不管如何处理,总会存在一种场景造成整体事务无法完全回滚的现象!不知道你是如何处理的?

另外,对于状态控制部分,你使用的什么方式?DB还是消息中间件还是。。。?
  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-09 22:37 LOGOS
A或者B的提交操作一旦执行,就无法回滚,是一个非常让人为难的情形。我大概会这么做
场景1:AB合并成一个服务器。不过这可能是现实情况下最做不到的事情。
场景2:事务中,把A需要对数据库进行的操作传给B,由B完成A和B的操作并提交。这在一些情况下还是可以做到的吧。
场景3:事务中,A和B都只是修改临时表,最后由A或者B将临时表的修改写入真表。这也只是针对某些情况。

”另外,状态控制部分,使用什么方式“
这是指什么?是master等待A或者B的某个操作吗?  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-10 09:57 99读书人
不错哦  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-10 11:48 developer
因为是多服务器的分布式事务,所以必然会涉及多个运行在不同主机上的进程和多个DB的数据操作,这种情况下,合并服务器或者不同DB的操作实际应用中都不可行,我觉得唯一的出路还是通过服务器间消息通信来控制各主机的行为,但这个方式的难点就在于,采用何种方式或技巧才能保证消息及时可靠的传递以及如何保证事务完整性。

目前我使用的是Tuxedo的消息中间件来在服务器间传递消息,但易用性和可靠性都不理想,以至于必须得考虑任何一次通信中对方没有接收到消息的情况,这实际又造成任何一方都无法最终确认对方的执行结果;
你文中说的master通过状态机来调度,我觉得也可以算作是通过状态来传递消息,这个机制你具体是如何实现的呢?

我对协程的应用不熟悉,感觉好像是一个比较优雅的解决办法,但它应该是不可以跨服务器远程调用吧?你是如何应用lua的协程呢?  回复  更多评论
  
# re: 服务器间异步事务处理 2009-07-10 16:09 LOGOS
通信总是不可靠的,所以发出一条消息后等待回执无非就3种情况
1.超时
2.回执
3.发出回执的服务器崩溃
如果能处理到这三种消息,基本上就没什么疏漏了。
比较微妙的是回执服务器崩溃的情况,需要去检查操作是否真的被执行了。

事务,被称为transaction,必须能做到在任何一点上rollback。
在我的想法里,只有master知晓事务的状态,并确认ABCD的执行结果。ABCD只负责do-echo。
状态机和协程只是用来在master上维护事务状态和步骤的一种方案,也许还有别的方案的。

状态机就是设计模式里的那个。
协程很优雅,不可以远程调用。
这两个东西,往细里说就大了。  回复  更多评论
  
# re: 服务器间异步事务处理 2012-05-29 13:40 Midnight
我觉得楼主光说理论没用  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理