49
Walled Garden Redu

Redu walled garden

Embed Size (px)

DESCRIPTION

Apresentará as motivações e lições aprendidas na criação de uma aplicação de larga escala orientada a serviços. Entenda como fatores como performance, estilos de comunicação e produtividade da equipe relacionam-se à estruturação de uma aplicação.

Citation preview

Page 1: Redu walled garden

Walled GardenRedu

Page 2: Redu walled garden

Apresentações

Page 3: Redu walled garden

Guilherme Cavalcanti

github.com/guiocavalcanti

Tiago Ferreiragithub.com/fltiago

Page 4: Redu walled garden
Page 5: Redu walled garden

Plataforma de educação a distância construída em uma estrutura de rede social

redu.com.br

Page 6: Redu walled garden

Walled Garden

Page 7: Redu walled garden

Monolítica Serviços

Redu

Analytics

Core

App Store

Page 8: Redu walled garden

Serviços

• Resposabilidades bem definidas

• API REST

• Privados

• On going process

• “Desmembrar” serviços

Analytics

Core

App Store

Page 9: Redu walled garden

Vantagens

• Evolução indepentente

• Liberdade de tecnologia

• Menos overhead de comunicação entre pessoas

Analytics

Core

App Store

Page 10: Redu walled garden

CoreVis Apps

Walled Garden

Page 11: Redu walled garden

Untiedgithub.com/redu/untied

Page 12: Redu walled garden

Acoplamento entre serviços

• Comunicação “um para muitos”

• Identidade de serviços

Page 13: Redu walled garden

Acoplamento entre serviços

Core

Vis

Apps

N

...

Page 14: Redu walled garden

spaghettiService

Page 15: Redu walled garden

Disponibilidade e tolerância

• Como lidar com não disponibilidade do serviço?

• Estratégia de retry no cliente

• Em casos de falhas de HTTP

Page 16: Redu walled garden

Disponibilidade e tolerância

Core

Vis

N

...

x

Page 17: Redu walled garden

Message Bus

Page 18: Redu walled garden

Ideia

• Canal de comunicação transversal entre todos os serviços

• Propagação de representações do domain model (RESTishy)

Page 19: Redu walled garden

The real Walled Garden

CoreVis Apps

Message Bus

Page 20: Redu walled garden

Messaging that just works

Page 21: Redu walled garden

Upsides

• Tolerância a falhas (dos consumers)

• O trabalho do publisher termina ao enviar a mensagem para o exchanger

• Garantia de entrega

Page 22: Redu walled garden

Untied Publishergithub.com/redu/untied

Page 23: Redu walled garden

Doorkeeper

class  DoorkeeperWithRepresenter    include  Untied::Doorkeeper

   def  initialize        watch  User,  :after_create,  represent_with:  UserRepresenter        watch  Course,  :after_create,  represent_with:  CourseRepresenter    endend

Page 24: Redu walled garden

Features

• ActiveRecord lifecycle

• Propaga representações, não domain models

• Multiplos adapters (Bunny & AMQP)

Page 25: Redu walled garden

Untied Consumergithub.com/redu/untied

Page 26: Redu walled garden

Observer

class  Builder  <  Untied::Consumer::Observer    observe  :user,  from:  "social-‐network"      def  build(attrs)        LeanUser.new(attrs)    end    alias_method  :after_create,  :buildend

• Lifecycle

• Configuração

• Framework agnostic

Page 27: Redu walled garden

“Daemonizable”

$  ruby  consumerd.rb  start$  ruby  consumerd.rb  statusuntiedc:  running  [pid  52324]$  ruby  consumerd.rb  stopuntiedc:  trying  to  stop  process  with  pid  52324...untiedc:  process  with  pid  52324  successfully  stopped.

worker  =  Untied::Consumer::Worker.newworker.daemonize(pids_dir:  pids_dir,  log_dir:  log_dir)

• gem “deamons”

• Monit, god, etc

Page 28: Redu walled garden

Untied Pluginsgithub.com/redu/untied-consumer-sync

Page 29: Redu walled garden

Padrões comuns

• Untied Consumer Sync

• Abstraí o padrão de replicar entidades através de vários serviços

Page 30: Redu walled garden

Como?

Untied::Consumer::Sync.configure  do  |config|    config.model_data  =  "mappings.yml"end

User:  #  Payload's  type    attributes:  #  Needed  attributes        -‐  id        -‐  login        -‐  first_name        -‐  last_name    mappings:        id:  core_id  #  Maps  payload's  id  key  to  model's  core_id  column    name:  LeanUser  #  Model  name

