Docker 환경undertow 스레드 부족 문제 탐구

7006 단어 Spring 관련J2EE
Docker 환경undertow 스레드 부족 문제 탐구
배경.
전편 Docker 환경 Spring Boot에서 대량의 http 요청 시간 초과를 적용했습니다. 우리는 대량의 http 요청 시간 초과 원인을 찾았습니다:undertow의 작업 라인이 부족합니다.몇 가지 의문을 남깁니다: undertow 기본 설정은 어떻게 됩니까?왜 다른 마이크로 서비스도 기본 파라미터를 사용하는데 256개의 작업 라인이 있습니까?
결론
k8s 스케줄링 시작 용기에 기본적으로 분배된 cpu 자원은 매우 작고 OpenJDK 1.8.0181은 용기 자원 제한을 감지한다. 두 가지 요소가 공통적으로 undertow가 사용할 수 있는 cpu를 적게 가져와서 undertow 작업 라인이 적다.
프로세스
undertow의 기본 루틴 설정은 무엇입니까
Google에서 찾을 수 없습니다.나는 시작 로그와 원본 코드 인터럽트를 보고 기본 설정이 io라는 것을 알았다.undertow.Undertow.Builder#Builder 클래스 정의:
ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2);
workerThreads = ioThreads * 8;

이 두 줄 코드를 보면 undertow 작업 라인 수량 계산 공식을 알 수 있다.'가용 cpu수'와 2를 큰 값으로 하고 8을 곱한다.
사용 가능한 cpu 수를 가져오는 것을 검증합니다
이상 마이크로 서비스는 16=2*8개 라인만 있고 런타임 때문일 수 있습니다.getRuntime().availableProcessors () 에서 가져온 '사용 가능한 cpu 수' 는 2보다 작거나 같습니다.
이거 아니야?출력에 사용할 수 있는 cpu 수를 출력하는 클래스를 만듭니다.
public class AvailCpu {
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

class로 컴파일하여 16개의 작업 라인만 있는 마이크로 서비스 용기와 256개의 작업 라인이 있는 마이크로 서비스 용기에 수동으로 코피를 하였는데, 실행 결과는 각각 1과 32였다.
이것은 왜 그 마이크로 서비스는 16개의 작업 라인만 있고 다른 마이크로 서비스는 256개의 작업 라인을 사용하는지 설명할 수 있다. 왜냐하면 undertow가 가져온 '사용 가능한 cpu 수'가 다르기 때문이다.
사용 가능한 cpu 수가 왜 다른지
다음에 나는 두 개의 마이크로 서비스 환경에 대해 어떤 차이가 있는지 비교한다.설명을 편리하게 하기 위해 후속으로 16개의 작업 라인이 있는 마이크로 서비스는 마이크로 서비스 16이라고 약칭하고 256개의 라인이 있는 마이크로 서비스는 마이크로 서비스 256이라고 약칭한다.
JDK 버전이 일치하지 않습니다.
마이크로서비스 16의 JDK 버전은 OpenJDK 1.8.0 입니다.181, 마이크로서비스 256은 OpenJDK 1.8.0111, JDK 버전 마이크로서비스 16 > 마이크로서비스 256.JDK 버전이 달라서 그런 거 아닐까요?(사실 이 원인이다. 구체적인 세부 사항은 뒤에 다시 묘사한다. 이어서 나는 많은 시행착오를 겪었다)
첫 번째 단계는 마이크로 서비스 16의 JDK 거울을 바탕으로 오픈 jdk:8-jdk-alpine, 그리고 Avail Cpu.class, 거울을 구성하여 테스트를 진행합니다.JDK 버전이 OpenJDK 1.8.0이 아니라는 걸 알게 됐어요.181, 오픈jdk:8-jdk-alpine 이 tag는 이미 최신 8-jdk-alpine 버전을 가리키고 있기 때문이다.OpenJDK 1.8.0_181에 대응하는 이미지 태그는 오픈 jdk:8u181-jdk-alpine입니다.
두 번째 단계는 Openjdk:8u181-jdk-alpine 렌즈를 사용하고 Avail Cpu를 추가합니다.class, 거울을 재구성하여 테스트를 진행합니다.용기를 수동으로 시작하면 출력할 수 있는 cpu 수가 정확합니다.JDK 버전 문제 아닌가요?
서버 커널 버전 불일치
테스트 과정에서 나는 테스트 서버의 핵 버전과 배치 마이크로서비스 16 서버의 핵 버전이 일치하지 않는 것을 발견했다.
내부 버전 문제 아니에요?다음은 검증 과정입니다.
  • 아리운 서버를 찾아 내부 버전과 생산 환경이 일치하는지 확인한다.
  • 테스트 이미지 구축을 괴롭히고 아리운 사복을 업로드하여 테스트하는 아리운 서버에 다운로드한다.
  • 수동으로 이미지를 시작하여 출력할 수 있는 cpu 수가 정확하다는 것을 발견했습니다.

