SlideShare uma empresa Scribd logo
1 de 143
Baixar para ler offline
O que aprendi após 3 bilhões
de jobs processados no Sidekiq
Anderson Dias
@extendsmymind
https://medium.com/@extendsmymind
onde trabalho
Carlos Brando

CTO no Enjoei :P
Daniel Romero

ex-devops no Enjoei :P
biblioteca de processamento
assíncrono em ruby
revisão rápida
como funciona o sidekiq?
class ImagesController < ApplicationController
def create
@image = Image.create(params[:image])
@image.process
end
end
operação síncrona bloqueante
class ImagesController < ApplicationController
def create
@image = Image.create(params[:image])
ImageProcessor.perform_async(@image.id)
end
end
operação assíncrona não bloqueante
anatomia de um worker
class ImageProcessor
include Sidekiq::Worker
sidekiq_options queue: 'low', retry: true
def perform(image_id)
image = Image.find(image_id)
image.process
end
end
workers
class ImageProcessor
include Sidekiq::Worker
sidekiq_options queue: 'low', retry: true
def perform(image_id)
image = Image.find(image_id)
image.process
end
end
configurações do worker
class ImageProcessor
include Sidekiq::Worker
sidekiq_options queue: 'low', retry: true
def perform(image_id)
image = Image.find(image_id)
image.process
end
end
parâmetros do worker
invocando jobs
ImageProcessor.perform_async(1)
ImageProcessor.perform_in(5.minutes, 1)
ImageProcessor.perform_at(5.minutes.from_now, 1)
ImageProcessor.set(queue: :critical).perform_async(1)
Sidekiq::Client.push('class' => ImageProcessor, 'args' => [1])
diversas formas de executar um job
executando o sidekiq
diversas formas de executar
sidekiq # executa com a configuração padrão
sidekiq -c 25 # 25 de concorrência
sidekiq -q default -q high # executa duas filas
monitoramento
os erros mais comuns

que cometi
os erros mais comuns

que cometi
idiotas
Dica #1:

não seja enganado pelos

seus testes unitários
class NamedParamsWorker
include Sidekiq::Worker
def perform(a: , b: )
...
end
end
RSpec.describe NamedParamsWorker do
describe '#perform' do
it 'prints information' do
subject.perform(a: 1, b: 1)
end
end
end
seus testes unitários podem te enganar
class HashParamsWorker
include Sidekiq::Worker
def perform(params)
logger.info params[:a]
end
end
RSpec.describe HashParamsWorker do
describe '#perform' do
it 'prints information' do
subject.perform(a: 1, b: 1)
end
end
end
RSpec.describe NamedParamsWorker do
describe '#perform' do
it 'prints information' do
subject.perform(a: 1, b: 1)
end
end
end
RSpec.describe HashParamsWorker do
describe '#perform' do
it 'prints information' do
subject.perform(a: 1, b: 1)
end
end
end
seus testes unitários podem te enganar
require 'sidekiq/testing'
RSpec.describe NamedParamsWorker do
describe '#perform' do
it 'prints information' do
Sidekiq::Testing.inline! do
described_class.perform_async(a: 1, b: 1)
end
end
end
end
teste utilizando chamada inline, funciona?
RSpec.describe HashParamsWorker do
describe '#perform' do
it 'prints information' do
described_class.perform_async(a: 1, b: 1)
described_class.drain
end
end
end
utilize o .drain para simular as chamadas

reais à API do Sidekiq
Dica #2:

sempre faça parsing de datas
class ReportWorker
include Sidekiq::Worker
def perform(until_date)
objects = Model.where('created_at <= ?', until_date)
end
end
# Fri, 20 Oct 2017 19:00:00 BRST -02:00
ReportWorker.perform_async(1.day.ago)
o que acontece se:
SELECT "models".*
FROM "models"
WHERE (created_at <= '2017-10-20 19:00:00 -0200')
tudo ok, não?
SELECT "models".*
FROM "models"
WHERE (created_at <= '2017-10-20 19:00:00 -0200')
não, o filtro pela data está errado.
class ReportWorker
include Sidekiq::Worker
def perform(until_date)
parsed_time = Time.zone.parse(until_date)
objects = Model.where('created_at <= ?', parsed_time)
end
end
sempre que receber uma data,

