Recentemente, mudamos nosso ambiente de produção para o Kubernetes. Eu gostaria de impor limites de CPU nos contêineres. Estou recebendo métricas de CPU conflitantes que não se encaixam. Aqui está a minha configuração:
- Agentes do DataDog em execução como um
Daemonset
- Aplicativos existentes em execução sem limites de CPU
- Os contêineres em questão são aplicativos Ruby multithread
- Duas métricas:
kubernetes.cpu.usage.{avg,max}
edocker.cpu.usage
c4.xlarge
nós de cluster (4 vCPUs ou 4000m em termos do Kubernetes)
kubernetes.cpu.usage.max
relatórios ~ 600m para os contêineres em questão. docker.cpu.usage
relatórios ~ 60%. Daqui resulta que um limite de CPU de 1000m seria capacidade mais que suficiente em operação normal.
Defino o limite para 1000m. Em seguida, docker.container.throttles
sobe significativamente, enquanto kubernetes.cpu.usage.max
e docker.cpu.usage
ficar na mesma. O sistema cai de joelhos durante esse período. Isto não faz sentido para mim.
Eu pesquisei estatísticas do Docker. Parece que docker stats
(e a API subjacente) normalizam a carga de acordo com os núcleos da CPU. Então, no meu caso, docker.cpu.usage
de 60% chega (4000m * 0,60) a 2400m em termos do Kubernetes. No entanto, isso não se correlaciona com nenhum número do Kubernetes. Fiz outro experimento para testar minha hipótese de que os números de Kubernetes estão incorretos. Defino o limite para 2600m (para algum espaço extra). Isso não resultou em nenhum acelerador. No entanto, Kubernetes observou que o uso da CPU não mudou. Isso me deixa confuso.
Então, minhas perguntas são:
- Isso parece um bug no Kubernetes (ou algo na pilha?)
- Meu entendimento está correto?
Minha pergunta de acompanhamento está relacionada a como determinar corretamente a CPU para aplicativos Ruby. Um contêiner usa Puma. Este é um servidor da web com vários threads com uma quantidade configurável de threads. Solicitações HTTP são tratadas por um dos threads. O segundo aplicativo é um servidor econômico, usando o servidor encadeado. Cada conexão TCP de entrada é tratada por seu próprio encadeamento. O encadeamento sai quando a conexão é fechada. Ruby como GIL (Global Interpreter Lock), para que apenas um encadeamento possa executar o código Ruby por vez. Isso permite que vários threads executem E / S e coisas assim.
Eu acho que a melhor abordagem é limitar o número de threads em execução em cada aplicativo e aproximar os limites da CPU do Kubernetes com base no número de threads. Os processos não são bifurcados, portanto, o uso total da CPU é mais difícil de prever.
A questão aqui é: como prever adequadamente o uso e os limites da CPU para esses aplicativos?