¿Por qué escribimos lógica empresarial en Lua?

Hola Habr En esta publicación queremos hablar sobre cómo y por qué usamos un lenguaje de programación con el hermoso nombre Lua en IPONWEB.

Lua es un lenguaje de programación integrado basado en script con un intérprete gratuito y código abierto en C. Fue desarrollado en 1993 en Brasil, en la división Tecgraf de la Universidad Católica de Río de Janeiro, y sus progenitores fueron DEL (Lenguaje de entrada de datos) y SOL (Simple Object Language) desarrollado allí antes. Uno de los antepasados, el idioma SOL, participó indirectamente en el "bautismo" del recién nacido: "Sol" se traduce del portugués como "sol", y el nuevo idioma se llamó "Lua", "luna".

La facilidad para integrar Lua en motores escritos en lenguajes de "sistema" lo ha convertido en un lenguaje de script popular para videojuegos. Por ejemplo, los guiones están escritos en Lua en Grim Fandango y Baldur's Gate. Aquellos que juegan a World of Warcraft probablemente también hayan escuchado sobre Lua más de una o dos veces: en él se escriben los complementos para el juego que facilitan la vida de los jugadores hardcore, fanáticos casuales, fanáticos para medir su efectividad y otros habitantes del mundo del juego. Fuera de gamedev, Lua se utiliza como lenguaje de programación de sistemas integrados (televisores, impresoras, paneles de automóviles), así como aplicaciones, por ejemplo, el VLC Media Player. Lua utiliza herramientas como Tarantool, Redis y OpenResty como lenguaje incorporado. Lua también se usó como un lenguaje de extensión para los códigos computacionales de Fortran que simulan el comportamiento termomecánico del combustible nuclear.

¿Por qué lua?


IPONWEB es un desarrollador de plataformas altamente cargadas para empresas que trabajan en el campo de la publicidad en línea: DSP, SSP, agencias de publicidad y anunciantes. Hablamos en detalle sobre nuestro trabajo en este artículo . Al principio, desarrollamos la lógica de negocios de nuestras plataformas en C ++, pero rápidamente nos dimos cuenta de que esta no era la mejor opción. Para minimizar los costos, el rendimiento de la plataforma es importante, así como la velocidad de desarrollo, y el desarrollo de C ++ resultó ser demasiado lento para nosotros, y la complejidad de agregar funcionalidad también se vio afectada. Decidimos aislar la interpretación de la lógica empresarial del código del servidor de bajo nivel, comenzamos a buscar un lenguaje adecuado para esto y nos decidimos por Lua. Fue en 2008, las implementaciones de JavaScript que eran adecuadas para nosotros todavía no existían, Perl, Python y Ruby eran demasiado lentas y no fáciles de integrar. Y estaba el lenguaje Lua, no muy famoso, pero popular en el desarrollo de juegos, y lo que queríamos era similar a las necesidades de los desarrolladores de juegos: necesitábamos un motor rápido para operaciones de bajo nivel y un lenguaje rápido fácil de construir para la lógica empresarial.

Lua es realmente un lenguaje muy rápido. Se puede lograr un aumento adicional de la velocidad utilizando LuaJIT , el entorno de tiempo de ejecución para Lua 5.1, que incluye un compilador JIT de seguimiento (utilizamos nuestro propio fork, sobre el que ya escribimos ). Dado que escribimos lógica de negocios para sistemas RTB , la velocidad es crítica para nosotros: en RTB, en promedio, hay 120 milisegundos para procesar cada solicitud entrante. Al mismo tiempo, solo se asignan de 10 a 15 milisegundos para la ejecución del código, y el resto del tiempo está esperando una respuesta de otros servicios. Si, por ejemplo, el usuario ni siquiera nota un retraso de medio segundo al cargar un sitio en la red, entonces para RTB estos 500 milisegundos son un período de tiempo enorme. La respuesta a la pregunta de qué tan rápido es el lenguaje Lua: es lo suficientemente rápido como para que podamos escribir lógica de negocios en él durante muchos años y permanecer en el negocio RTB. Si el idioma que elegimos no fuera lo suficientemente rápido, no tendríamos a nadie para quien escribir la plataforma. ¿Esto significa que RTB no se puede escribir en otros idiomas? No significa Pero escribimos RTB en Lua y hacemos frente con éxito a nuestras tareas comerciales y las de los clientes. Un buen ejemplo de la velocidad de Lua en el servidor es este punto de referencia OpenResty.

Lua como lenguaje incorporado tiene muchas ventajas: es minimalista, compacto, con una biblioteca estándar muy pequeña. Su funcionalidad está completamente duplicada en C, lo que proporciona una interacción fácil y "fluida" entre Lua y C. Lua tiene un umbral de inicio de sesión bastante bajo en comparación con muchos otros lenguajes: la mayoría de los programadores que vienen a trabajar en IPONWEB nunca han escrito en Lua antes, pero tienen suficiente varios días para participar plenamente en el trabajo.

Aquí hay un ejemplo simple de apuntar a una audiencia publicitaria.

-- 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 

Y así es como se ve un controlador simple (controlador de eventos).

 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 

La simplicidad de Lua no solo proporciona un desarrollo rápido, sino que también le permite hacer mucho trabajo con poco esfuerzo. La plataforma IPONWEB es una solución general que se adapta a las necesidades de un cliente en particular, mientras que un desarrollador y un gerente pueden llevar a cabo el proyecto. Leer el código en Lua puede no solo a los propios desarrolladores, sino también a los gerentes de proyectos y, a veces, a los clientes. Juntos, descubrimos rápidamente el problema, encontramos su causa y solución. A menudo, el gerente del proyecto informa al desarrollador sobre el problema e inmediatamente sugiere una forma de resolverlo.

Al mismo tiempo, la simplicidad de Lua puede ser engañosa, mientras que el minimalismo y la compacidad tienen un inconveniente. Si el código está escrito, por ejemplo, en Perl o Python, el desarrollador tiene a su disposición enormes repositorios de módulos listos para usar, Ruby tiene RubyGems y muchos otros idiomas tienen repositorios ricos. Y Lua tiene LuaRocks y los tres mil módulos que yacen allí. Además, incluso si LuaRocks tiene el módulo correcto, es muy probable que tenga que trabajar duro para usarlo en una empresa en particular. Lua proporciona buenas herramientas para crear un entorno seguro para ejecutar código (sandboxes), y cuando se trabaja en sandboxes, algunas funciones se pueden deshabilitar. Esto significa que los módulos LuaRocks pueden no funcionar si usan funciones que están bloqueadas por el entorno seguro de la compañía. Este es el precio de la compacidad y la capacidad de integración, pero vale la pena: los lenguajes con baterías, como, por ejemplo, Python, se construyen de una manera no más complicada que Lua.

Como funciona


La base de nuestra plataforma es un servidor HTTP personalizable con una API conveniente y extensible que proporciona un conjunto de funciones para el desarrollador de Lua y se adapta a las tareas del mercado publicitario. Este servidor procesa cientos de millones de solicitudes y escribe terabytes de registros por día. Las solicitudes entrantes se distribuyen uniformemente entre los hilos del sistema, y ​​dentro de los hilos del sistema hay cajas de arena.

imagen

Cuando llega una solicitud al servidor, se crea una rutina dentro del entorno limitado en el que cayó esta solicitud, que procesa la solicitud. Las rutinas funcionan independientemente unas de otras, cada una de las que se está creando se pone en cola para su ejecución. La vida útil de cada rutina (el tiempo de procesamiento total de la solicitud, teniendo en cuenta la respuesta esperada de los servicios involucrados: base de datos, métricas, servidor de presupuesto) no debe exceder los 120 milisegundos.



En resumen, el proceso de procesamiento de solicitudes se puede describir de la siguiente manera:

  1. Cada solicitud recibida se analiza y pasa un chequeo estándar para su corrección.
  2. Se lanza Corutin, que se encarga de procesar esta solicitud. Dentro de cada caja de arena, hay muchas corutinas en diferentes estados.
  3. Comienza el procesamiento de solicitudes, que puede tener dos resultados:
    • Procesamiento completado con éxito.
    • Corutin transfiere el control al servidor. Esto generalmente ocurre cuando la rutina está esperando una respuesta de otros servicios. En tales casos, el trabajo de la corutina se suspende hasta que llegue una respuesta o expire el tiempo de espera. Al transferir el control, el servidor comienza a procesar la siguiente solicitud. Puede ser una nueva solicitud o una solicitud que recibe una respuesta de todos los servicios involucrados y está lista para continuar ejecutando el código. El orden de procesamiento de las solicitudes está determinado por los requisitos de la lógica empresarial.


El uso de corutina es otro tema interesante que merece una discusión detallada. Por ejemplo, este artículo detalla cómo se pueden utilizar las corutinas para crear escenas en videojuegos. Y las rutinas en el servidor de aplicaciones deberían dedicar un artículo separado, y quizás en el futuro lo hagamos.

Que sigue


Y luego, quizás, se ampliará el uso de Lua en IPONWEB. Tenemos ideas sobre cómo puede seguir utilizando Lua en nuestro negocio, y cuando se implementen estas ideas, definitivamente compartiremos nuevas experiencias. La conveniencia y las capacidades de Lua como lenguaje de script integrado pueden ayudarnos, en particular, a acelerar el procesamiento de los datos del cliente. Pero esto todavía es del campo de los planes y las perspectivas.

En resumen, podemos decir que nuestra elección del lenguaje de la lógica empresarial, realizada hace 11 años, continúa justificándose, permitiéndonos hacer frente con éxito a nuestras propias tareas comerciales y ayudarnos a resolver los problemas de nuestros clientes. Fácil de leer, fácil de integrar, rápido y fácil de aprender, Lua ha sido y sigue siendo uno de los mejores lenguajes de secuencias de comandos, cuyo alcance no se limita en modo alguno al desarrollo de juegos. La lógica empresarial de IPONWEB escrita en él es solo un ejemplo de esto.

Source: https://habr.com/ru/post/469049/


All Articles