为什么我们用Lua编写业务逻辑

哈Ha 在这篇文章中,我们想谈谈如何以及为什么在IPONWEB中使用具有美丽名称Lua的编程语言。

Lua是一种基于脚本的嵌入式编程语言,带有免费的解释器和C开源代码。Lua于1993年在巴西里约热内卢天主教大学的Tecgraf部门开发,其前身是DEL(数据输入语言)和SOL。 (简单对象语言)在此之前开发。 SOL的祖先之一间接参与了新生儿的“洗礼”-“ Sol”从葡萄牙语翻译为“ sun”,新语言被命名为“ Lua”,“ moon”。

将Lua嵌入以“系统”语言编写的引擎中的简便性使其成为一种流行的视频游戏脚本语言。 例如,脚本是用Grim Fandango和Baldur's Gate中的Lua编写的。 玩过《魔兽世界》的人可能还不止一次听说过Lua-在游戏中添加了附加组件,可以使铁杆玩家,休闲迷,爱好者评估自己的效率以及游戏世界中其他居民的生活变得更轻松。 在gamedev之外,Lua用作嵌入式系统(电视,打印机,汽车面板)以及应用程序(例如VLC Media Player)的脚本语言。 Lua使用诸如Tarantool,Redis和OpenResty之类的工具作为嵌入式语言。 Lua还用作Fortran计算代码的扩展语言,用于模拟核燃料的热机械行为。

为什么是卢阿?


IPONWEB是为在线广告领域的公司(DSP,SSP,广告代理商和广告商)提供高负载平台的开发商。 在本文中,我们详细介绍了我们的工作。 最初,我们使用C ++开发了平台的业务逻辑,但是很快意识到这不是最佳选择。 为了最大程度地降低成本,该平台的性能以及开发速度至关重要,而C ++开发对我们来说太慢了,添加功能的复杂性也受到了影响。 我们决定将业务逻辑的解释与低级服务器代码隔离开来,开始为此寻找合适的语言,并选择了Lua。 到了2008年,尚不存在适合我们的JavaScript实现,Perl,Python和Ruby太慢且不易于集成。 还有Lua语言,虽然不是很出名,但在游戏开发人员中很流行,我们想要的与游戏开发人员的需求相似-我们需要用于低级操作的快速引擎和用于业务逻辑的易于构建的快速语言。

Lua确实是一种非常快速的语言。 通过使用LuaJl (用于Lua 5.1的运行时环境)可以进一步提高速度,该环境包括一个跟踪JIT编译器(我们使用了我们自己编写的fork)。 由于我们为RTB系统编写业务逻辑,因此速度对我们至关重要:在RTB中,平均而言,要处理每个传入请求的时间为120毫秒。 同时,仅将10到15毫秒分配给代码执行,其余时间正等待其他服务的响应。 例如,如果用户在网络上加载站点时甚至没有注意到半秒的延迟,那么对于RTB而言,这500毫秒是一个巨大的时间段。 Lua语言有多快的问题的答案是:它足够快,以便我们可以在它上面编写业务逻辑很多年并保留在RTB业务中。 如果我们选择的语言不够快,我们将没有人编写平台。 这是否意味着RTB无法用其他语言编写? 不代表。 但是我们用Lua编写了实时出价工具,并成功地完成了我们和客户的业务任务。 这个OpenResty 基准测试很好地说明了Lua在服务器上的速度。

Lua作为一种嵌入式语言具有许多优点:它极简,紧凑,具有非常小的标准库。 它的功能完全用C语言复制,从而在Lua和C之间提供了轻松,“无缝”的交互。与许多其他语言相比,Lua的登录阈值较低:大多数使用IPONWEB工作的程序员以前从未编写过Lua,但是他们已经足够几天才能充分从事这项工作。

这是定位广告受众的简单示例。

-- deal: ,  ,      --     ( ,    ..) -- imp:   (impression opportunity),  --       local function can_be_shown(deal, imp) local targeting = deal.targeting --    if not targeting then return true end --         -- (,    ,   ): if targeting.media_type then if not passes_targeting(targeting.media_type, imp.details.media_type) then return false end end --        : if targeting.size then if not passes_targeting(targeting.size, imp.details.sizes) then return false end end return true end 