faça parse dela no timezone atual
SELECT "models".*
FROM "models"
WHERE (created_at <= '2017-10-20 21:00:00.000000')
data passada com timezone correto
Dica #3:

nunca confie que o job vai ser
executado imediatamente
salvando histórico de intenções de compra
class PurchasesController < ApplicationController
def new
@product = Product.find(params[:product_id])
StorePurchaseIntentWorker.perform_async(current_user.id,
@product.id)
end
end
salvando histórico de intenções de compra
class StorePurchaseIntentWorker
include Sidekiq::Worker
def perform(user_id, product_id)
PurchaseIntent.create(user_id: user_id,
product_id: product_id)
end
end
salvando histórico de intenções de compra
class StorePurchaseIntentWorker
include Sidekiq::Worker
def perform(user_id, product_id)
PurchaseIntent.create(user_id: user_id,
product_id: product_id)
end
end
salvando histórico de intenções de compra
class StorePurchaseIntentWorker
include Sidekiq::Worker
def perform(user_id, product_id, created_at)
PurchaseIntent.create(
user_id: user_id,
product_id: product_id,
created_at: Time.zone.parse(created_at)
)
end
end
Dica #4:
sempre criptografe

dados sensíveis
processando compras com cartão de crédito
class CreditCardPurchaseWorker
include Sidekiq::Worker
def perform(purchase_id, number, name, expiration_date, cvc)
...
end
end
é possível visualizar os dados via sidekiq/web
credit_card_params = {
number: '4444333322221111', name: 'Joao Silva',
expiration_date: ’10/20', cvc: '123'
}
json_credit_card_params = credit_card_params.to_json
SecureCreditCardPurchaseWorker.perform_async(
14151,
json_credit_card_params.encrypt(
:symmetric,
password: ENV['SECRET_KEY_BASE']
)
)
criptografando os dados do cartão
decriptografando os dados do cartão
class SecureCreditCardPurchaseWorker
include Sidekiq::Worker
def perform(purchase_id, cryptographed_credit_card)
@cryptographed_credit_card = cryptographed_credit_card
credit_card_information = JSON.parse(decrypted_credit_card)
puts credit_card_information['number']
end
private
def decrypted_credit_card
@cryptographed_credit_card.decrypt(
:symmetric,
password: ENV['SECRET_KEY_BASE']
)
end
end
dados ilegíveis no sidekiq/web
Dica #5:
evite ao máximo utilizar delay
delay era bem comum antes do Sidekiq 5
UserMailer.delay.welcome_email(@user.id)
User.delay_until(2.weeks.from_now).whatever
@product.delay.destroy
porém no Sidekiq 5…
Delayed Extensions
desativadas por padrão.
nós bagunçamos a parada :P
o grande problema
UserMailer.delay.welcome_email(@user.id)
User.delay_until(2.weeks.from_now).whatever
@product.delay.destroy
usando da forma correta
utilizando da forma errada
a regra é
# Ao invés de:
@product.delay.destroy
# Prefira:
Product.delay.destroy(@product.id)
ProductDestroyerWorker.perform_async(@product.id)
Dica #6:
muito cuidado com os logs
Sidekiq é extremamente verboso
crie uma forma fácil de ativar/desativar

logs através de ENV vars
# config/initializers/sidekiq.rb
if (ENV["SIDEKIQ_LOGS_DISABLED"] == "true")
Sidekiq::Logging.logger = nil
end
dicas para o sidekiq pro
Sidekiq Batch
o que são batches
batch = Sidekiq::Batch.new
batch.jobs do
FirstWorker.perform_async

SecondWorker.perform_async
end
Dica #7:
cuidado com iterações, pois
batches são atômicos
qual o erro aqui?
batch = Sidekiq::Batch.new
products.find_each do |product|
batch.jobs { ProductWorker.perform_async(product.id) }
end
agende todos os jobs dentro

de uma única chamada de batch.jobs
batch = Sidekiq::Batch.new
batch.jobs do
products.find_each do |product|
ProductWorker.perform_async(product.id)
end
end
Dica #8:
cuidado com jobs únicos
dentro de batches
o que acontece?
batch = Sidekiq::Batch.new
batch.jobs do
UniqueWorker.perform_async(1)
raise
end
batch = Sidekiq::Batch.new
batch.jobs do
UniqueWorker.perform_async(1)
UniqueWorker.perform_async(2)
end
não, o sidekiq só processou 1 job do batch
https://github.com/mperham/sidekiq/issues/3662
Dica #9:
cuidado ao utilizar operações
destrutivas em batches
qual o problema aqui?
class EnqueueInvitationEmailWorker
include Sidekiq::Worker
def perform
batch = Sidekiq::Batch.new
batch.jobs do
while attributes = EmailSerializer.pop
SendInvitationEmailWorker.perform_async(attributes)
end
end
end
end
nesse caso é melhor não utilizar batch
class EnqueueInvitationEmailWorker
include Sidekiq::Worker
def perform
while attributes = EmailSerializer.pop
SendInvitationEmailWorker.perform_async(attributes)
end
end
end
dicas para o sidekiq
enterprise
Dica #10:
criptografe dados sensíveis

(versão enterprise)
criptografando parâmetros manualmente
require 'encrypted_strings'
require 'json'
credit_card_params = {}.to_json
encrypted_params = credit_card_params.encrypt(:symmetric, password: ENV['SECRET_KEY_BASE'])
SecureCreditCardPurchaseWorker.perform_async(12, encrypted_params)
class SecureCreditCardPurchaseWorker
include Sidekiq::Worker
def perform(purchase_id, cryptographed_credit_card)
credit_card_information = decrypted_credit_card(cryptographed_credit_card)
end
def decrypted_credit_card(cryptographed_credit_card)
JSON.parse(cryptographed_credit_card.decrypt(:symmetric, password: ENV['SECRET_KEY_BASE']))
end
end
configurando a extensão ent encryption
# config/initializers/sidekiq.rb
version = ENV.fetch('SIDEKIQ_CRYPTO_VERSION')
Sidekiq::Enterprise::Crypto.enable(active_version: version) do |version|
Base64.decode64(ENV.fetch("SIDEKIQ_CRYPTO_KEY_V#{version}"))
end unless Rails.env.test?
# .env
SIDEKIQ_CRYPTO_VERSION=2
SIDEKIQ_CRYPTO_KEY_V1=XXXXXXXX
SIDEKIQ_CRYPTO_KEY_V2=YYYYYYYY
utilizando ent encryption em um worker
class SecureCreditCardPurchaseWorker
include Sidekiq::Worker
sidekiq_options encrypt: true
def perform(purchase_id, cryptographed_credit_card)
puts cryptographed_credit_card['number']
end
end
credit_card_params = {
number: '4444333322221111', name: 'Joao Silva',
expiration_date: '10/20', cvc: '123'
}
SecureCreditCardPurchaseWorker.perform_async(12341, credit_card_params)
utilizando ent encryption em um worker
mais exemplos: somente o último

parâmetro será criptografado
escalando o sidekiq
organização de queues
PaymentProcessorWorker

queue: default
ImageProcessorWorker

queue: default
SalesReportWorker

queue: default
Rápido e crítico Lento e não crítico Lento, pesado e não crítico
sidekiq -c 10 -q default
10 50 1
múltiplos workers em fila única
Pros Contras
Fácil manutenção
Processos críticos podem
demorar muito a processar
quando houverem muitos jobs
de baixa prioridade
PaymentProcessorWorker

