zoukankan      html  css  js  c++  java
  • 分布式架构下的mvc 异步controller ajax comet 长连接

    这两天光干这事了。遇到各种恶心问题,总结一下

    mvc异步controller中的异步action成对出现以

    public void xxxAsync()

    public ActionResult xxxCompleted(object result)

    形式,其中void是发起异步,ActionResult的是执行完毕

    可以在void上面加[AsyncTimeout(30000)]来控制超时时间

    在void中,使用

    AsyncManager.OutstandingOperations.Increment();

    表示有一个需要等待完成的任务。此时这个链接不会返回,而是等待完成

    也就是有地方调用了

    AsyncManager.OutstandingOperations.Decrement();

    ajax长连接的情况为

    用户a发起一个长连接,服务器端increment,然后在内存中保存下这个AsyncManager。可以用各种方式保存,比如session id相关,用户id相关等

    要确保通过用户id(或其他方式)能够找回这个AsyncManager。

    用户a发起之后就等,超时就重发,重发的时候,要把重发后新的AsyncManager更新到之前的那个。

    用户b给用户a发信息,服务器通过用户a的id等信息,找到他连接到服务器AsyncManager,通过AsyncManager.Parameters.Add()设置返回值,然后decrement,此时用户a的长连接就返回了。

    在用户a的页面,可以通过js来获取返回的结果,并在页面上作相应的处理。

    其中涉及到IAsyncResult这里不详细说明

    在单一服务器结构下,流程还是相对比较简单的。当多个web服务器,加上负载均衡,恶心事就来了。

    我们用大写的 A B表示两台服务器,小写的a b表示两个用户

    b给a发消息,a通过ajax 长连接获取到消息

    首先,a发起的长连接,发起到具体A B那台服务器了,不确定,通过负载均衡之后,可能在A,也可能在B

    其次,b给a发送消息产生的连接在那台服务器也不确定

    如果b在发送时,负载到了A服务器,而用户a的长连接也恰好连到了a服务器,则与一台服务器情况一样。

    但是如果两个不是同一台服务器,比如a长链到A,而b的发送请求负载到了B,则在B服务器的内存中找不到a的AsyncManager,返回不了。消息没收到

    长连接,连到那台服务器上,必须由那台服务器返回,不能由其他的服务器返回。

    所以在长连接建立的时候,需要记录是建立在了那台服务器上。而这个记录需要放在一个相对公共的地方,A,B都能操作,比如放在memcache里

    额外说,AsyncManager本身是不能放到memcache里的,因为不可序列化。

    当b给a发信息时,b先去memcache里找到a连接到的服务器,然后调用此服务器的发送方法给a返回信息。如果两个操作不是一台机器,所操作的信息也要放在公共的地方,由b的发送操作放入,而由a的长链服务器取出并返回。

    以上的思路可以保证无论是加一个服务器,减一个服务器,都是均衡并且都能即时返回(假设此方法为最优方法)。

    另外在思考的过程中,还曾经考虑过一些其他的方法

    1、建立主服务器,把所有的ajax长链全分配到此服务器,其他服务器统一调用此服务器的返回

    2、对用户做hash,把固定的用户长链分配到固定的服务器。

    这两种,在均衡上不是很好

    3、记录下未发送出去的信息,等待用户长链超时,重新连接到有信息的服务器时一次性发送

    4、根据时间记录信息,重新连接后,从公共部分取出所有未发送的,一次性发送

    此两种方式即时性差

    使用最优方法,依然存在一个问题。对用一个用户来说,他打开了两个网页,建立了两个长连接,而后一个会覆盖掉前一个。

    也就是,当b给a发信息时,a打开的两个页面只有一个能收到消息,而且还不一定是那个页面。

    我个人对所有的页面都收到消息提示的用户友好性保留看法。

    下面说多页面的情况

    a开多个页面,建立了多个长连接,这些长连接通过负载连接到了不知道几台服务器上,

    b给a发送信息,负载到某一台,然后a的所有长连接均返回

    在每台服务器上,记录a的全部长连接,每一个用户id,对应一个长连接数组

    b发送时,遍历所有的服务器,每个服务器找自己保存的a的长连接,依次返回。

    需要谨慎处理的是超时和返回的连接要即时清除。

    (下称此方式为 最优方法改)

    比如聊天,a给b发一条,b又回a一条,在页面上

    a显示

    我:xxxxxx

    b:yyyyy

    b显示

    a:xxxxxx

    我:yyyyy

    在最优方法时,我说的话,可以用js直接写到页面上,接收的才是通过ajax长链返回处理写到页面上的

    而在最优方法改时,我说的话,也得通过ajax长链来处理

    否则b开3个页面,在其中一个页面上对a说话,a可以收到,b的其他两个页面不显示这句话

    所以在b给a发信息时

    除了遍历服务器找a的长链全部返回外,还得找b自己的全部长链,也全部返回。

    以上是最近几天研究的结果,如果哪位牛人有更好的思路,欢迎给我留言。

    ps:

    1、谁知道nginx怎么配置负载成根据各服务器的总请求数均衡,类似ms web farm

    2、谁知道ms web farm做farm controller的机器能不能自己也挂web服务?我试了很多方法做controller的机器单纯做controller,web服务在其他机器上没问题,但是如果controller自身也加web服务,怎么也负载不来。 配置方法

    很抱歉没什么代码,如果有空,可能会整理一个例子代码出来。

  • 相关阅读:
    git上传本地项目
    第十一章 持有对象
    java 闭包与回调
    类名.class 类名.this 详解
    匿名内部类
    第十章 内部类
    Java简单调用Zookeeper服务
    Linux下ZooKeeper集群安装
    Linux自动化安装JDK
    linux下初步实现Keepalived+Nginx高可用
  • 原文地址:https://www.cnblogs.com/czcz1024/p/2375971.html
Copyright © 2011-2022 走看看