Por que escrevemos lógica de negócios em Lua

Oi Habr. Neste post, queremos falar sobre como e por que usamos uma linguagem de programação com o belo nome Lua no IPONWEB.

Lua é uma linguagem de programação embarcada baseada em script, com intérprete gratuito e código aberto em C. Foi desenvolvida em 1993 no Brasil, na divisão Tecgraf da Universidade Católica do Rio de Janeiro, e seus progenitores eram DEL (Data-Entry Language) e SOL (Linguagem de Objeto Simples) desenvolvida lá anteriormente. Um dos progenitores, a língua SOL, participou indiretamente do “batismo” do recém-nascido - “Sol” é traduzido do português como “sol”, e o novo idioma foi nomeado “Lua”, “lua”.

A facilidade de incorporar Lua em mecanismos escritos em linguagens de "sistema" tornou uma linguagem de script popular para videogames. Por exemplo, os scripts são escritos em Lua no Grim Fandango e no Baldur's Gate. Aqueles que jogam World of Warcraft também provavelmente já ouviram falar de Lua mais de uma ou duas vezes - é aí que os complementos do jogo são criados para facilitar a vida de jogadores hardcore, fãs casuais, fãs, para medir sua eficácia e outros habitantes do mundo do jogo. Fora do gamedev, Lua é usada como a linguagem de script de sistemas embarcados (TVs, impressoras, painéis de automóveis), além de aplicativos, por exemplo, o VLC Media Player. Lua usa ferramentas como Tarantool, Redis e OpenResty como uma linguagem incorporada. Lua também foi usada como uma linguagem de extensão para os códigos computacionais do Fortran, simulando o comportamento termomecânico do combustível nuclear.

Por que Lua?


A IPONWEB é desenvolvedora de plataformas altamente carregadas para empresas que trabalham no campo da publicidade on-line: DSP, SSP, agências de publicidade e anunciantes. Falamos em detalhes sobre o nosso trabalho neste artigo . Inicialmente, desenvolvemos a lógica comercial de nossas plataformas em C ++, mas rapidamente percebemos que essa não era a melhor opção. Para minimizar os custos, o desempenho da plataforma é importante, bem como a velocidade de desenvolvimento, e o desenvolvimento de C ++ acabou sendo muito lento para nós, e a complexidade de adicionar funcionalidades também foi afetada. Decidimos isolar a interpretação da lógica de negócios do código do servidor de baixo nível, começamos a procurar uma linguagem adequada para isso e resolvemos Lua. Em 2008, as implementações de JavaScript adequadas para nós ainda não existiam, Perl, Python e Ruby eram muito lentos e não eram fáceis de integrar. E havia a linguagem Lua, não muito famosa, mas popular no desenvolvimento de jogos, e o que queríamos era semelhante às necessidades dos desenvolvedores de jogos - precisávamos de um mecanismo rápido para operações de baixo nível e de uma linguagem rápida fácil de construir para a lógica de negócios.

Lua é realmente uma linguagem muito rápida. Um aumento adicional na velocidade pode ser alcançado usando o LuaJIT , o ambiente de tempo de execução do Lua 5.1, que inclui um compilador JIT de rastreamento (usamos nosso próprio fork, sobre o qual já escrevemos ). Como escrevemos a lógica comercial dos sistemas RTB , a velocidade é fundamental para nós: no RTB, em média, existem 120 milissegundos para processar cada solicitação recebida. Ao mesmo tempo, apenas 10 a 15 milissegundos são alocados para a execução do código e o restante do tempo aguarda uma resposta de outros serviços. Se, por exemplo, o usuário nem perceber um atraso de meio segundo ao carregar um site na rede, então para RTB esses 500 milissegundos são um período de tempo enorme. A resposta para a pergunta sobre a rapidez com que a linguagem Lua é: é rápida o suficiente para que possamos escrever nela uma lógica de negócios por muitos anos e permanecer no negócio de RTB. Se o idioma escolhido não fosse rápido o suficiente, não teríamos ninguém para quem escrever a plataforma. Isso significa que o RTB não pode ser escrito em outros idiomas? Não significa Mas nós escrevemos RTB em Lua e lidamos com sucesso com nossas tarefas comerciais e clientes. Um bom exemplo da velocidade de Lua no servidor é esse benchmark do OpenResty.

Lua como uma linguagem incorporada tem muitas vantagens: é minimalista, compacta, com uma biblioteca padrão muito pequena. Sua funcionalidade é completamente duplicada em C, o que fornece uma interação fácil e "perfeita" entre Lua e C. Lua tem um limite de login bastante baixo em comparação com muitas outras linguagens: a maioria dos programadores que trabalham no IPONWEB nunca escreveu para Lua antes, mas eles têm o suficiente vários dias para se envolver totalmente no trabalho.

Aqui está um exemplo simples de segmentação para um público publicitário.

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

