Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

关于“ 异步”,从 Amazon 的工作流框架中获得的思考

Posted on 03/03/201206/23/2019 by 四火

云平台的工作流框架 AWS Flow Framework 给我带来的另一个有所感触的话题是“ 异步”:

1

这个框架把异步的行为划分为 Workflow 端执行的部分和 Activity 端执行的部分,Workflow 控制工作流程,Activity 执行具体的工作流 task,二者都以 poll 的模式不断从中心 SWF 去获取任务。对于开发者来说,用类似这样简单的代码,就完成了整个工作流任务的部署,框架为开发人员隐藏了大部分实现细节:

@Workflow  
public interface CalculateWorkflow  
{  
    @Execute  
    public void calculate();  
}  
  
public class CalculateWorkflowImpl implements CalculateWorkflow  
{  
    ……  
    public void calculate()  
    {  
        Promise<String> val1 = activity1.calc();  
        Promise<String> val2 = activity2.calc();  
          
        printResult(val1, val2);  
    }  
  
    @Asynchronous  
    public void printResult(Promise<String> val1, Promise<String> val2)  
    {  
        System.out.println("Result: " + val1 + " and " + val2);  
    }  
}  

对于这样一段代码(再配合 Activity 的代码),做了两点处理:

1、activity 调用的逻辑,返回值通过 Promise 包装:

Promise<String> val1 = activity1.calc();  
Promise<String> val2 = activity2.calc();  

2、@Asynchronous 所修饰的方法会被处理成本地执行的异步方法,其中的参数使用 Promise 包装:

public void printResult(Promise<String> val1, Promise<String> val2)  

这样一来,这里面包含了三个异步任务:

  • a、Activity1 端执行的 activity1.calc(),
  • b、Activity2 端执行的 activity2.calc(),
  • c、等待上述两个任务执行完毕后再在 Workflow 端执行的 printResult。

其中,使用 Promise 包装的参数,它的作用就在此,在上述两个异步的 Activity 方法执行返回后,才会触发 printResult 方法的执行(printResult 方法依赖于两个 Activity 方法执行结果的返回),可是,这和一般等待执行的异步流程 merge 操作不同的是,在等待过程中它不会 block 住线程(反例可以参考 Future 类,它的 get 方法是会 block 住线程的),最大限度地减少了资源的占用。

这只是其中利用异步的设计,给我印象很深刻的一个场景。对于减少资源占用,我们还经常接触到许多其它类似的场景,比如 NIO Server,这是多路复用技术的一种。

传统服务器接收到请求以后,从 request 到 response,整个过程占住一个线程不放,但是这种服务器可以在收到请求之后,将需要完成的工作用一个或若干个 Command 包装好,交给线程池中的工作线程去完成,对于收到请求和返回响应这样的过程,使用 1~2 个独立的线程去完成,在事件发生时,系统线程才通知这 1~2 个线程去完成和客户端的一次交互(或者用监控线程去轮询当前挂在 Server 上所有的连接,寻找需要响应的连接来完成交互)。

当在线用户数量大大超出服务器的线程数时,使用 NIO 模式可以保证在收到请求和返回响应的用户接口层不成为瓶颈 。

另外还有一个特别值得一提的场景,由于互联网的 BS 模式下,从 Server 实时或准实时地向 Client 推送一些东西是比较麻烦的(有同学说用 pushlet 来解决,但这个办法有很大的局限性),有一种解决这个问题的办法是客户端使用 ajax 去定期获取数据(比如现在的很多 SNS 网站都用了这种办法),在这种情况下服务端对请求处理的压力就陡然增大了。

Nginx 是一款高性能的代理服务器,性能高的其中一个重要原因是,它基于 epoll 模型设计的。与之相对的是 select 模型,select 采用的是轮询的办法,每次读写状态检测都检查 FD_SET 中所有的句柄,当句柄数量增大时,这个过程消耗的时间应该是线性增长的。另外,FD_SIZE 也设定了整个可开启的句柄数,这造成了另一种局限。

epoll 模型就没有这两个问题,它给每个活跃 FD 挂接一个异步回调函数,不需要第三方去遍历和调用这些句柄,而它的句柄限制是操作系统的限制 。

关于 Continuation Server。这种模式下 Client 和 Server 会调过来,Continuation Server 发送页面给客户端,作为 function call,然后等待客户端返回执行结果 (SendPageAndWait),因此,在服务端收到响应的时候,要恢复之前方法调用的上下文环境,继续执行收到响应后的下一行语句 。

这个过程就需要服务器端能够在发送页面前将上下文环境保存下来,在获得响应之后动态获取调用栈恢复上下文环境,这些工作都是异步事件驱动的。

不能不说一说 Node.js,这是 JavaScript 在 2011 年最火爆的词语之一,其实服务端 js 不是什么新东西,只不过因为 Node.js,人们高呼,JavaScript 居然也可以这样快!大概 V8 引擎做的编译优化太好了,许多前端工程师第一次发现自己的价值其实远不止在页面上 。Node.js 把复杂的事件处理框架隐藏起来,开发人员只需要关注业务接口的调用。

Node.js 所有的事件触发的调用都是异步和非阻塞的,它对高并发的访问有很好的承受能力(Node 宣称他们的服务器每一台都可以承受几万连接并发)。如果服务端面对一场 subscribe 的灾难,虽然有足够大的队列来承受瞬间的高并发访问,但是瓶颈在请求接收和响应上,那么 Node.js 应该能成为一个有价值的解决方案。

最后,对于 Jscex,还有 Barrier 模式,在此不展开。

异步调用给传统软件编码的思维带来了新的挑战,无论是对现场的快照、异常的处理还是分支跳转的控制,但是带来了许多不可替代的优势,资源占用更少,效率更高,可扩展性更强。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 关于“ 无状态”,从 Amazon 的工作流框架中获得的思考
  2. 一种工作流心跳机制的设计
  3. 工作流系统的设计
  4. 画圆画方的故事
  5. 多重继承的演变

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Python Spark 互联网 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 程序员 管理 系统设计 缓存 编码 编程范型 英语 西雅图 设计 评审 问题 面试 项目

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Big Data and Machine Learning (5)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • + 1.943624 BTC.NEXT - https://graph.org/Ticket--58146-05-02?hs=9a9c6f8dfe3cdbe0074006e3e640b19b& on 所有文章
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
  • Anonymous on 我裸辞了
  • Dylan on 我裸辞了
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme