C
ClaudioGodoy
As configurações do ambiente execução do Go podem impactar o comportamento de um serviço em determinado ambiente.
Entender quais configurações são necessárias é imprescindível quando se trata de garantir o máximo de eficiência e desempenho de um serviço escrito em Go.
A configuração
Neste artigo, vou descrever minha experiência em busca da configuração ideal para um serviço hospedado no Kubernetes.
A documentação oficial do Go refere-se às goroutines como sendo um tipo de
Uma
De forma resumida, são eles:
A variável de ambiente
Em outras palavras, o
Definir um valor muito alto para o
O
Por exemplo, um
Para resolver esse problema, podemos configurar a variável nas especificações do contêiner da seguinte forma:
Imagine uma imagem
Podemos aplicar a configuração mencionada anteriormente na definição de um contêiner, como no exemplo abaixo:
O resultado que você terá, ao conferir os logs de execução deste
Entender a relação entre o número de núcleos da
Continue reading...
Entender quais configurações são necessárias é imprescindível quando se trata de garantir o máximo de eficiência e desempenho de um serviço escrito em Go.
A configuração
GOMAXPROCS
dita o comportamento do serviço em relação ao consumo de CPU
.GOMAXPROCS
: Número de "threads
" disponíveis para o processo. O valor padrão é o número de núcleos daCPU
.
Neste artigo, vou descrever minha experiência em busca da configuração ideal para um serviço hospedado no Kubernetes.
GOMAXPROCS e goroutines
A documentação oficial do Go refere-se às goroutines como sendo um tipo de
thread
mais leve. Embora correta, essa afirmação pode gerar confusões.Uma
goroutine
é uma estrutura usada pelo runtime da qual conterá uma pilha de execução, onde o próprio runtime
pode gerenciar sua execução. Para gerenciar a execução das rotinas, o Go implementa três componentes principais, introduzidos por Dmitry Vyukov
em seu trabalho Scalable Go Scheduler Design Doc.De forma resumida, são eles:
G (Goroutine)
: Contem a pilha de execução e todos artefatos necessários para execução, descrito na documentação como um tipo dethread
, porém muito mais leve.M (Thread)
: M é a forma mais comum de referenciar umathread
do sistema operacional.P (Processor)
: Processor é uma estrutura lógica introduzida porDmitry Vyukov
para minimizar o número degoroutines
que ficam em estado de espera quando umathread M
realiza uma operação bloqueante, conhecida comosys-call
. OProcessor
implementa uma série de algoritmos que controlam a distribuição das rotinas entre asthreads
disponíveis. Vale lembrar que existe uma relação íntima entre umProcessor P
e umaThread M
, porque oP
é uma estrutura lógica e, no fim do dia, vai rodar no contexto de umaThread M
.
A variável de ambiente
GOMAXPROCS
controla o número máximo de Processors
disponíveis para nossa aplicação. Para facilitar o entendimento deste ponto, o GOMAXPROCS
não controla o número máximo de Threads M
disponíveis para nossa aplicação. Em outras palavras, ela não inclui o número de threads bloqueadas, realizando uma chamada para o kernel do SO
.Em outras palavras, o
GOMAXPROCS
controla o número máximo de threads
que podem ser processadas de forma concorrente pelo processador do sistema operacional. O valor padrão é o número de núcleos do processador do host
da aplicação.Definir um valor muito alto para o
GOMAXPROCS
pode gerar um grande número de trocas de contexto da CPU
.GOMAXPROCS no Kubernetes
O
GOMAXPROCS
ainda não tem uma integração nativa com os limites definidos para um pod do Kubernetes.Por exemplo, um
pod
com limite de 1 núcleo de CPU
, rodando em um node com 64 núcleos de CPU
, vai acabar tendo o valor padrão GOMAXPROCS=64
.A empresa Uber realizou uma série de estudos em relação aos comportamentos desse desencontro de configurações no repositório do Github: uber-go/automaxprocs.
Configurar GOMAXPROCS na definição do contêiner
Para resolver esse problema, podemos configurar a variável nas especificações do contêiner da seguinte forma:
Code:
env:
- name: GOMAXPROCS
valueFrom:
resourceFieldRef:
resource: limits.cpu
Imagine uma imagem
docker
, contendo a seguinte aplicação:
Code:
package main
import (
"fmt"
"runtime"
"runtime/debug")
func main() {
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
}
Podemos aplicar a configuração mencionada anteriormente na definição de um contêiner, como no exemplo abaixo:
Code:
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: imagem-da-aplicação
resources:
limits:
cpu: 1500m
env:
- name: GOMAXPROCS
valueFrom:
resourceFieldRef:
resource: limits.cpu
O resultado que você terá, ao conferir os logs de execução deste
pod
é:
Code:
GOMAXPROCS: 2
Conclusão
Entender a relação entre o número de núcleos da
CPU
, threads
e goroutines
é essencial para elevar o nível de eficiência do seu serviço Go. Este artigo pode servir de base para que você realize e aprofunde seus estudos sobre o assunto proposto, para que possa ter uma grande consciência da estratégia que pretende utilizar, mudando ou não a configuração GOMAXPROCS
.Continue reading...