queue: critical
ImageProcessorWorker

queue: default
SalesReportWorker

queue: low
Rápido e crítico Lento e não crítico Lento, pesado e não crítico
sidekiq -c 10 -q critical -q default -q low
10 50 1
múltiplas filas priorizadas
Pros Contras
Divisão clara de processos por
níveis de prioridade.
Existe risco de acúmulo de jobs
nas filas de menor prioridade se
houver alto volume de jobs nas
filas mais priorizadas.
PaymentProcessorWorker

queue: critical
ImageProcessorWorker

queue: default
SalesReportWorker

queue: low
Rápido e crítico Lento e não crítico Lento, pesado e não crítico
sidekiq -c 10 -q critical,4 -q default,2 -q low,1
10 50 1
múltiplas filas com pesos diferentes
Pros Contras
Com um único processo do
sidekiq você tem priorização
sem que as filas fiquem
esperando umas as outras.
Processos pesados ainda
podem interferir diretamente na
performance de processos
críticos.
PaymentProcessorWorker

queue: critical
ImageProcessorWorker

queue: default
SalesReportWorker

queue: low
Rápido e crítico Lento e não crítico Lento, pesado e não crítico
sidekiq -c 10 -q critical
10 50 1
processos isolados para cada queue
Pros Contras
Isolamento completo de cada fila
Controle de escala de cada
queue individual
Sonho?
Maior consumo de memória/
máquina
sidekiq -c 10 -q default sidekiq -c 2 -q low
de repente…
1. monitore o uso do sidekiq
2. isole processos críticos
3. identifique timeframes das
queues
4. reduza o número de filas
Dica #11:
monitore o uso do sidekiq
monitorando as filas
monitorando o tamanho das filas
Sidekiq::Queue.all.each do |queue|
Enjoei::Metrics.event(
'SidekiqQueueReport', name: queue.name, size: queue.size
)
end
monitorando processos online
queues_processing = Sidekiq::ProcessSet.new.map do |p|
p['queues'].flatten
end.uniq
queues_processing.each do |queue|
Enjoei::Metrics.event(
'SidekiqOnlineQueueReport', name: queue
)
end
Dica #12:
isole processos críticos
PaymentProcessorWorker

queue: critical
ImageProcessorWorker

queue: default
SalesReportWorker

queue: low
Rápido e crítico Lento e não crítico Lento, pesado e não crítico
sidekiq -c 10 -q critical
10 50 1
processos separados por criticidade
Pros Contras
Isolamento completo de filas
mais críticas
Permite escalar filas de forma
diferente
Maior consumo de memória/
máquina
sidekiq -c 10 -q default,2 -q low,1
Dica #13:
identifique timeframes
processos rodando em timeframes idênticos
processos rodando em timeframes diferentes
Dica #14:
reduza o número de filas e
processos
unifique filas que rodam em
timeframes diferentes
processos rodando em timeframes diferentes
unifique todos os processos em uma só fila
# Antes:
sidekiq -q invoice -c 3
sidekiq -q coupon_reminder_emails -c 10
sidekiq -q counter_cache_update -c 10
# Depois:
sidekiq -q low -c 10
substitua concorrência por
limiters em caso de rate limit
processo com concorrência por causa

de rate limit da API de terceiro
# Antes:
sidekiq -q invoice -c 3
sidekiq -q coupon_reminder_emails -c 10
sidekiq -q counter_cache_update -c 10
# Depois:
sidekiq -q low -c 10
utilize limiters
class InvoiceWorker
include Sidekiq::Worker
ERP_THROTTLE = Sidekiq::Limiter.concurrent('erp', 3)
def perform
ERP_THROTTLE.within_limit do
end
end
end
lidando com ociosidade e
concorrência em processos
com características comuns
período de ociosidade vs concorrência
ociosidade concorrência leve concorrência pesada
proposta 1:

