4

Seastar 入门

 2 years ago
source link: https://forrestsu.github.io/posts/architecture/archi-seastar/seastar-started/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Seastar 入门

2018年2月27日
| 字数 2496

1 what is Seastar

这篇文章将介绍一下 Seastar : 一个在现在多核机器上编写高效复杂的服务器应用程序的 C++ 库。

有些框架非常高效,但只允许构建简单的应用程序(eg: DPDK 允许单独处理数据包的应用程序), 而其他框架则允许构建极其复杂的应用程序,代价是运行时效率。Seastar 是我们尝试获得两全其美的方法:创建一个允许构建高度复杂的服务器应用程序并实现最佳性能的库。

Seastar 的灵感和首例使用案例是ScyllaDB,重写了Apache Cassandra,Cassandra 是一个分厂复杂的应用,同时通过 Seastar,我们能够重新实现吞吐量提高10倍,以及显着降低和更一致的延迟。 Seastar提供了一个完整的异步编程框架,它使用两个概念 - 期货和延续 - 统一表示和处理每种类型的异步事件,包括网络I/O,磁盘 I/O 以及其他事件的复杂组合。

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

具有同步设计的服务器仍然具有令人不满意的性能,并且随着并发连接数量的增长而缩小。1999年,Dan Kigel普及了 “C10K问题” —— 需要在一台服务器上有效处理 10,000个并发连接 —— 其中大多数是缓慢, 甚至是不活跃。(大四的时候,美团面试官也问过我这个问题

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

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

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

  • 现代机器:现代机器与十年前的机器非常不同。它们具有许多内核和深层存储器层次结构(从L1缓存到NUMA),这些层次会奖励某些编程实践并惩罚其他人:不可扩展编程实践(如锁定)可能会破坏许多内核的性能; 共享内存和无锁同步原语可用(即原子操作和内存排序的屏蔽),但比仅涉及单个内核高速缓存中的数据的操作要慢得多,并且还会阻止应用程序扩展到多个内核。

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

Seastar是一个用于编写异步服务器应用程序的框架,旨在解决上述所有四个难题:它是编写涉及网络和磁盘I / O的复杂异步应用程序的框架。该框架的快速路径完全是单线程(每核心),可扩展到多个内核,并最大限度地减少了在内核之间使用昂贵的内存共享。它基于 C++14 的一些新特性,为用户提供了复杂的编译时功能和对性能的完全控制,而无需运行时间开销。

3 Features

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

  • 合作型微任务调度器:每个核心都运行一个协作式任务调度器,而不是运行线程。每个任务通常都非常轻量级 - 只需要处理最后一次I / O操作的结果并提交新结果即可运行。

  • 无共享SMP体系结构:每个内核独立于SMP系统中的其他内核运行。内存,数据结构和CPU时间不共享; 相反,核心间通信使用明确的消息传递。Seastar核心通常被称为碎片。TODO:更多https://github.com/scylladb/seastar/wiki/SMP

  • 基于 future 的API:期货允许您提交I / O操作并链接完成I / O操作时执行的任务。并行运行多个I / O操作非常简单 - 例如,响应来自TCP连接的请求,您可以发出多个磁盘I / O请求,将消息发送到同一系统上的其他内核,或发送请求到集群中的其他节点,等待部分或全部结果完成,汇总结果并发送响应。

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

  • 基于DMA的存储API:与网络堆栈一样,Seastar提供零拷贝存储API,允许您将数据存储在存储设备中或从存储设备中存取数据。

<且听下回分解>


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK