门店-中心分布式系统的问题解答

凤舞凰扬 2011-02-15
     刚刚有个网友问我一个问题,我个人觉得这类问题蛮常见,所以将邮件及我的回复提出来,供大家讨论:
     来信中写道
引用
最近在开发一个呼叫中心的业务系统项目,用于处理订单业务.因为客户网络架构的问题,需要将订单的处理通过两个系统的协作来完成.
    一个系统放在中心服务器上,下面简称:中心系统.
    一个系统会部署到各个门店的一台pc上,下面简称:门店系统.
    目前两个系统通过webservice的方式进行通讯协作,完成一个订单的处理流程.订单处理流程描述如下:
    中心系统进行新增订单,修改订单,取消订单.并将相关信息通过webservice的方式通知门店系统.
    门店系统进行订单状态的修改,如:备餐,送出,结帐.并将订单的状态通过webservice的方式通知中心系统.
    而中心系统进行修改或取消订单的时候,需要判断在业务规则控制下当前订单能否进行当前操作.
    同样门店系统在进行备餐,送出等操作时也需要判断业务规则是否允许进行当前的操作.
  
    这样,两个系统之间的沟通协作处理就会因为网络环境的不稳定性带来以下问题:
    1. 数据不可靠.(中心系统和门店系统均在传送数据的时候出现网络问题,导致数据没有传递过去.而在这种情况下,根据业务环境的需要,还不能做回滚操作.)
    2. 事务无法保障.(这个是webservice处理的典型问题,我也没有好的解决方案).
    3. 并发问题.(如:中心系统在进行订单修改提交的时候,门店送出订单).
    在订单处理的整个过程中会因为上面三个问题,出现各种错综复杂的问题.

    我的回复:
引用
你说的这些问题都是蛮正常的问题,常见的解决方案包括:
1. 如果你的网络环境极其不稳定,可以考虑使用异步流程,比如引入消息服务器(MQ)或者ESB。这样可以确保数据会发送。另外,即使网络环境稳定,也要控制订单数据的大小,最好限制在50K一下,这样,数据因为网络问题产生的影响会降低;第三,在你的服务端,应该启用异步处理流程,将接受订单和处理订单(包括存储数据库等操作)逻辑异步分开,避免业务逻辑事务过长导致webservice响应时间长而引起的问题(也能降低并发访问时的性能问题)。
2. 其实Webservice有事务协议,也就是WS-Transaction,只是目前比较少人用而已。你首先看看你的门店系统和中心系统的 webservice服务器是否支持该协议。另外,如你第一个问题所说,出现问题还不能回滚,说明其实两者并非相同事务,只是需要进行一些补偿事务而已。如果是这样,其实是两个系统不需要担心事务问题,只是需要增加一个机制来确保数据传递的可靠性(而这个又是MQ应用场景的擅长之处了),所以建议你考虑引入MQ。
3. 同一个数据在不同的界面或者用户同时操作带来的数据保证问题,可以使用乐观锁或者悲观锁来解决了,根据你的需要决定。比如如果使用乐观锁,那么有两个字段来描述版本戳(一个描述原先的,一个描述新产生的,比如+1),门店送出订单后,版本戳已经改变,这个时候,中心修改订单想提交就会提示版本冲突,至于是选择放弃策略还是覆盖,或者同步显示在界面让用户修改完全在于你们的设计方案了。这个问题另外有个潜在的约束,在门店提交订单后不能修改(或者与门店修改相同的字段或者中心不能将修改内容发回门店),因为你的数据会存在两个数据库(中心和门店),那样不能完全依靠数据库的锁机制,需要自己做一些补充。
superbug 2011-03-10
1、通讯问题:这种系统引入esb太重了,还是通过mq或者socket来通讯吧。ws方式效率不高,在网络不能保证的情况下,还是不要使用了吧;
2、事务问题:不建议使用分布式事务,主要是效率太低,可以考虑些事务补偿机制;
3、并发问题:消息接受和消息处理分开,要是都在一个线程里肯定堵死。
w412692660 2011-03-12
so,我也认为用ESB,这个场景太重了,不过MQ依然是王道;
1.可以逻辑上解决或者是技术解决;
逻辑解决就是加个异常队列,如果传输失败,加到异常队列(存储方式可以序列话硬盘和内存都可以)中,然后测试网络连接成功时,按顺序发给服务器端,这个实现比较简单,适合应付客户,和开发时间紧,哈哈;我知道俺是很坏的..
技术上就是MQ,这是典型他的使用场景,绝对王道~~~~~
不过估计测试比较麻烦,哈哈,比较耗时间;