unificar processos em fila única
# Antes:
sidekiq -q read_only_default -c 10
sidekiq -q read_only_low -c 10
sidekiq -q read_only_high -c 10
# Depois:
sidekiq -q read_only -c 10
Pros Contras
Única fila para gerenciar
Para escalar basta subir um
novo processo
Não existe prioridade de
execução
Em momento de concorrência
irá somar o tempo de execução
proposta 2:

unificar filas por prioridade
# Antes:
sidekiq -q read_only_default -c 10
sidekiq -q read_only_low -c 10
sidekiq -q read_only_high -c 10
# Depois:
sidekiq -q read_only_high 

-q read_only_default 
-q read_only_low -c 10
Pros Contras
Prioridade na execução
Só executará processos com menos
prioridade quando acabarem os
prioritários
Em momento de concorrência irá somar
o tempo de execução
proposta 3:

unificar filas por peso
# Antes:
sidekiq -q read_only_default -c 10
sidekiq -q read_only_low -c 10
sidekiq -q read_only_high -c 10
# Depois:
sidekiq -q read_only_high,4 

-q read_only_default,2 
-q read_only_low,1 -c 10
Pros Contras
Para escalar basta subir um novo
processo
Irá processar simultaneamente todas
as filas com prioridades diferentes
Em momento de concorrência
irá somar o tempo de execução
proposta 4:

fila única e utilizar autoscale
# Antes:
sidekiq -q read_only_default -c 10
sidekiq -q read_only_low -c 10
sidekiq -q read_only_high -c 10
# Depois:
sidekiq -q read_only -c 10
Pros Contras
Única fila para gerenciar
Auto scaling vai aumentar número
de processos para dar vazão a
todas as filas quando houver picos
Sem um limite para auto scaling você
pode acabar consumindo muitos
recursos e derrubar sua base de dados
Pode demorar mais para processar os
jobs em momentos de picos
recursos sobre auto scaling
https://engenharia.elo7.com.br/sidekiq-workers/

http://www.pablocantero.com/blog/2013/05/04/auto-scale-sidekiq-workers-on-amazon-ec2/
http://manuelvanrijn.nl/blog/2012/11/13/scalable-heroku-worker-for-sidekiq/



http://blog.honeybadger.io/cleanly-scaling-sidekiq/
o pior pesadelo
informação do job é totalmente perdida
antes
depois
Dica #15:
cuidado ao iterar sobre

longos arrays
https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting
https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting
“Unfortunately it's up to you to
determine which worker and query
is causing the [memory] bloat.”
Mike Perham
Sidekiq creator
“Unfortunately it's up to you to
determine which worker and query
is causing the [memory] bloat.”
Mike Perham
Sidekiq creator
👍
pensando fora da caixa
Dica #16:
utilize processos separados para
ler de bases readonly
sidekiq -q default
workers por tipo de acesso aos dados
PaymentProcessorWorker

queue: default
ImageProcessorWorker

queue: default
SalesReportWorker

queue: readonly
SalesMailer.completed

queue: readonly
master
DATABASE_URL=$FOLLOWER_DATABASE_URL

sidekiq -q readonly
follower
replicação de dados
envie emails em filas readonly
config/initializers/sidekiq.rb
Sidekiq::Extensions.enable_delay!
# require DelayedMailer class in order to bypass lazy load
require 'sidekiq/extensions/action_mailer'
Sidekiq::Extensions::DelayedMailer.sidekiq_options queue: :readonly
em bases readonly sempre conte
com o delay de sincronização
replicação de base pode ter delay
master follower
replicação de dados
o que ocorre quando buscamos o produto?
class ProductMailer < ApplicationMailer
def published(product_id)
@product = Product.find(product_id)
...
end
end
class Product < ActiveRecord::Base
after_create do |product|
ProductMailer.delay.published(product.id)
end
end
cuidado com os callbacks do
ActiveRecord::Base
class ProductMailer < ApplicationMailer
def published(product_id)
@product = Product.find(product_id)
...
end
end
class Product < ActiveRecord::Base
after_create do |product|
ProductMailer.delay.published(product.id)
end
end
adicione um pequeno delay em

