作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
遗留代码无处不在. 随着代码激增的速度继续呈指数增长, 越来越多的代码被降级为遗留代码. 在许多大型组织中, 遗留系统的维护消耗了90%以上的信息系统资源.
对遗留代码和系统进行现代化以满足当前性能和处理需求的需求非常普遍. 这篇文章提供了使用的案例研究 Erlang 编程语言,以及基于erlang的 CloudI 面向服务架构(SOA), 适应遗留代码——特别是, 一个有几十年历史的C源代码集-到21世纪.
几年前,我是基于文本的多人在线游戏《欧博体育app下载》的忠实粉丝。MUDs). 但它们总是充斥着性能问题. 我决定回到几十年前的C源代码堆中,看看我们如何使这些遗留代码现代化,并将这些早期的在线游戏推向极限. 在高层次上,这个项目是一个很好的例子 using Erlang 调整遗留软件以满足21世纪的需求.
简要总结:
所有大型多人在线角色扮演游戏(MMORPGs)——如《欧博体育app下载》和《欧博体育app下载》——开发了一些功能,这些功能的早期起源可以追溯到更早的基于文本的多人在线游戏,即多用户地下城(MUDs).
第一个MUD是Roy Trubshaw的Essex MUD(或 MUD1),它最初是在1978年使用DEC PDP-10上的MARO-10汇编语言开发的, 但被转化为BCPL, C语言的前身(一直运行到1987年). (正如你所看到的,这些东西比大多数程序员都要老.)
在20世纪80年代末和90年代初,随着各种用C编写的MUD代码库的出现,MUD逐渐流行起来. 例如,DikuMUD代码库被认为是最大的代码库之一的根 trees 的派生MUD源代码, 至少有51个独特的变体,它们都基于相同的DikuMUD源代码. (在这段时间内, incidentally, mud也被称为“多大学生毁灭者”,因为许多大学生因为沉迷于mud而辍学.)
历史上的C MUD源代码(包括DikuMUD及其变体)由于其创建时的现有限制而充满了性能问题.
那时,还没有容易访问的线程库. 此外,线程化会使源代码更加难以维护和修改. 因此,这些mud都是单线程的.
在单个“tick”期间(跟踪所有游戏事件进程的内部时钟的增量), MUD源代码必须处理 every 游戏活动 every 连接套接字. 换句话说:每段代码都会减慢单个tick的处理速度. 如果任何计算迫使处理跨越超过一个刻度, the MUD lags, 影响每一个连接的玩家.
有了这种延迟,游戏的吸引力就会立刻降低. 玩家只能眼睁睁地看着自己的角色死去,而自己的命令却没有得到处理.
对于这个遗留应用程序现代化实验的目的,我选择 SillyMUD, 这是《欧博体育app下载》的历史衍生品,它影响了现代mmorpg以及它们所共有的性能问题. 在90年代, 我玩了一个从SillyMUD代码库派生出来的MUD, 所以我知道源代码将是一个有趣的和有点熟悉的起点.
SillyMUD的源代码与其他历史上的C mud类似,因为它被限制在大约50个并发玩家(64个), 准确地说, 基于源代码).
然而,我注意到由于性能原因,源代码被修改了.e.,以推动其并发玩家限制). 具体地说:
CloudI was 以前讨论的 作为多语言开发的解决方案,因为它提供了容错性和可伸缩性.
CloudI提供了一个服务抽象(以提供面向服务的体系结构)。SOA)) in Erlang, C/C++, Java, Python, and Ruby, 同时将软件故障隔离在CloudI框架内. 通过CloudI的Erlang实现提供了容错功能, 依赖于Erlang的容错特性及其实现 Actor Model. 这种容错是CloudI的Erlang实现的一个关键特性 所有软件都有bug.
CloudI还提供了一个应用服务器来控制服务执行的生命周期和服务进程的创建(无论是作为非Erlang编程语言的操作系统进程,还是作为用Erlang实现的服务的Erlang进程),以便在没有外部状态影响可靠性的情况下执行服务. 欲了解更多,请参阅我的 以前的文章.
考虑到CloudI的可靠性问题,历史的C MUD源代码为CloudI集成提供了一个有趣的机会:
与CloudI集成, 服务器稳定性错误仍然可以正常修复, 但它们的影响是有限的,所以当一个之前未被发现的漏洞导致内部游戏系统失败时,游戏服务器的操作并不总是受到影响. 这提供了一个使用Erlang在遗留代码库中强制容错的好例子.
最初的代码库被编写为单线程且高度依赖全局变量. 我的目标是保留遗留源代码的功能,同时对其进行现代化改造,以适应当前的使用.
With CloudI, 我能够保持源代码的单线程,同时仍然提供套接字连接的可伸缩性.
让我们回顾一下必要的更改:
silymud控制台输出的缓冲(终端显示,通常与 Telnet)已经就位, 但是一些直接文件描述符的使用确实需要缓冲(以便控制台输出可以成为对CloudI服务请求的响应)。.
套接字处理在原始源代码中依赖于 select()
检测输入的函数调用, errors, 以及产出的机会, 以及在处理悬而未决的游戏事件之前暂停250毫秒的游戏tick.
clouddi sliymud集成依赖于在C clouddi API暂停时输入的传入服务请求 cloudi_poll
函数(在处理相同的未决游戏事件之前的250毫秒). 在与C CloudI API集成之后,silymud源代码很容易作为CloudI服务在CloudI中运行 CloudI同时提供C和c++ api,使用C API更好地促进了与sliymud的C源代码的集成)。.
CloudI集成订阅了三种主要的服务名称模式来处理连接, disconnect, 以及游戏事件. 这些名称模式来自C CloudI API调用 subscribe 在集成的源代码. Accordingly, WebSocket连接或Telnet连接都有服务名称目的地,用于在建立连接时发送服务请求.
clouddi中的WebSocket和Telnet支持是由clouddi内部服务(cloudi_service_http_cowboy
用于WebSocket支持和 cloudi_service_tcp
用于Telnet支持). 因为内部CloudI服务是用Erlang编写的, 他们能够利用Erlang的极致可伸缩性, 同时使用CloudI 服务抽象 它提供了CloudI API函数.
通过避免套接字处理,可以减少对套接字错误或类似情况的处理 link death (用户与服务器断开连接). 因此,删除低级套接字处理解决了主要的可伸缩性问题.
但可扩展性问题依然存在. For example, MUD使用文件系统作为静态和动态游戏元素的本地数据库.e.,玩家和他们的进程,以及世界区域,对象和怪物)。. 重构MUD的遗留代码,转而依赖CloudI服务作为数据库,将提供进一步的容错性. 如果我们使用数据库而不是文件系统, 多个SillyMUD CloudI服务进程可以作为独立的游戏服务器并发使用, 使用户与运行时错误隔离并减少停机时间.
有三个主要的改进领域:
So, 通过简单的CloudI集成, 连接数量增加了三个数量级,同时提供容错性并提高了相同传统玩法的效率.
Erlang提供了99个.9999999%正常运行时间(小于31).(每年536毫秒的停机时间). 有了CloudI,我们将同样的可靠性带到其他编程语言和系统中.
除了证明这种方法在改进停滞不前的遗留游戏服务器源代码方面的可行性之外(《欧博体育app下载》最后一次修改是在20多年前的1993年)!), 该项目在更广泛的层面上演示了如何利用Erlang和CloudI来实现遗留应用程序的现代化并提供容错功能, 提升的性能。, 以及总体上的高可用性. 这些结果为使遗留代码适应21世纪而不需要对软件进行重大修改提供了希望.
Michael是分布式系统和容错专家,曾在AT工作过&T、E*Trade、诺基亚等.
世界级的文章,每周发一次.
世界级的文章,每周发一次.