  • 결론은 내부 버전과 상관없다는 것이다.
    그런 다음 JDK 버전 불일치로 돌아갑니다.
    OpenJDK 1.8.0을 온라인으로 다운로드해 보겠습니다.181의 원본 코드는 찾기 어려워서 많은 링크를 시도해 보았지만 다운로드하지 못해 포기했다.
    k8s 시동 용기와 수동 시동 용기는 차이가 있습니다
    마지막으로 내가 포기하려고 할 때 갑자기 영광이 나타나면 k8s 시동 용기와 수동 시동 용기가 차이가 있지 않을까요?다음은 검증 과정,
  • 테스트 이미지를 재구성하여 사복에 업로드한다.
  • k8s에서 이 테스트 렌즈를 기반으로 용기를 시작합니다. 출력은 cpu수로 1입니다.
  • 수동으로 이 테스트 렌즈를 기반으로 용기를 시작합니다. 출력할 수 있는 cpu 수는 4입니다.

  • 역시 K8s 시동 용기와 수동 시동 용기는 차이가 있다.
    내 마음은 기쁘다.
    이어서 나는 두 가지 방향을 따라 원인을 찾았다.
  • k8s 스케줄링 시작 용기 기본 매개 변수는 무엇입니까?
  • OpenJDK 1.8.0181 Docker 환경에서 사용할 수 있는 cpu 수는 1입니까?

  • 방향 1, 나는 k8s 시작 용기의 기본 파라미터를 찾지 못했지만, Docker 시작 용기에 cpu 자원을 설정하는 파라미터가 있는 것을 발견했다. - cpu-shares, - cpuset-cpus, - cpu-period, - cpu-quota.
    방향 2, 나는 자바세8u131+와 JDK9이 용기 자원 제한에 대한 자동 감지 능력을 지원한다는 것을 발견했다.마이크로 서비스 16 용기에서 실행
    java -XX:+PrintFlagsFinal 2>/dev/null|grep Container
    

    출력
     bool PreferContainerQuotaForCPUCount           = true                                {product}
     bool UseContainerSupport                       = true                                {product}
    

    설명 OpenJDK 1.8.0181은 용기 자원 제한을 감지한다.
    그렇다면 k8s 가동 용기와 수동 가동 용기 자원 제한은 도대체 무엇이 다릅니까?Docker가 이용하는 리눅스 베이스 기술 cgroup을 배워서 모든 용기에/sys/fs/cgroup 파일 설명 자원이 생성되고 cpu와 관련된 폴더는 cpu와 cpuacct라는 것을 알게 되었습니다.
  • cpu설명cpu자원
  • cpuacct는 cpu자원의 사용 통계 상황을 기술한다.

  • k8s 시작 용기와 수동 시작 용기/sys/fs/cgroup/cpu의 파일을 비교하여 cpu를 발견합니다.shares에 차이가 있음,
  • k8s 시동 용기, cpu.shares=2
  • 수동 부팅 용기, cpu.shares=1024

  • 수동으로 용기 docker run - cpu-shares=2... 을 시작합니다. 인증에서 사용할 수 있는 cpu수=1을 찾았습니다.
    이로써 undertow 작업 스레드 수가 부족한 실제 원인을 찾았습니다: k8s 스케줄링 시작 용기에 기본적으로 분배된 cpu 자원이 매우 작고 OpenJDK 1.8.0181은 용기 자원 제한을 감지한다. 두 가지 요소가 공통적으로 undertow를 가져오는 데 사용할 수 있는 cpu 수가 적고 undertow 작업 라인 수가 적다.
    넓히다
  • K8S 부팅 컨테이너의 기본 매개 변수를 검토합니다.
  • Docker의 핵심 기초 지식을 배운다.
  • K8S와 JVM이 어떻게 자원 제한을 함께 하는지 연구한다.

  • 참고 자료
  • https://yq.aliyun.com/articles/562440
  • Docker run 매개변수 참조https://docs.docker.com/engine/reference/run/?spm=a2c4e.11153940.blogcont562440.8.35c7627aBRGAn3#cpu-period-constraint
  • 용기(docker)에서 자바를 실행할 때 주목해야 할 몇 가지 작은 문제http://www.concurrent.work/docker/java/jvm/gc/pitfalls-about-running-java-inside-container/
  • https://www.infoq.cn/article/docker-kernel-knowledge-cgroups-resource-isolation
  • '새 JDK의 도커 용기에 대한 지원 이야기'https://segmentfault.com/a/1190000014142950
  • DOCKER 베이스 기술: LINUX CGROUPhttps://coolshell.cn/articles/17049.html
  • 좋은 웹페이지 즐겨찾기