jobs que usam base follower
class ProductMailer < ApplicationMailer
def published(product_id)
@product = Product.find(product_id)
...
end
end
class Product < ActiveRecord::Base
after_create_commit do |product|
ProductMailer.delay_for(10.seconds).published(product.id)
end
end
sempre utilize callbacks de commit
class ProductMailer < ApplicationMailer
def published(product_id)
@product = Product.find(product_id)
...
end
end
class Product < ActiveRecord::Base
after_create_commit do |product|
ProductMailer.delay_for(10.seconds).published(product.id)
end
end
Dica #17:
utilize sidekiq para comunicar entre
diferentes sistemas/tecnologias
https://github.com/andersondias/multiplatform-sidekiq
RubyApp::Workers::ProducerWorker

queue: ruby
ruby_app: sidekiq -q ruby
CrystalApp::Workers::ReceiverWorker

queue: crystal
crystal_app: sidekiq -q crystal
Toda a comunicação entre as
aplicações é feita através de
escritas em filas.
comunicando através de filas
RubyApp::Workers::ProducerWorker

queue: ruby
ruby_app: sidekiq -q ruby
CrystalApp::Workers::ReceiverWorker

queue: crystal
crystal_app: sidekiq -q crystal
escrevendo jobs em outra aplicação
job = Sidekiq::Job.new
job.klass =
"RubyApp::Workers::ProducerWorker"
job.queue = "ruby"
Sidekiq::Client.new.push(job)
Sidekiq::Client.push(
'class' =>
'CrystalApp::Workers::ReceiverWorker',
'args' => [rand(10)],
'queue' => 'crystal'
)
Dica #18:
utilize outras tecnologias
métricas do enjuads
numa stack padrão
problema #1:

muitos dados passando pelo sidekiq
problema #2:

alto índice de insert/update no postgres
nossa solução usando stack da AWS
Kinesis Lambda DynamoDB
nossa solução usando stack da AWS
Substitui a queue

do Sidekiq com
baixa latência.
Substitui os workers e
agrupa “jobs”
automaticamente.
Substitui a base.
Faktory
https://github.com/contribsys/faktory
servidor faktory
conclusão

Mais conteúdo relacionado

Mais procurados

Mongo DB 완벽가이드 - 4장 쿼리하기
Mongo DB 완벽가이드 - 4장 쿼리하기Mongo DB 완벽가이드 - 4장 쿼리하기
Mongo DB 완벽가이드 - 4장 쿼리하기JangHyuk You
 
Ruby Microservices with RabbitMQ
Ruby Microservices with RabbitMQRuby Microservices with RabbitMQ
Ruby Microservices with RabbitMQZoran Majstorovic
 
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - Berlin
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - BerlinUsing MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - Berlin
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - BerlinSébastien Le Marchand
 
ModSecurity 3.0 and NGINX: Getting Started
ModSecurity 3.0 and NGINX: Getting StartedModSecurity 3.0 and NGINX: Getting Started
ModSecurity 3.0 and NGINX: Getting StartedNGINX, Inc.
 
Web worker in your angular application
Web worker in your angular applicationWeb worker in your angular application
Web worker in your angular applicationSuresh Patidar
 
SAP hybris - User Account Management
SAP hybris - User Account ManagementSAP hybris - User Account Management
SAP hybris - User Account ManagementZhuo Huang
 
Chromium에 contribution하기
Chromium에 contribution하기Chromium에 contribution하기
Chromium에 contribution하기규영 허
 
Redis trouble shooting
Redis trouble shootingRedis trouble shooting
Redis trouble shootingDaeMyung Kang
 
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정Seongyun Byeon
 
