把异步架构延伸到客户端

作者:陈叶皓(携程邮轮研发部软件架构师)

我们先来回顾一下之前提到过的知识点,
1.在一台电脑上,使用异步编程可以提高cpu的使用效率
2.使用Actor模型,实现同一台电脑上,在并发环境下的串行操作,保证事务执行的正确
3.在多服务器环境下,actor模型配合Zookeeper,可以实现在多服务器环境下的串行操作,保证事务执行正确
4.对应用进行读写分离的设计,做到“写服务”(有状态)执行正确,同时又能方便地(增加服务器)提高“读服务”(无状态)的性能

所以,在服务实现的内部,异步已经无处不在,今天我来讲服务的消费者,也就是浏览器客户端,为什么也需要使用异步模式。

在Joe Armstrong创造erlang的时候,他假设网络通讯是不可靠的,外部服务的响应时间是不可靠的,所以erlang里面只有异步调用,同步调用是用异步来模拟。Erlang软件的运行,不会因为任何的外部操作而阻塞cpu。

而到了互联网时代,Joe Armstrong的假设依旧成立,网络通讯不可靠,外部服务不可靠。设计同步调用的应用架构,从一开始就引入了巨大的风险。举个简单的电商下单的例子,步骤如下,
1.浏览器发送下单请求到网页服务器(web server)
2.网页服务器发送请求到应用服务器
3.应用服务器检查库存,锁定库存,生成订单。通知网页服务器下单成功
4.网页服务器把下单结果传送到用户的浏览器

在这个场景下,步骤3最为耗时,有时需要超过1秒。对于步骤2,我们有很多方法来实现异步操作,如果不能实现,那网页服务器被应用服务器的响应所阻塞,吞吐量将急剧下降。

今天我们主要讨论步骤1,用户在下单,期望看到下单的结果,这是一个典型的同步操作,随着并发量上升,服务器的响应时间可能会超过30秒,最终造成浏览器的超时,用户什么也看不到,这是最坏的结果。我们来把这个同步调用,用异步来模拟,
1.浏览器发送下单请求到网页服务器(web server)
2.网页服务器发送请求到应用服务器
3.a)应用服务器生成订单号,把订单号返回网页服务器
b)应用服务器检查库存,锁定库存,把订单状态改成“下单成功”
4.浏览器收到订单号,采用ajax方式,每隔2秒,请求网页服务器,查询订单状态,直到获得“下单成功”的状态,跳转到下单成功页面

在这个异步流程中,步骤3.b和步骤4在时间上是并行执行的,但是,还记得我们的“读写分离”设计吗,步骤3访问的是“写”服务,步骤4访问的是“读”服务,这两个服务可以独立优化,不会成为对方的瓶颈。

使用浏览器的异步访问还带来额外的好处,在异步架构下,网页服务器和应用服务器的响应都非常迅速。原先的耗时请求“请帮我下单,并告诉我下单结果”被拆分成不耗时的请求“帮我下单”(一次)和“刚才的下单成功了吗”(一次或多次)。

如果使用了老式的网页服务器,不支持异步请求应用服务器,这样还能一举解决网页服务器访问应用服务器阻塞的问题。

在互联网高并发的状态改变(写)操作,把业务流程设计成异步是上策,比如大众点评的退款操作,系统会告诉用户“已收到您的退款请求,会在x个工作日能把钱退到您的账户”,这样的异步业务流程,对于系统毫无压力。有时出于用户体验不得不采用同步流程,比如上面说的下单流程,如果一开始设计成用异步流程来模拟,有两个好处
1.不会因为并发量突然上升而触发浏览器超时
2.可以对“读”,“写”服务独立优化
另外,在ajax异步操作时,还可以在浏览器绘制动画来安抚用户焦躁的情绪,不要说我没告诉你~

用异步流程模拟同步流程的补充说明,在浏览器内使用ajax轮询下单结果,是不得以。在服务器可以主动访问客户端的环境下,应该总是优先考虑回调的方式。浏览器是特殊的环境,服务器访问浏览器有时有困难,所以才使用比较保险的轮询模式。

原文链接:http://techshow.ctrip.com/archives/792.html

时间: 2024-10-11 22:21:05

把异步架构延伸到客户端的相关文章

