과부하 상태에서 스레드 풀 부족 문제 해결
Dotnet-core(3.1) 응용 프로그램에서 높은 로드 문제가 발생했습니다.
일정 수준 이상의 연결(가상 사용자)이 발생하면 병목 현상이 발생하고 서버가 부족하며 요청 시간이 초과되지만 프로세스가 중단되지 않습니다(nokestrel 로그 없음).우리는 우리의 앱을 벤치마킹하기 위해 K6를 사용하고 있습니다.현재 로드 테스트는 로그인 페이지에서만 GET 요청을 수행하여 작은 데이터 세트(가입 없음 등)에서 기본 SQL 요청 하나를 트리거합니다.
Visual Studio 2019 Performance Profiler 툴과 perfview를 사용하여 문제를 조사했지만, 이러한 툴 중 어떤 것도 이러한 병목 현상을 일으키는 코드 부분을 식별하는 데 도움이 되지 않았습니다.
ThreadPool 기아에 대한 이 기사를 찾았습니다: https://learn.microsoft.com/fr-fr/archive/blogs/vancem/diagnosing-net-core-threadpool-starvation-with-perfview-why-my-service-is-not-saturating-all-cores-or-seems-to-stall 다음 예제와 같이 임의의 값으로 최소 ThreadPool을 조정하면,(그래프가 아닌) 성능이 크게 향상되었습니다.이건 스톱 갭 같은데, 사용하는 게 얼마나 나쁜가요?
System.Threading.ThreadPool.SetMinThreads(200, 200);
설명 : 2C_2G/100.csv => 코어 2개, 2Go RAM, 가상 사용자 100명
환경:
- 역방향 프록시로 nginx
- K6을 벤치마크 툴
- 닷넷 코어 3.1(엔티티 프레임워크 포함)
- 운영 체제 : Ubuntu 20.04
- mariadbas 데이터베이스
스레드 풀에 있는 동안 장기 실행 코드를 실행하고 있습니다.
이를 위한 방법은 다음과 같습니다.Task.Run
:
public async Task<byte> CalculateChecksumAsync(Stream stream) => await Task.Run(() =>
{
int i;
byte checksum = 0;
while ((i = stream.ReadByte()) >= 0)
{
checksum += (byte)i;
}
return checksum;
});
비동기/대기가 있기 때문에 완전히 비동기 코드처럼 보이는 일상적인 관찰자에게.Task
온통.
그러나 실제로는 스트림을 읽는 데 걸리는 시간 동안 스레드 풀 스레드를 묶게 됩니다(데이터의 양뿐만 아니라 스트림의 대역폭에도 따라 다름).
스레드 풀이 부족하면 스레드 풀이 새 스레드를 생성할 때까지 1초의 지연이 발생합니다.그 말은 다음에 전화가 올 때까지Task.Run
CPU가 유휴 상태인 경우에도 작업이 그만큼 지연됩니다.
대안:
- 가능한 경우 동기식 방법 대신 비동기식 방법을 사용합니다(예:
Stream.ReadAsync
), 특히 스레드 풀에 있을 때 - 코드에 대한 생성: 장기실코대장한기실작행생업성:
public async Task<byte> CalculateChecksumAsync(Stream stream) => await Task.Factory.StartNew(() => { int i; byte checksum = 0; while ((i = stream.ReadByte()) >= 0) { checksum += (byte)i; } return checksum; }, TaskCreationOptions.LongRunning);
그TaskCreationOptions.LongRunning
플래그는 C#에게 작업을 위해 즉시 새 스레드가 생성되기를 원한다고 알려줍니다.
네, 최소 작업자 스레드 수를 늘리는 것이 해결책이 아니라 갭 스토퍼입니다.
당신은 그 문제를 재현할 수 있는 것 같습니다.그런 경우에는 다음을 사용할 것을 제안합니다.dotnet-dump
차단 코드가 어디에 있는지 확인할 수 있습니다.이 YouTube 비디오의 스레드 풀 기아 진단 단계를 따르십시오. 꽤 효과적입니다.
BTW, 갭 스토퍼 코드의 경우, 문제를 일으키지 않는 비동기 IO 풀 카운트에 대한 두 번째 인수를 읽고 유지하며 호출의 설정 결과를 확인합니다.
int minWorker, minIOC;
// Get the current settings.
ThreadPool.GetMinThreads(out minWorker, out minIOC);
// Change the minimum number of worker threads to four, but
// keep the old setting for minimum asynchronous I/O
// completion threads.
if (ThreadPool.SetMinThreads(200, minIOC))
{
// The minimum number of threads was set successfully.
}
else
{
// The minimum number of threads was not changed.
}
언급URL : https://stackoverflow.com/questions/73637676/troubleshoot-threadpool-starvation-under-heavy-load
'programing' 카테고리의 다른 글
리액트 네이티브 iOS 시뮬레이터에서 경고를 숨기는 방법은 무엇입니까? (0) | 2023.06.09 |
---|---|
데카르트 제품을 할 수 있는 좋은 LINQ 방법이 있습니까? (0) | 2023.06.09 |
[ : 셸 프로그래밍에서 예기치 않은 연산자 (0) | 2023.06.04 |
레일즈에서 플럭과 수집의 차이점은 무엇입니까? (0) | 2023.06.04 |
iOS: UTC NSDate를 로컬 표준시로 변환 (0) | 2023.06.04 |