Otimização e Performance

truques (meio extremos) do Stack Overflow

/whois 

  • recifense
  • programadora há 15 anos
  • principal software developer na stack overflow
  • co-host do hipsters.tech
  • @rla4
  • desde 2008
    • 20 devs no core team
  • 50+ milhões de usuários únicos/mês
  • 20 milhões de perguntas
  • 30 milhões de respostas

números de julho

  • 7,766,285,553 HTTP requests
    • 4500/segundo
  • 2,261,504,325 page views
  • 108,822,522,849,648 bytes (108 TB) enviados
  • 20,451,152,295 SQL queries executadas
    • 11.000/segundo
  • 14ms de tempo de renderização da Question page
  • 123ms de tempo de renderização geral

9 WEB SERVERS

2 SQL SERVERS

LIVE

HOT STANDBY

Stack Overflow

528 M queries/dia

~5% CPU

🤷‍♀️

tech stack

  • c#
  • asp.net core
  • sql server
    • dapper, ef core
  • typescript
    • vanilla
  • redis
  • elasticsearch
  • ha proxy

qual arquitetura é mais performática?

The Free Lunch is Over, Herb Sutter. 2009

acabou a lei de Moore?

"The biggest sea change in software development since the OO revolution is knocking at the door, and its name is Concurrency"

latência

serialização

simplicidade

paralelização

independência

fast delegate

?

truques que independem da sua arquitetura

não chute: meça

truque #1: aprenda a usar uma ferramenta de benchmarking

 

  • suporte a benchmarks em múltiplas configurações de máquina/SO
  • tempo de processamento
  • alocação
  • métricas de GC

 

var siteIds = keys.Select(x =>
   int.Parse(x.Split(':')[0]));
var siteIds = keys.Select(x =>
   int.Parse(x.Substring(0, x.IndexOf(':'))));
| Method |     Mean |    Error |   StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|------- |---------:|---------:|---------:|-------:|------:|------:|----------:|
|  Split | 87.54 ns | 1.732 ns | 2.429 ns | 0.0153 |     - |     - |     128 B |
| Substr | 33.93 ns | 0.317 ns | 0.281 ns | 0.0057 |     - |     - |      48 B |
// keys: ["1:banana", "2:cuscuz", "3:coentro"]
var siteIds = keys.Select(x =>
   int.Parse(x.Split(':')[0]));
var siteIds = keys.Select(x =>
   int.Parse(x.Substring(0, x.IndexOf(':'))));
| Method |     Mean |    Error |   StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|------- |---------:|---------:|---------:|-------:|------:|------:|----------:|
|  Split | 87.54 ns | 1.732 ns | 2.429 ns | 0.0153 |     - |     - |     128 B |
| Substr | 33.93 ns | 0.317 ns | 0.281 ns | 0.0057 |     - |     - |      48 B |
|   Span | 23.46 ns | 0.491 ns | 0.734 ns |      - |     - |     - |         - |
var siteIds = keys.Select(x =>
   int.Parse(x.AsSpan().Slice(0, x.IndexOf(':'))));
// keys: ["1:banana", "2:cuscuz", "3:coentro"]

fique de olho no GC

truque #2: minimize suas alocações

fique de olho no GC

truque #2: minimize suas alocações

alocações são o principal gatilho do coletor de lixo (garbage collector - GC)

embora boa parte da coleção de lixo já aconteça em background, as pausas pra coleta ainda podem impactar duramente a performance de uma aplicação

https://github.com/Maoni0/mem-doc/blob/master/doc/.NETMemoryPerformanceAnalysis.md

var result = "";
foreach (var i in items) {
  result = result + "i: " + i + Environment.NewLine;
}
var result = new StringBuilder();
foreach (var i in items) {
  result.Append("i: ");
  result.AppendLine(i);
}
return result.ToString();

exemplo clássico: concatenação de strings

outros exemplos extremos pra minimizar alocações

// padrao do objeto vazio
private static MeuObjeto _empty = new MeuObjeto();
private static string[] _empty = Array.Empty<string>();
private static IList<int> _empty = ImmutableList<int>.Empty;
var sb = StringBuilderPool.Get();

truques de bancos de dados

mas sem contrariar seu DBA

truque #3: read uncommited (não somos um banco (ainda))

truque #4: denormalizar pode ser uma ótima opção

                     mas nunca denormalize dados que são custosos                               pra atualizar

truque #5: índices: use com cautela

 pergunta             (0.8ms)     

 top comments   (2.6ms)
 respostas            (2.8ms)

 dados user card (4.9ms)

truque #6: otimize o que você faz *mais*

escolher o momento certo pra converter de markdown => html é essencial

posts são editados em markdown

...mas renderizados em html

essa palestra é sobre o quê mesmo?

simplicidade

 

não alocar é melhor que alocar, mas cuidado com código esquisito

 

a linha de código mais rápida é aquela que você não escreveu :)

 

MEÇA!

obrigada :)

@rla4

rla4.com

Tweet do @Nick_Craver dizendo: "We've been playing with the GC knobs  @maoni0  added in .NET Core. By tweaking how much Gen 0 budget and heap count we want on 48 core machines for smaller apps, we have a lot better memory usage.  No more super lazy semi-unbounded gen 0 growth making things hard to get a read on" seguido de uma imagem mostrando alocações de memória saindo de 20Gb para 6Gb em media

nossos web servers têm 64Gb de memória apenas

 

coleta de lixo normalmente acontece quando se chega a ~85%-90% da memória disponível

<environmentVariable name="COMPLUS_GCHeapCount" value="0x14" /><!-- 20 heaps -->
<environmentVariable name="COMPLUS_GCGen0MaxBudget" value="0x3200000" /><!-- 50MB -->

truque #bonus: brinque com as configurações do GC

caching

cuidado com taxas de hit/miss

 

costumávamos cachear muita coisa, até medir e descobrir que o cache quase não era acessado :(

 

cachear complexifica o código: caching invalidation ainda é um dos maiores problemas da programação :)

por que performance importa?

  • $$$
  • Acessibilidade
    • 67% dos brasileiros não têm acesso a internet rápida
    • 4G e usuários móveis
  • Retenção de usuários
    • BBC: cada 1s a mais de load => -10% retenção de usuários
    • Mobify: cada 100ms a menos => 1.55% aumento na conversão de venda
  • UX

Otimização e Performance

By rla4

Otimização e Performance

  • 406