异步Socket服务器与客户端

本文灵感来自Andre Azevedo 在CodeProject上面的一片文章,An Asynchronous Socket Server and Client,讲的是异步的Socket通信. Socket连接(Socket Connection) Socket服务(Socket Service) 连接主机(Connection Host) 加密与压缩(Encrypt与Compress) 请求入队(Enqueuing Requests) 确保发送和接收(Ensure send and recie

Node的结构和Chrome十分相似,基于事件驱动的异步架构

事件驱动:触发一个事件然后再调用相关可用的资源来解决这个事件 异步:无需等待被调用函数的返回值,进行下一项调用 I/O:是input/output的缩写,即输入输出端口 首先,Node是一个架构,通过事件驱动来服务I/O. 在Node中,JS可用随心所欲的访问本地文件,可用搭建WebSocket服务器端,可用链接数据库,可用如Web Worders一样玩转多进程 Node的结构和Chrome十分相似,基于事件驱动的异步架构

同步架构OR异步架构

把智能系统比喻成KFC营业厅,处理器是窗口和窗口后面的服务员(把一个窗口当作一个核心),指令集是后面排队的人,窗口是数据吞吐量.当中午就餐人多的时候,一个窗口肯定忙不过来,这时候可以增加窗口,有两种方法: 1.在窗口后面增加多个服务员,分担一下工作 2.新增多个窗口 方案一就是异步架构,方案二同步架构,一个窗口是不可能比上多个窗口的工作效率,因为只有一条通道,显然异步架构设计简单,实现方便,不过缺点是性能低,吞吐量差.同步架构吞吐量高出不少,不过设计复杂.对于处理量不高的ARM处理器来说,异步架

python 使用epoll异步处理多个客户端的连接

服务器端: #-*- coding:utf8 -*- import socket import select import os address = "0.0.0.0" port = 10001 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) def main(): global address,port,sock epoll = select.epoll() #获取创建好的sock的文件描述符 fd = sock.fil

h5牛牛平台架设游戏开发的架构总结(一) 客户端

有问题Q1446595067官网:h5.haozibbs.com或http:\www.qabaa.com [客户端]1.关于游戏引擎在15年3月开始准备做h5游戏的时候,首先遇到的问题就是引擎选型的问题.当时市面上的2d引擎主要有3个:白鹭egret,layabox和cocos2d-js.一方面,是因为我以前用cocos2d-x(c++)做了一年多的手游客户端,所以,很自然就选择了cocos2d-js.另一方面,是因为当时市面上其他两个引擎的成功项目还不多.cocos引擎的每一次版本更新,我们都

Delphi2010中采用DataSnap的三层网络架构服务器获取客户端ip,端口信息

需要的控件 首先要有 TDSServerModule. TDSServer.TDSTCPServerTransport; TDSServerClass.TDataModule;实现上述功能主要控件如下图所示 包含的单元包括 SysUtils, Classes, DSTCPServerTransport, DSHTTPCommon, DSHTTP, DSServer, DSCommonServer, Provider, IdBaseComponent, IdComponent, IdTCPConn

MVC文件上传 - 使用jquery异步上传并客户端验证类型和大小

本篇体验MVC上传文件,从表单上传过渡到jquery异步上传. MVC最基本的上传文件是通过form表单提交方式 □ 前台视图部分 <% using(Html.BeginForm("FileUpload", "FileUpload", FormMethod.Post, new {enctype = "multipart/form-data"}) {)%> <input name ="uploadFile" t

基于消息机制的异步架构之回调函数注册

/* * akg.h * 业务逻辑注册 * */ #ifndef AKG_H_ #define AKG_H_ #include "conn.h" #include "msgqueue.h" #define MAX_PKG_TYPE (0xffff) extern const uint16 g_akg_connected_id; extern const uint16 g_akg_timeout_id; extern const uint16 g_akg_closed

基于消息机制的异步架构之对消息队列的处理

/* *   handle.h */ #ifndef HANDLE_H_ #define HANDLE_H_ #include "msgqueue.h" typedef struct HANDLER{ int send_sock; char send_ip[128]; uint16 send_port; int ind; pthread_t  thread_id; //WORKER* father_thread; MSG_QUEUE* qmsg; }HANDLER; HANDLER*