异步编程框架Seastar介绍

使用Seastar进行异步(Asynchronout)编程

介绍

我们在本文中介绍的Seastar,是一个用于在现代多核机器上,编写高效复杂的服务器应用程序的C++库。

传统上,用于编写服务器应用程序的编程语言库和框架已经分为两个不同的阵营:那些注重效率的阵营和侧重于复杂性的阵营。一些框架是非常高效的,但是只允许构建简单的应用程序(例如,DPDK允许单独处理数据包的应用程序),而其他框架允许构建极其复杂的应用程序,代价是运行时效率。 Seastar是我们努力获得两全其美的方法:创建一个允许构建高度复杂的服务器应用程序,但实现最佳性能的库。

Scylladb第一个使用了Seastar,它是对Apache Cassandra的重写。 Cassandra是一个非常复杂的应用程序,然而,通过Seastar,我们能够让吞吐量提高10倍,同时显著的降低一致性的延迟。

Seastar提供了一个完整的异步编程框架,它使用了 futrues 和 continuations 的概念,来统一表示和处理每种类型的异步事件,包括网络IO,磁盘IO以及其他事件的复杂事件。

由于现代多核和多插槽机器在核心之间共享数据(原子指令,高速缓存行反弹和内存隔离)具有很高的代价,Seastar程序使用无共享编程模型,即可用内存隔离,每个核心都在自己的内存部分进行数据处理,内核之间的通信通过显式的消息传递(当然这发生在使用SMP的共享内存硬件的情况下)

异步编程

用于网络协议的服务器(如经典的HTTP(Web)或SMTP(电子邮件)服务器)处理是并行的:多个客户端并行发送请求,在完成处理一个请求之前,我们无法开始处理下一个请求:因为各种原因,一个请求可能并经常需要阻塞磁盘IO,例如一个完整的TCP窗口(即一个慢速连接),甚至是持有非活跃连接的客户端。服务器需要处理其他连接也是如此。

经典网络服务器(如Inetd,Apache Httpd和Sendmail)处理这种并行连接所采用的最直接的方法是对每个连接使用单独的操作系统进程。这种技术经过多年的发展,以提高其性能:刚开始,使用一个新的进程来处理每个新的连接;后来,使用进程池,每一个新的连接都被分配到池中的一进程。最后,进程被线程所取代。但是,所有这些实现背后的共同思想是,在每一个时刻,每个进程只处理一个连接。因此,服务器代码可以自由使用带阻塞的系统调用,例如读取或写入连接,或者从磁盘读取数据,如果这个过程阻塞了,也没关系,因为我们有许多额外的进程可以处理其他连接。

对每个连接使用一个进程(或一个线程)的服务器编程称为同步编程,因为代码是线性执行的,在上一行完成后,下一行代码开始运行。例如,代码可能会从套接字读取请求,解析请求,然后零碎地从磁盘读取文件并将其写回套接字。这样的代码很容易编写,就像传统的非并行程序一样。事实上,甚至可以运行一个外部的非并行程序来处理每个请求 - 例如Apache HTTPd如何运行“CGI”程序,生成第一个动态Web页面。

>注意:尽管同步服务器应用程序是以线性,非并行的方式编写的,但内核可以帮助确保所有事情都是并行发生的,并且可以充分利用机器的资源(CPU,磁盘和网络)。除了进程并行(我们有多个进程并行处理多个连接)之外,内核甚至可以并行化一个单独连接的工作 - 例如处理一个未完成的磁盘请求(例如,从磁盘文件中读取)并行处理网络连接(发送缓冲区中尚未发送的数据,并缓冲新接收的数据,直到应用程序准备好读取它)。

但是同步的,每个连接的过程,服务器编程并不是没有缺点或成本的。服务器作者慢慢地但是确定地意识到,开始一个新的进程是缓慢的,上下文切换很慢,每个进程都伴随着大量的开销,最显着的是它的堆栈大小。服务器和内核作者努力减轻这些开销:他们从进程切换到线程,从创建新线程到线程池,降低了每个线程的默认堆栈大小,增加了虚拟内存大小以允许部分利用的堆栈。但是,同步设计的服务器的性能并不理想,随着并发连接数量的增长,服务器的性能也不尽人意。 1999年,Dan Kigel普及了“C10K问题”,需要一台服务器来高效地处理10,000个并发连接,其中大部分是缓慢甚至不活动的。