Lessons learned from operating Data Platform on Kubernetes(EKS)
Lessons learned from operating Data Platform on Kubernetes(EKS)Lessons learned from operating Data Platform on Kubernetes(EKS)
Lessons learned from operating Data Platform on Kubernetes(EKS)창언 정
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to CeleryIdan Gazit
 
Celery - A Distributed Task Queue
Celery - A Distributed Task QueueCelery - A Distributed Task Queue
Celery - A Distributed Task QueueDuy Do
 
nGram full text search (by 이성욱)
nGram full text search (by 이성욱)nGram full text search (by 이성욱)
nGram full text search (by 이성욱)I Goo Lee.
 
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018Amazon Web Services Korea
 
Massive service basic
Massive service basicMassive service basic
Massive service basicDaeMyung Kang
 
ProxySQL & PXC(Query routing and Failover Test)
ProxySQL & PXC(Query routing and Failover Test)ProxySQL & PXC(Query routing and Failover Test)
ProxySQL & PXC(Query routing and Failover Test)YoungHeon (Roy) Kim
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁정민 안
 
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019devCAT Studio, NEXON
 

Mais procurados (20)

Mongo DB 완벽가이드 - 4장 쿼리하기
Mongo DB 완벽가이드 - 4장 쿼리하기Mongo DB 완벽가이드 - 4장 쿼리하기
Mongo DB 완벽가이드 - 4장 쿼리하기
 
Ruby Microservices with RabbitMQ
Ruby Microservices with RabbitMQRuby Microservices with RabbitMQ
Ruby Microservices with RabbitMQ
 
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - Berlin
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - BerlinUsing MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - Berlin
Using MyBatis in Alfresco custom extensions - Alfresco Devcon 2012 - Berlin
 
ModSecurity 3.0 and NGINX: Getting Started
ModSecurity 3.0 and NGINX: Getting StartedModSecurity 3.0 and NGINX: Getting Started
ModSecurity 3.0 and NGINX: Getting Started
 
Web worker in your angular application
Web worker in your angular applicationWeb worker in your angular application
Web worker in your angular application
 
SAP hybris - User Account Management
SAP hybris - User Account ManagementSAP hybris - User Account Management
SAP hybris - User Account Management
 
Chromium에 contribution하기
Chromium에 contribution하기Chromium에 contribution하기
Chromium에 contribution하기
 
Redis trouble shooting
Redis trouble shootingRedis trouble shooting
Redis trouble shooting
 
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정
TF에서 팀 빌딩까지 9개월의 기록 : 성장하는 조직을 만드는 여정
 
Lessons learned from operating Data Platform on Kubernetes(EKS)
Lessons learned from operating Data Platform on Kubernetes(EKS)Lessons learned from operating Data Platform on Kubernetes(EKS)
Lessons learned from operating Data Platform on Kubernetes(EKS)
 
An Introduction to Celery
An Introduction to CeleryAn Introduction to Celery
An Introduction to Celery
 
Celery - A Distributed Task Queue
Celery - A Distributed Task QueueCelery - A Distributed Task Queue
Celery - A Distributed Task Queue
 
nGram full text search (by 이성욱)
nGram full text search (by 이성욱)nGram full text search (by 이성욱)
nGram full text search (by 이성욱)
 
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018
AWS Cloud9과 Workspace만으로 PC없는 개발환경 활용기 (박성용, 허밍랩) :: AWS DevDay 2018
 
Massive service basic
Massive service basicMassive service basic
Massive service basic
 
Celery
CeleryCelery
Celery
 
ProxySQL & PXC(Query routing and Failover Test)
ProxySQL & PXC(Query routing and Failover Test)ProxySQL & PXC(Query routing and Failover Test)
ProxySQL & PXC(Query routing and Failover Test)
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁
20240325 TuistNight 모듈로 나누면 알아두면 좋을 3가지 팁
 
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019
강성훈, 실버바인 대기열 서버 설계 리뷰, NDC2019
 