2.事务嘛,WS-Transaction顶下楼主,俺也知道一点,似乎没具体实现,我以前也有想过这个问题,但是没找到相关资料,后来搁置,如果楼主知道的话,给俺讲讲呗~~~俺啥都答应你..不过俺是男的....

继续,这个问题啊,同意两位事务补偿的方法,不过是已经解决了传输问题了,那么就不会有相关问题了啊,一共才两个系统交互,用不到补偿机制吧,何况中心系统的设计一般都是让多个系统看成一对一整体

比如说: 2->1, 3->1,4->1;我们就优化4->1,那么4->1就是一个系统整体,来看....
咳..这种垃圾设计...惭愧俺也设计过...那是还是干开发的时候...别介意

因此4-1是一个系统就用不上分布式系统和系统补偿了,嘿嘿,好处就是让技术含量变低,
不会有多个系统连续交互,或者说多系统协作的危险;
ESB设计..那时候觉得,还在云端...二年前的事情了.....不像现在这么普及了;

3.这是普遍问题,解决方法,多如牛毛..随便抛砖头引美玉吧;
主要看他是存数据库,还是缓存里,缓存处理费事点,数据库就简单多了;
1.简单的就是多线程,但是要注意锁机制;
2.事务队列..这个用不用多线程都可以;
3.按客户端的编号(每个客户端的编号),分组进行处理,我就不信,TMD他客户端一台电脑
能同时发来两个修改数据的,除非他黄金圣斗士光速拳...如果她有..你就认命吧

哈哈
凤舞凰扬 2011-03-15
superbug 写道
1、通讯问题:这种系统引入esb太重了,还是通过mq或者socket来通讯吧。ws方式效率不高,在网络不能保证的情况下,还是不要使用了吧;
2、事务问题:不建议使用分布式事务,主要是效率太低,可以考虑些事务补偿机制;
3、并发问题:消息接受和消息处理分开,要是都在一个线程里肯定堵死。

   MQ的场景是异步通信及消息传递,对于流程和应用的整合,MQ是不够的,引入ESB的一个思考是重用其WS的设计,并不重。
   WS效率不高,这并不是一个客观的观点,至少在我所见的许多使用WS的系统中,完全是架构师和设计开发人员的问题了。说实话,我还真没见过几个能把服务设计的人。除非楼主所在的网络环境实在太差,比如门店在国外,只能使用64K/128K ISDN的网络时(呵呵,千万不要笑哦,我就遇到过这样的业务场景的),那就真不建议了。
   分布式事务一般做在系统间,而不是客户端与服务器端,并且在异构系统使用WS-Tran还没见过成熟案例,使用事务补偿是一个比较稳妥的方式。
   提出的并发问题并不是线程并发,而是指并发操作导致的版本冲突问题。呵呵,别看到并发就想到了多线程。
  
凤舞凰扬 2011-03-15
w412692660 写道
so,我也认为用ESB,这个场景太重了,不过MQ依然是王道;
1.可以逻辑上解决或者是技术解决;
逻辑解决就是加个异常队列,如果传输失败,加到异常队列(存储方式可以序列话硬盘和内存都可以)中,然后测试网络连接成功时,按顺序发给服务器端,这个实现比较简单,适合应付客户,和开发时间紧,哈哈;我知道俺是很坏的..
技术上就是MQ,这是典型他的使用场景,绝对王道~~~~~
不过估计测试比较麻烦,哈哈,比较耗时间;

2.事务嘛,WS-Transaction顶下楼主,俺也知道一点,似乎没具体实现,我以前也有想过这个问题,但是没找到相关资料,后来搁置,如果楼主知道的话,给俺讲讲呗~~~俺啥都答应你..不过俺是男的....

继续,这个问题啊,同意两位事务补偿的方法,不过是已经解决了传输问题了,那么就不会有相关问题了啊,一共才两个系统交互,用不到补偿机制吧,何况中心系统的设计一般都是让多个系统看成一对一整体