• Configuração

• Definição de atributos

• Definição de mapeamentos

• ActiveRecord

• Mongoid

Page 31: Redu walled garden

Vis

Page 32: Redu walled garden

Objetivos

• Garantia de entrega

• Assíncrono e escalável

• Fail-safe

• Independente de Framework

Page 33: Redu walled garden

Big Picture

Core VismongoDB

HTTP

Page 34: Redu walled garden

Solução

• MongoDB

• Dados não estruturados

• Possibilidade de guardar estrutura de dados complexas

• Mais facilmente escalável

• Boa biblioteca de consulta

Page 35: Redu walled garden

Solução

• Aplicação isolada (fail-safe)

• Interação através de uma API REST

• em-http-request (requisições assíncronas e paralelas)

Page 36: Redu walled garden

Implementação inicial

• Cliente da API (VisClient) bem simples

• Uso do em-http-request para envio de requisições de forma assíncrona e paralela

• Falhas logadas em arquivos

• Uso extensivo de Observers

Page 37: Redu walled garden

Requisições

• Assíncronas

• Logs em arquivos

def  send_async_info(params,  url)    if  EM.reactor_running?        do_request(params,  url,  true)    else        ...    endend  def  do_request(params,  url,  self_reactor)    http  =  EM::HttpRequest.new(url).post({:body  =>  params.to_json  })      http.callback  do        ...        rescue              log.error  "log  goes  here..."        end        EM.stop  unless  self_reactor    end      http.errback    do        ...        rescue            log.error  "log  goes  here..."        end        EM.stop  unless  self_reactor    endend

Page 38: Redu walled garden

Requisições

• Paralelas

• Logs em arquivos

def  send_multi_request    ...    em  do        multi  =  EventMachine::MultiRequest.new                enrollments.each_with_index  do  |enroll,  idx|            multi.add  idx,  EM::HttpRequest.new(url).post({                :body  =>  enroll.to_json  })        end          multi.callback  do            multi.responses[:errback].each  do  |err|                logger.error  "logs  goes  here..."            end              EM.stop  unless  @running        end    endend

Page 39: Redu walled garden

Parâmetros

• Preenchidos manualmente

• Acesso a múltiplos modelos

def  fill_enroll_params(enrollment_id,  type)    ...    if  enrollment        course  =  enrollment.subject.space.course        params  =  {            :user_id  =>  enrollment.user_id,            :type  =>  type,            :lecture_id  =>  nil,            :subject_id  =>  enrollment.subject_id,            :space_id  =>  enrollment.subject.space.id,            :course_id  =>  course.id,            ...            :created_at  =>  enrollment.created_at,            :updated_at  =>  enrollment.updated_at        }    else        nil    endend

Page 40: Redu walled garden

Lições aprendidas

Page 41: Redu walled garden

Lições Aprendidas

• Não havia interface única para envio das notificações, ou seja, código espalhado e de difícil manutenção

• O em-http-request é construído em cima do EventMachine

• Logar em arquivos com propósito de recuperar falhas é uma bola de neve

Page 42: Redu walled garden

Lições Aprendidas

• Lidar com requisições paralelas é difícil

• Pouco workers do nginx para muitas requisições paralelas

• Difícil depuração

Page 43: Redu walled garden

Atualmente

Page 44: Redu walled garden

Atualmente• Delayed Job lida com falhas e reenvios de

uma forma atômica

• VisClient responsável por criar Jobs e construir os parâmetros

• Simples depuração e detecção de falhas

• Uso de representersgithub.com/apotonick/roar

Page 45: Redu walled garden

New vis client

• Envio de requisições (Faraday)

• Lógica de criação de jobs

• Lógica de parametrização

def  self.notify_delayed(resource,  type,  args)    elements  =  args.respond_to?(:map)  ?  args  :  [args]    notifier_builder  =  NotifierBuilder.new(resource,                                            type,  elements)    notifier_builder.buildend

Page 46: Redu walled garden

Representermodule  Vis    module  EnrollmentVisRepresenter        include  Roar::Representer::JSON          property  :user_id        property  :subject_id        property  :space_id        property  :course_id        property  :created_at        property  :updated_at          def  space_id            self.subject.space.id        end          def  course_id            self.subject.space.course.id        end    endend

Page 47: Redu walled garden

Futuro próximo

Page 48: Redu walled garden

Futuro

• Vis vai se tornar provedora de Relatórios e Visualizações

• não haverá API de consulta

• relatórios e visualizações estarão em Vis, front-end incluso

• inclusão será feita através de iframe