该解决方案在接下来的十年中变得流行,它放弃了舒适但低效的同步服务器设计,转而采用新型服务器设计 - 异步服务器或事件驱动服务器。事件驱动的服务器只有一个线程,或者更准确地说,每个CPU有一个线程。这个单线程运行一个紧密的循环,在每次迭代时,使用poll()(或更高效的epoll)检查许多打开文件描述符(例如套接字)上的新事件。例如,一个事件可以是一个套接字变得可读(新的数据已经从远端到达)或变得可写(我们可以在这个连接上发送更多的数据)。应用程序通过做一些非阻塞操作来处理这个事件,修改一个或多个文件描述符,并且保持它对这个连接状态的知识。

然而,异步服务器应用程序的作者面临着今天仍面临的两大挑战:

复杂性:编写简单的异步服务器非常简单。但是编写一个复杂的异步服务器是非常困难的。单个连接的处理,而不是一个简单易读的函数调用,现在涉及大量的小型回调函数和一个复杂的状态机,以记住每个事件发生时需要调用哪个函数。

非阻塞:每个内核只有一个线程,对于服务器应用程序性能很重要,因为上下文切换很慢。但是,如果我们每个内核只有一个线程,则事件处理函数不能阻塞,否则内核将保持空闲状态。但是一些现有的编程语言和框架让服务器作者别无选择,只能使用阻塞函数,因此也不能使用多线程。例如,Cassandra被编写为一个异步服务器应用程序;但是因为磁盘I/O是用mmaped文件实现的,所以在访问时可以不受控制地阻塞整个线程,它们被迫在每个CPU上运行多个线程。

而且,当需要尽可能好的性能时,服务器应用程序及其编程框架不得不考虑以下因素:

现代机器:现代机器与十年前的机器非常不同。它们具有许多内核和深层内存层次结构(从L1缓存到NUMA),这些有利于某些编程实践,却带来一些问题:不可扩展的编程实践(如锁定)会破坏许多内核的性能;共享内存和无锁同步原语是可用的(即,原子操作和内存排序的屏障),但是比仅涉及单个内核的缓存中的数据的操作慢得多,并且也阻止应用程序扩展到多个内核。

编程语言:诸如Java,Javascript和类似的“现代”语言的高级语言是很方便的,但是每一种语言都有自己的一套假设,与上面列出的要求相冲突。这些旨在可移植的语言也使编程人员无法控制关键代码的性能。为了获得最佳的性能,我们需要一种编程语言,使程序员能够完全控制,零运行时间的开销,另一方面, 编译时代码的复杂性和优化。

Seastar是一个用于编写异步服务器应用程序的框架,旨在解决上述所有四个难题:这是一个用于编写复杂的异步应用程序(包括网络和磁盘I / O)的框架。该框架的高效运行途径完全是单线程(每核心),并可扩展到多个内核,并最小化在内核之间使用昂贵的内存共享。它是一个C ++ 14库,为用户提供了复杂的编译时功能和对性能的全面控制,而无需运行时间的开销。

Seastar

Seastar是一个事件驱动的框架,允许您以相对直接的方式编写非阻塞的异步代码。它的API基于 futures(c++11新特性)。 Seastar利用以下概念来实现卓越的性能:

Cooperative micro-task scheduler(合作的微任务调度器):每个核心运行一个合作任务调度器,而不是运行线程。每个任务通常都是非常轻量级的,只要处理最后一次I/O操作的结果并提交一个新的结果就可以运行。

Share-nothing SMP architecture(无共享SMP架构):每个内核独立于SMP系统中的其他的内核运行。内存,数据结构和CPU时间不共享;相反,核心间通信使用显示的消息传递。 Seastar core 通常被称为 shard。

TODO:更多在资料访问 scylladb/seastar

Future based APIs(基于future的API):futures允许您提交I/O操作,并链接完成I/O操作时要执行的任务。这是很容易并行运行多个I/O操作。例如,在响应TCP连接请求时,可以发出多个磁盘I/O请求,或发送相同的系统上的消息给其他核,或者发送请求到集群中的其他节点,等待一些或全部结果完成,汇总结果并发送响应。

Share-nothing TCP stack(无共享TCP堆栈):虽然Seastar可以使用主机操作系统的TCP堆栈,但它还提供了自己的高性能TCP/IP堆栈,该堆栈构建在任务调度器和无共享架构之上。堆栈在两个方向上提供零拷贝:您可以直接从TCP堆栈的缓冲区处理数据,并将您自己的数据结构的内容作为消息的一部分发送,而不会产生副本。

DMA-based storage APIs(基于DMA的存储API):与网络堆栈一样,Seastar提供零拷贝存储API,允许您将数据存入存储设备。

本教程面向已经熟悉C ++语言的开发人员,并将介绍如何使用Seastar创建新的应用程序。

参考链接:

scylladb/seastar

异步编程框架Seastar介绍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值