这就是简单的处理程序(事件处理程序)的外观。

 local adm_cache = require 'modules.adm_cache' -- adm = "ad markup" local config = require 'modules.config' local util = require 'modules.util' local AbstractHandler = require 'handlers.abstract' local ImpRenderHandler = AbstractHandler:new({is_server_request = false}) local IMP_RENDER_TEMPLATE = config.get('imp_render_template') local IMP_RENDER_BILLING = {name = 'free', type = 'in'} --   ,  . --   ( ,   ) . --          . function ImpRenderHandler:handle(params) local user_id = self.uuid local cache_id = get_param('id') if not cache_id or cache_id == '' then return self:process_bad_request({reason = '"id" parameter is expected', user_id = user_id}) end local adm = adm_cache.get(cache_id) if not adm then return self:process_bad_request({reason = 'No adm in cache', user_id = user_id}) end update_billing(IMP_RENDER_BILLING) self:log_request('imp_render', {adm = adm, user_id = user_id, cache_id = cache_id}) local content = util.expand_macro(IMP_RENDER_TEMPLATE, {ADM = adm}) return {200, content = content} end return ImpRenderHandler 

Lua的简单性不仅提供了快速的开发,而且使您可以轻松完成许多工作。 IPONWEB平台是一种通用解决方案,可根据特定客户的需求量身定制,而一名开发人员和一名经理可以执行该项目。 阅读Lua上的代码不仅可以使开发人员自己,而且可以使项目经理,有时甚至是客户。 在一起,我们迅速发现问题,找到问题的原因和解决方案。 通常,项目经理会将问题告知开发人员,并立即提出解决方案。

同时,Lua的简单性可能是骗人的,而简约和紧凑则有不利之处。 例如,如果代码是用Perl或Python编写的,则开发人员可以使用庞大的现成模块存储库,Ruby可以使用RubyGems,而许多其他语言也可以使用丰富的存储库。 Lua有LuaRocks和那里的三千个模块。 此外,即使LuaRocks具有正确的模块,您极有可能必须努力在特定的公司中使用它。 Lua提供了很好的工具来创建执行代码(沙箱)的安全环境,在沙箱中工作时,可以禁用某些功能。 这意味着,如果LuaRocks模块使用了公司安全环境所阻止的功能,则它们可能无法工作。 这是紧凑性和可嵌入性的代价,但是这是值得的-带有电池的语言(例如Python)的构建方式并不比Lua复杂。

如何运作?


我们平台的基础是可定制的HTTP服务器,它具有方便且可扩展的API,可为Lua开发人员提供一系列功能,并针对广告市场的任务进行量身定制。 该服务器每天处理数亿个请求,并写入数TB的日志。 传入的请求均匀地分布在系统线程中,并且在系统线程内部是沙箱。

图片

当请求到达服务器时,将在该请求所属的沙箱内创建一个协程协程将处理该请求。 协程彼此独立工作,正在创建的每个协程都排队等待执行。 每个协程的生命周期(请求的总处理时间,考虑到所涉及服务的预期响应:数据库,指标,预算服务器)不应超过120毫秒。



简而言之,请求处理过程可以描述如下:

  1. 每个收到的请求都会被解析,并通过标准检查是否正确。
  2. 启动Corutin,负责处理此请求。 在每个沙盒中,有许多状态不同的协程。
  3. 请求处理开始,可能有两个结果:
    • 处理成功完成。
    • Corutin将控制权转移到服务器。 当协程正在等待其他服务的响应时,通常会发生这种情况。 在这种情况下,Corutin的工作将暂停,直到响应到达或等待时间到期为止。 转移控制权时,服务器开始处理下一个请求。 这可以是新请求,也可以是从所有涉及的服务接收响应并准备继续执行代码的请求。 处理请求的顺序由业务逻辑的要求确定。


Corutin的使用是另一个有趣的话题,值得详细讨论。 例如, 本文详细介绍了如何在游戏中使用Corutins创建过场动画。 而且应用服务器上的协程应该专门写一篇文章,也许将来我们会做。

接下来是什么?


然后,也许会扩大IPONWEB中Lua的使用。 我们对您如何在我们的业务中仍然使用Lua有一些想法,当这些想法付诸实施时,我们一定会分享新的经验。 Lua作为嵌入式脚本语言的便利性和功能特别可以帮助我们加快客户端数据的处理速度。 但这仍然来自计划和前景领域。

综上所述,我们可以说,我们11年前对业务逻辑语言的选择继续证明其合理性,使我们能够成功应对自己的业务任务并帮助我们解决客户的问题。 易读,易集成,快速易学,Lua一直是并且仍然是最好的脚本语言之一,其范围绝不限于游戏开发。 上面写的IPONWEB业务逻辑只是一个例子。

Source: https://habr.com/ru/post/zh-CN469049/


All Articles