Semelhante a O que aprendi após 3 bilhões de jobs processados no Sidekiq

Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010lucashungaro
 
Design Patterns on Rails
Design Patterns on RailsDesign Patterns on Rails
Design Patterns on Railstchandy
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComunidade NetPonto
 
Testando Rails apps com RSpec
Testando Rails apps com RSpecTestando Rails apps com RSpec
Testando Rails apps com RSpecNando Vieira
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Androidtdc-globalcode
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Androidtdc-globalcode
 
iOS Delegates - Mobile Conf Rio 2014
iOS Delegates - Mobile Conf Rio 2014iOS Delegates - Mobile Conf Rio 2014
iOS Delegates - Mobile Conf Rio 2014osnipso
 
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividadeZabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividadeIgor Nicoli
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Rafael Ponte
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Carlos Duarte do Nascimento
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineCampus Party Brasil
 
Curso: Desenvolvimento de aplicativos híbridos (dia 2)
Curso: Desenvolvimento de aplicativos híbridos (dia 2)Curso: Desenvolvimento de aplicativos híbridos (dia 2)
Curso: Desenvolvimento de aplicativos híbridos (dia 2)Wennder Santos
 
Os 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFOs 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFtarsobessa
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidNelson Glauber Leal
 
Desenvolvendo com Angular CLI
Desenvolvendo com Angular CLIDesenvolvendo com Angular CLI
Desenvolvendo com Angular CLIVanessa Me Tonini
 

Semelhante a O que aprendi após 3 bilhões de jobs processados no Sidekiq (20)

Rails na prática
Rails na práticaRails na prática
Rails na prática
 
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
Coisas que aprendi e quero passar adiante - RubyConf Brasil 2010
 
Design Patterns on Rails
Design Patterns on RailsDesign Patterns on Rails
Design Patterns on Rails
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noite
 
Testando Rails apps com RSpec
Testando Rails apps com RSpecTestando Rails apps com RSpec
Testando Rails apps com RSpec
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Android
 
TDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no AndroidTDC2016POA | Trilha Android - Testes no Android
TDC2016POA | Trilha Android - Testes no Android
 
iOS Delegates - Mobile Conf Rio 2014
iOS Delegates - Mobile Conf Rio 2014iOS Delegates - Mobile Conf Rio 2014
iOS Delegates - Mobile Conf Rio 2014
 
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividadeZabbix Conference LatAm 2019 - Automação: Ganhando produtividade
Zabbix Conference LatAm 2019 - Automação: Ganhando produtividade
 
Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)Hibernate efetivo (IA-2014 / Disturbing the Mind)
Hibernate efetivo (IA-2014 / Disturbing the Mind)
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App Engine
 
Tornado
TornadoTornado
Tornado
 
Curso: Desenvolvimento de aplicativos híbridos (dia 2)
Curso: Desenvolvimento de aplicativos híbridos (dia 2)Curso: Desenvolvimento de aplicativos híbridos (dia 2)
Curso: Desenvolvimento de aplicativos híbridos (dia 2)
 
Os 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSFOs 10 Maus Hábitos dos Desenvolvedores JSF
Os 10 Maus Hábitos dos Desenvolvedores JSF
 
React js
React js React js
React js
 
Aplicacoes Rapidas Para Web Com Django
Aplicacoes Rapidas Para Web Com DjangoAplicacoes Rapidas Para Web Com Django
Aplicacoes Rapidas Para Web Com Django
 
Node.js: serious business
Node.js: serious businessNode.js: serious business
Node.js: serious business
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
 
Desenvolvendo com Angular CLI
Desenvolvendo com Angular CLIDesenvolvendo com Angular CLI
Desenvolvendo com Angular CLI
 

O que aprendi após 3 bilhões de jobs processados no Sidekiq