比如说: 2->1, 3->1,4->1;我们就优化4->1,那么4->1就是一个系统整体,来看....
咳..这种垃圾设计...惭愧俺也设计过...那是还是干开发的时候...别介意

因此4-1是一个系统就用不上分布式系统和系统补偿了,嘿嘿,好处就是让技术含量变低,
不会有多个系统连续交互,或者说多系统协作的危险;
ESB设计..那时候觉得,还在云端...二年前的事情了.....不像现在这么普及了;

3.这是普遍问题,解决方法,多如牛毛..随便抛砖头引美玉吧;
主要看他是存数据库,还是缓存里,缓存处理费事点,数据库就简单多了;
1.简单的就是多线程,但是要注意锁机制;
2.事务队列..这个用不用多线程都可以;
3.按客户端的编号(每个客户端的编号),分组进行处理,我就不信,TMD他客户端一台电脑
能同时发来两个修改数据的,除非他黄金圣斗士光速拳...如果她有..你就认命吧

哈哈

  问题1: 使用MQ自然不是问题,但是这样已经将客户端与服务器端的业务行为变得松耦合,反而更像一个数据交换而不是业务交互了。并且,在消息中去封装业务的上下文并不一定是恰当的行为表述,这个是需要讨论的。
  问题2: WS-Transaction已经是一个成熟很多年的规范了,许多产品中都实现了,包括IBM Webshpere/ESB, WebLogic还有开源的OpenESB等。只是很少人懂,更加有很少人用罢了。在国内,能提出完整集成解决方案也怕是没有几个。
  至于事务补偿的问题,原因是在于,客户端和服务器端其实是相对独立的两个系统,它们会对同一个数据(逻辑层面)进行操作和判断,但是在业务层面又需要进行事务逻辑,所以才会需要事务补偿机制(或者通过分布式事务确保在同一事务下)。
  最后一个,这跟线程是没啥关系的,一个在客户端改,一个在服务端改,完全是独立的两个进程,所以这里的锁并不是线程的同步锁,而是数据的锁(悲观或乐观)。
w412692660 2011-03-15
首先,一个机器在一个时间点只能做一件事,而我们的问题是多个机器在一个时间点处理同一批数据;(修改一个表的数据)

这样的话,这样就是数据的问题,只要把一个机器的时间点区分开,就可以;
这样我们需要一个验证措施+简单的状态机+队列实现;
状态机是预定,售出,未售出;

凤舞凰扬 2011-03-16
w412692660 写道

首先,一个机器在一个时间点只能做一件事,而我们的问题是多个机器在一个时间点处理同一批数据;(修改一个表的数据)

这样的话,这样就是数据的问题,只要把一个机器的时间点区分开,就可以;
这样我们需要一个验证措施+简单的状态机+队列实现;
状态机是预定,售出,未售出;

   别又谈到时间点了,呵呵,和时间点是没啥关系的(否则又扯到线程问题了)。问题更加不是多台机器对同一个表操作(那样更加可以简单到使用数据库的事务来保证了)。
   问题是存在多个用户(当然也会扯到时间,但不是时间点的概念),用户理解成系统也好,机器也好,进程也好,会对同一个逻辑数据(不是数据库的表,而是各自内部的数据,但是在逻辑层面是同一个数据)进行操作,然后进行识别和处理的问题。就像,将一份调查表复印成两份,两个人写,如果各自只写自己部分,自然合并不是问题,如果写的东西相互冲突,则就必须保证逻辑上的统一了。
w412692660 2011-03-17
恩,明白您的意思;
当然这是数据不统一的问题;
可是这样在业务上能够说得通吗,两个人做同一个业务,修改的却是两份数据;
这些正是我们要规避的情况,我觉得应该是找出出现问题的地方;
首先,照您的叙述随便画了一张大体的图


您之前有这样说过:
中心系统进行新增订单,修改订单,取消订单.并将相关信息通过webservice的方式通知门店系统.
门店系统进行订单状态的修改,如:备餐,送出,结帐.并将订单的状态通过webservice的方式通知中心系统.
而中心系统进行修改或取消订单的时候,需要判断在业务规则控制下当前订单能否进行当前操作.
同样门店系统在进行备餐,送出等操作时也需要判断业务规则是否允许进行当前的操作.