E é assim que um manipulador simples (manipulador de eventos) se parece.

 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 

A simplicidade do Lua não apenas fornece desenvolvimento rápido, mas também permite que você trabalhe muito com pouco esforço. A plataforma IPONWEB é uma solução geral adaptada às necessidades de um cliente específico, enquanto um desenvolvedor e um gerente podem conduzir o projeto. Leia o código em Lua não só os próprios desenvolvedores, mas também os gerentes de projeto e, às vezes, os clientes. Juntos, descobrimos rapidamente o problema, encontramos sua causa e solução. Muitas vezes, o gerente de projeto informa o desenvolvedor sobre o problema e sugere imediatamente uma maneira de resolvê-lo.

Ao mesmo tempo, a simplicidade de Lua pode enganar, enquanto o minimalismo e a compacidade têm uma desvantagem. Se o código é escrito, por exemplo, em Perl ou Python, o desenvolvedor tem à sua disposição enormes repositórios de módulos prontos, Ruby possui RubyGems e muitas outras linguagens possuem repositórios avançados. E Lua tem LuaRocks e os três mil módulos que estão lá. Além disso, mesmo se o LuaRocks tiver o módulo certo, é altamente provável que você tenha que trabalhar duro para usá-lo em uma empresa específica. Lua fornece boas ferramentas para criar um ambiente seguro para a execução de código (caixas de areia) e, ao trabalhar em caixas de areia, algumas funções podem ser desabilitadas. Isso significa que os módulos LuaRocks podem não funcionar se eles usarem funções bloqueadas pelo ambiente seguro da empresa. Esse é o preço da compactação e da capacidade de incorporação, mas vale o preço - idiomas com baterias, como, por exemplo, Python, são construídos de maneira não mais complicada que Lua.

Como isso funciona?


A base de nossa plataforma é um servidor HTTP personalizável com uma API conveniente e extensível que fornece um conjunto de funções para o desenvolvedor Lua e é adaptado para as tarefas do mercado publicitário. Esse servidor processa centenas de milhões de solicitações e grava terabytes de logs por dia. As solicitações de entrada são distribuídas igualmente pelos threads do sistema e dentro dos threads do sistema existem caixas de proteção.

imagem

Quando uma solicitação chega no servidor, uma corotina é criada dentro da sandbox na qual essa solicitação caiu, que processa a solicitação. As corotinas funcionam independentemente uma da outra, cada corotina criada é enfileirada para execução. O tempo de vida de cada corotina (o tempo total de processamento da solicitação, levando em consideração a resposta esperada dos serviços envolvidos: banco de dados, métricas, servidor de orçamento) não deve exceder 120 milissegundos.



Em resumo, o processo de processamento de solicitações pode ser descrito da seguinte maneira:

  1. Cada solicitação recebida é analisada e passa em uma verificação padrão de correção.
  2. Corutin é lançado, responsável pelo processamento desta solicitação. Dentro de cada sandbox, existem muitas corotinas em diferentes status.
  3. O processamento da solicitação é iniciado, o que pode ter dois resultados:
    • Processamento concluído com sucesso.
    • Corutin transfere o controle para o servidor. Isso geralmente acontece quando a corotina está aguardando uma resposta de outros serviços. Nesses casos, o trabalho do corutin é suspenso até que uma resposta chegue ou o tempo de espera expire. Ao transferir o controle, o servidor começa a processar a próxima solicitação. Pode ser uma nova solicitação ou uma solicitação que recebe uma resposta de todos os serviços envolvidos e está pronta para continuar executando o código. A ordem dos pedidos de processamento é determinada pelos requisitos da lógica de negócios.


O uso de corutin é outro tópico interessante que merece uma discussão detalhada. Por exemplo, este artigo detalha como as corutinas podem ser usadas para criar cenas em videogames. E as corotinas no servidor de aplicativos devem dedicar um artigo separado, e talvez no futuro o façamos.

O que vem a seguir?


E então, talvez, o uso de Lua no IPONWEB seja expandido. Temos idéias sobre como você ainda pode usar Lua em nossos negócios e, quando essas idéias forem implementadas, compartilharemos definitivamente novas experiências. A conveniência e os recursos de Lua como uma linguagem de script incorporada podem nos ajudar, em particular, a acelerar o processamento de dados do cliente. Mas isso ainda é do campo de planos e perspectivas.

Em resumo, podemos dizer que nossa escolha da linguagem da lógica de negócios, feita há 11 anos, continua a justificar-se, permitindo-nos lidar com sucesso com nossas próprias tarefas de negócios e nos ajudar a resolver os problemas de nossos clientes. Fácil de ler, fácil de integrar, rápido e fácil de aprender, Lua tem sido e continua sendo uma das melhores linguagens de script, cujo escopo não se limita ao desenvolvimento de jogos. A lógica de negócios IPONWEB escrita nele é apenas um exemplo disso.

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


All Articles