我们脱离时间点,脱离一切,我一直觉得应该在"状态机"这里应该是同步操作或者队列实现,这样可以确定数据的唯一性,防止两份数据的状况;

上面我们再次扔开,换套思路去思考:
从业务上来讲,一共这几个状态的变化,怎么会有两套数据来处理呢,
无非多用户操那个作一份数据问题,简单的多对一的关系,每个用户拥有对数据的修改操作,
无非就是怕数据出现脏数据,那么我们想办法让数据是唯一性应该就可以;
这个数据可以不是一个表的,但是我们可以用逻辑上算法或者SQL去验证数据的正确性;
甚至,他是在缓存中修改,我们维护缓存都是可以的;,重点是在"一"的地方,进行同步


Alexyin_sc 2011-05-11
LZ所述问题实际上是属于事务工作流所讨论的范围。
“中心系统进行修改或取消订单的时候,需要判断在业务规则控制下当前订单能否进行当前操作.
  同样门店系统在进行备餐,送出等操作时也需要判断业务规则是否允许进行当前的操作. ”
这样的运行时控制有些问题,应该修改为:中心系统用户在特定时刻向引擎申请对订单的操作,引擎根据上下文返回用户可以发出的操作,如果其中包含修改或者取消操作,那么说明是允许的。在实际发出操作后,引擎应该再次验证操作的合法性(因为在申请操作和发出操作期间存在其它系统用户对订单进行操作的可能)。运行时,如果所有与订单相关的用户都照这种方式进行操作时,结果将不会产生冲突,或者说订单事务将正确执行。

  顺便说一句,目前BPEL描述的过程模型还达不到这样的要求,WS-Transaction是一种基于补偿的事务模型,目前所能解决的问题范围还没有完全覆盖LZ所述问题。MQ只是应用层面上的一种具有可靠性保证的解决方法,与工作流事务几乎是正交的。
  工作流事务有些复杂,但大多数情况下又必不可少,即使是OA,有些也涉及事务问题,现在关于这一问题的讨论已经引起相当的重视,LZ可以看看相关资料。
凤舞凰扬 2011-05-22
w412692660 写道
恩,明白您的意思;
当然这是数据不统一的问题;
可是这样在业务上能够说得通吗,两个人做同一个业务,修改的却是两份数据;
这些正是我们要规避的情况,我觉得应该是找出出现问题的地方;
首先,照您的叙述随便画了一张大体的图


您之前有这样说过:
中心系统进行新增订单,修改订单,取消订单.并将相关信息通过webservice的方式通知门店系统.
门店系统进行订单状态的修改,如:备餐,送出,结帐.并将订单的状态通过webservice的方式通知中心系统.
而中心系统进行修改或取消订单的时候,需要判断在业务规则控制下当前订单能否进行当前操作.
同样门店系统在进行备餐,送出等操作时也需要判断业务规则是否允许进行当前的操作.

我们脱离时间点,脱离一切,我一直觉得应该在"状态机"这里应该是同步操作或者队列实现,这样可以确定数据的唯一性,防止两份数据的状况;

上面我们再次扔开,换套思路去思考:
从业务上来讲,一共这几个状态的变化,怎么会有两套数据来处理呢,
无非多用户操那个作一份数据问题,简单的多对一的关系,每个用户拥有对数据的修改操作,
无非就是怕数据出现脏数据,那么我们想办法让数据是唯一性应该就可以;
这个数据可以不是一个表的,但是我们可以用逻辑上算法或者SQL去验证数据的正确性;
甚至,他是在缓存中修改,我们维护缓存都是可以的;,重点是在"一"的地方,进行同步



   你想回避操作两份数据的问题,可我要告诉你,回避不了,也不能回避。在处于互联网的异构分布式系统下(包括我们最为常见带Rich Client),数据以多个物理形式存在是非常正常的(包括集群系统也是一样,多个JVM也会有多个不同的数据)。你要清楚的是,逻辑上的一份数据和物理上的一份数据是两码事。
   我们需要做的是通过系统的检查和处理,确保物理上的多个数据不会对逻辑产生大的影响。
Global site tag (gtag.js) - Google Analytics