반응형

사내 서비스 중 Redis 에서 Lua 를 많이 사용하여 이번 기회에 Lua 메모리 관련하여 정리해 보았습니다.

 

Lua 스크립트란 ?

  • 스크립트 언어로써, 문자열 함수와 수학 함수를 제공
  • 그래픽 시뮬레이션을 위한 스크립트 언어로 개발된 언어로써 타 스크립트 언어보다 빠른 성능을 제공
  • 변수를 제거하거나 미리 선언을 위한 별도의 처리가 필요 없음

 

Redis 에서 Lua 스크립트

  • 프로그래밍 방식 제어구조를 사용하고 db에 access 하여 실행하는 대부분의 명령을 사용 가능
    • redis.call('set', key, value) 형태
  • 지역 변수를 사용해야 함
    • ex) 변수 선언 시 : local src = keys[1]
  • eval 명령어를 이용하여 수행하고자 하는 스크립트를 redis로 전송하여 사용 가능
  • script load 명령을 이용하여 redis server에 등록 시킨 후 사용 가능
    • 데이터가 존재하는 곳에서 실행되기 때문에 전체 대기 시간 뿐만 아니라 네트워크 리소스 절약 가능
    • Application 로직의 일부를 Redis 내에서 실행이 가능하며 여러키에 걸쳐 조건부 업데이트 수행 가능하며 다른 데이터 유형을 함께 처리도 가능
  • Script는 Lua 엔진(Lua5.1) 에 의해 실행
  • 기본적으로 Eval script는 클라이언트 일부로 간주하기 때문에 서버에 persistence 하게(영구) 저장이 되지 않기에(단순 Caching-휘발성), Redis server가 재시작 되거나 한다면 re-Load 해야 함
    • 7.0에서 부터는 redis function 추가 프로그래밍 로직으로 서버 자체를 확장할 수 있는 프로그래밍 가능성에 의해 persitence 하게 저장이 가능 (모든 client에서 사용이 가능)
    • 7.0 부터는 read-only script 가 가능 (read replica에서 지원)
    • https://redis.io/docs/manual/programmability/
  • 메모리 각 내용
    • used_memory_lua :   Lua 엔진에 의해 사용된 메모리 크기 (byte)
    • used_memory_scripts :  5.0 추가   (mh->lua_caches) 생성된 루아 스크립트가 사용하는 메모리 양
      • 모니터링 진행 할 때 used_memory_scripts  를 확인하면 되며, set 명령어만 이루어진 스크립트는 별도로 used_memory_scripts  영역이 변경되지 않음
    • redis server에서 실행되는 lua script는 원자성(Atomicity)하게 처리된다. (lua가 실행되는 동안 다른 레디스 명령어는 실행 안되는 것을 의미-다른 모든 명령어 차단)
      • 이 부분은 single thread 때문이 아닐까...
    • 스크립트 내용이 동일한 동작!!!을 하더라도, 조금이라도 다르다면 다른 스크립트로 인식 하기 때문에, 의미만 변경되는 스크립트 들에 대해서는 변수 처리로 하여 사용하면 캐싱 절약 효과를 얻을 수 있음
#아래는 동일한 동작을 하지만 내용이 다르기 때문에 서로 다른 내용으로 인식하여 used_memory_lua / used_memory_scripts 값 둘다 변경
eval "return 'hellow world?'" 0
eval "return 'hellow world????'" 0

#아래는 동일한 내용을 호출한 경우 캐싱되어 있기 때문에 memory 변화값이 없음을 확인
eval "return 'hellow world????'" 0
eval "return 'hellow world????'" 0

 

테스트 1.

 

이번에는 재밌는 테스트를 진행 하였다.
동일한 redis 구문이지만, return 을 하고 안하고의 차이 이다.
둘다 명령어는 get 명령어로 값을 리턴을 하지만, 이것을 결국 client까지 return을 하느냐 안 하느냐 차이일 것 같은데, 스크립트는 역시 이것을 다른 script로 인식을 하는 것을 확인

eval "redis.call('get', 'lua_test_2555')" 0
eval "return redis.call('get', 'lua_test_2555')" 0
  • 당연히 get 명령어이고 lua script를 호출이기 때문에 used_memory_scripts / used_memory_lua 모두 값이 변경 된 것을 확인할 수 있다.

  • 이번에는 명령어는 동일하지만 return 을 하는 명령어 실행
    • used_memory_scripts / used_memory_lua 모두 값이 변경 된 것을 확인할 수 있다.

  • 당연하겠지만, 기존에 캐싱되어 있는 영역을 다시 조회 시
    • used_memory_scripts / used_memory_lua 모두 값이 변경 되지 않은 것을 확인

  • 결국은 lua 는 내부 모두 동일해야 동일한 script로 인식하여 캐싱 여부를 사용할지 정하는 척도
    • 데이터 변경이 일어나는 곳이라면 당연히 파라메터로 작성하여 사용 하는 것을 의미하며 이렇게 사용할 것을 권고

테스트 2.

  • 추가로 set 명령어는 lua 엔진을 사용할 뿐, used_memory_scripts 의 값이 변경 되는 내역은 없음
    • 기존 get 명령어나 return 하는 명령어의 경우 used_memory_scripts  값이 변경 되는 것을 확인할 수 있으나, 오로지 set 명령어의 경우 lua engine 의 값만 변경(used_memory_lua ) 되는 것을 확인 할  수 있다.
local src = KEYS[1]  
for i=1, src, 2 do  
	local test_key = 'lua_test_' .. i  
	redis.call('set', test_key, i)  
end;  
-> 한마디로 set lua_test_홀수번호 홀수번호  
EVAL "local src = KEYS[1] for i=1, src, 2 do local test_key = 'lua_test_' .. i redis.call('set', test_key, i) end;"
  1. 초기 값 확인
    1. used_memory_lua : 32768 / used_memory_scripts : 0 / number_of_cached_scripts : 0  
  2. lua 스크립트로 캐싱 진행
    1. used_memory_lua : 33792 / used_memory_scripts : 216 / number_of_cached_scripts : 1
    2. lua 엔진 및 메모리에 적재 된 것을 확인 (스크립트 등록 시 기본 동작 하는 것으로 확인)
  3. lua 스크립트 실행
    1. used_memory_lua : 63488 / used_memory_scripts : 216 / number_of_cached_scripts : 1
    2. lua 엔진은 사용하였지만, get 명령어 같이 조회 하거나 하는 것이 아니기 때문에 lua 메모리 쪽에 적재 되는 것은 없는 것으로 확인
  4. 다시 한번 lua 스크립트 실행
    1. 동일하게 lua 엔진은 사용하였지만, memory 는 사용 하지 않은 것을 확인
    2. 바로 lua 로 실행 하여도 동일하게  engine 은 사용하지만, memory는 변경 되지 않는 것을 확인 완료

결론

  • 동일한 의미로 보이는 Lua 스크립트라고 하더라도, 내용이 조금이라도 다르면 서로 다른 스크립트로 인식
  • 동일한 명령어 이라고 하더라도, return  의 유무에 따라 위의 의미와 같이 서로 다른 스크립트로 인식
  • set 명령어로만 이루어진 lua  스크립트는, 별도의 메모리를 사용하지 않음 (lua 엔진만 메모리 사용)
  • 그 외 메모리 사용률을 확인 하기 위해서는 used_memory_scripts  를 모니터링 하며, used_memory_lua 는 평소와 비슷한지 체크하면 좋을 듯 합니다.
  • Elasticache 를 이용한다면, Lua script 내용이 get 형태의 읽기로만 이루어진 내용이라면, read를 이용하는 것을 추천합니다.(Lua의 수행속도가 오래 걸린다면 write 뿐만 아니라 redis 자체가 싱글 스레드로 동작하기 때문에 대기를 하게 되지만, 적어도 read를 이용한다면 write에 대해서만큼은 영향을 덜 미치기 때문 / 하지만 Lua 성능 최적화는 꼭 합시다.)

그외

AWS 의 경우 Cloudwatch 상에서 Elasticache 지표에서는 used_momory_scripts / lua 등을 제공을 하지 않기 때문에 BytesUsedForCache 와 FreeableMemory 의 변화로 모니터링 하는 것으로 우회 하거나, 해당 지표를 직접 조회하여 모니터링 하는 것을 추천 드립니다.

 

참고

다양한 샘플을 참고 할 수 있음 : https://bstar36.tistory.com/348
https://redis.io/docs/manual/programmability/eval-intro/
AWS  Support 최원 님 도움 주셔서 감사합니다.

반응형
반응형

MongoDB 여러 메모리 지표 중 cursor를 발생하는 과정에서 spinlock 이 발생 시키지만 lock 으로는 잡히지 않는 내용을 보고 검색 중 tcmalloc 전체를 정리하는 시간을 가지게 되었습니다.


tcmalloc 이란 ?

  • 구글에서 만든 메모리 할당하는 라이브러리(memory allocation (malloc))
    • 메모리 풀을 사용하면
      • 빠른 메모리 할당
      • 메모리 단편화 감소
  • Thread Caching malloc (TCmalloc)
  • 메모리를 Thread Local Cache와 Central Heap으로 나누어서 관리
    • tcmalloc은 성능상의 이유로, 각각 스레드는 자체 로컬(Thread Local Cache) 여유 페이지 캐시와 중앙 여유 페이지(Central Heap) 캐시를 보유
    • 메모리를 신청할 때 Thread Local 여유 페이지 캐시(32k 이하) 에서 사용 가능한 메모리를  찾고==> 사용 가능한 메모리가 없을 때만 Central Heap 페이지캐시(4k page)에서 추가 할당 적용 (Thread Local Cache는 32K이하의 작은 오브젝트 들을 담당하며 메모리가 부족할 시에는 Central Heap에서 메모리를 얻어와서 할당. 그리고 32K가 넘어가는 큰 오브젝트들은 Central Heap에다 4K의 페이지 단위로 나누어서 메모리 맵을 이용하여 할당)
    • 단순 Central Heap은 일반적으로 사용하는 메모리 풀과 다를바가 없지만, Thread Local Cache가 있음으로 불필요한 동기화가 줄어들어 lock cost 가 꽤 많이 감소하여 성능향상 효과
    • THread 의 수가 늘어날 수록 메모리 단위가 작을 수록 TCMalloc 이 효율이 더 뛰어남
    • 출처: https://gamedevforever.com/31
 

Google Performance Tools - TCmalloc (Thread-Caching memory allocation)

안녕하세요.  라오그람이란 필명을 사용하는 김효진 입니다. 저는 서버 쪽 개발을 하고있구요, 원래는 게임 서버 개발자이지만 현재는 게임쪽이 아닌 잠시 다른 쪽 서버 분야를 개발하고 있습

gamedevforever.com

 

MongoDB tcmalloc

  • https://medium.com/daangn/memory-allocator-for-mongodb-1953f9cee06c (Memory Allocator for MongoDB - 당근마켓 팀블로그 Sunguck Lee 님)
  • C++로 개발되어 메모리 할당과 해제를 직접 처리하는 C 언어와는 달리, C++에서는 (일반적으로) Heap Memory의 할당과 해제가 매우 많이 발생
    • 별도의 Memory Allocator를 사용하지 않으면 리눅스 운영 체제의 기본 Memory Allocator인 PTMalloc2를 사용
    • MongoDB에서도 PTMalloc2보다는 다른 더 나은 TCMalloc을 코드 수준에서 내장
    • https://jira.mongodb.org/browse/SERVER-24268 (Investigate jemalloc as alternative to tcmalloc)
  • mongos는 메모리 설정 파라메터가 없으며, 전통적으로 많은 사용자들이 mongos는 많은 메모리를 사용하지 않으며 일반적인 경우 100~200MB 정도로 할당해도 충분하다고 알고 있음
  • MongoDB의 관리형 서비스인 Atlas MongoDB에서도 mongod(MongoDB 서버)와 mongos를 동일 인스턴스에 배포해서 서비스를 제공
  • mongos를 통해서 아주 큰 데이터를 읽어오는 경우, mongos는 일시적으로 많은 데이터를 버퍼링해야 하며 순간적으로 메모리 사용량이 증가
  • mongos는 적절한 페이징 사이즈만큼의 도큐먼트를 가져와서 클라이언트가 가져갈 때까지 버퍼링을 하기 때문에 1~2개의 클라이언트가 대량의 데이터를 읽어 간다고 해서 심각한 메모리 사용을 유발하지는 않음
  • MongoDB에서는 메모리를 해제할 때 메모리도 캐시로 반환되고 tcmalloc Background에서 OS로 천천히 반환
  • 기본적으로 tcmalloc은 최대 메모리(1GB, 1/8 * system_memory)까지 캐시하며, 이 값은 setParameter.tcmallocMaxTotalThreadCacheBytesParameter매개변수가 있지만 일반적으로 수정하지 않는 것이 좋음
  • WiredTiger cacheSizeGB를 올바르게 구성(약 60%)
  • Sort 의 경우 메모리 정렬에는 일반적으로 더 많은 Tempory Memory 가 필요
    • 그렇기 때문에 index를 생성할 때 seak - sort - range 순서로 index 생성하는 이유
  • primary 와 secondary 간의 replication의 간격이 너무 크면 안됨
    • secondary 가 oplog를 저장하고 가져오기 위해(테일러커서) buffer (default maxsize 256mb) 유지해야하는데, 백그라운드는 buffer에서 oplog를 검색하고 계속 적용해야하기 때문에 secondary의 동기화가 느리면 버퍼가 최대 메모리로 계속 사용하게 됨
  • colleaction 및 index의 수를 제어하여 메타 데이터의 메모리 오버헤드를 줄여야 함.
replSet:PRIMARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("55188352944"),
                "heap_size" : NumberLong("102460903424")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : NumberLong("11626672128"),
                "pageheap_unmapped_bytes" : NumberLong("31339495424"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 207674832,
                "total_free_bytes" : NumberLong("4306382928"),
                "central_cache_free_bytes" : NumberLong("4098687488"),
                "transfer_cache_free_bytes" : 20608,
                "thread_cache_free_bytes" : 207674832,
                "aggressive_memory_decommit" : 0,
                "pageheap_committed_bytes" : NumberLong("71121408000"),
                "pageheap_scavenge_count" : 549140549,
                "pageheap_commit_count" : 614667087,
                "pageheap_total_commit_bytes" : NumberLong("119850820927488"),
                "pageheap_decommit_count" : 560377066,
                "pageheap_total_decommit_bytes" : NumberLong("119779699519488"),
                "pageheap_reserve_count" : 7546,
                "pageheap_total_reserve_bytes" : NumberLong("102460903424"),
                "spinlock_total_delay_ns" : NumberLong("1232934807643"),
                "release_rate" : 1,
                "formattedString" : "------------------------------------------------\nMALLOC:    55188353520 (52631.7 MiB) Bytes in use by application\nMALLOC: +  11626672128 (11088.1 MiB) Bytes in page heap freelist\nMALLOC: +  4098687488 ( 3908.8 MiB) Bytes in central cache freelist\nMALLOC: +        20608 (    0.0 MiB) Bytes in transfer cache freelist\nMALLOC: +    207674256 (  198.1 MiB) Bytes in thread cache freelists\nMALLOC: +    498335744 (  475.2 MiB) Bytes in malloc metadata\nMALLOC:  ------------\nMALLOC: =  71619743744 (68301.9 MiB) Actual memory used (physical + swap)\nMALLOC: +  31339495424 (29887.7 MiB) Bytes released to OS (aka unmapped)\nMALLOC:  ------------\nMALLOC: = 102959239168 (98189.6 MiB) Virtual address space used\nMALLOC:\nMALLOC:        5237759              Spans in use\nMALLOC:            182              Thread heaps in use\nMALLOC:          4096              Tcmalloc page size\n------------------------------------------------\nCall ReleaseFreeMemory() to release freelist memory to the OS (via madvise()).\nBytes released to the OS take up virtual address space but no physical memory.\n"
        }
}

replSet:SECONDARY> db.serverStatus().tcmalloc
{
        "generic" : {
                "current_allocated_bytes" : NumberLong("54850342264"),
                "heap_size" : NumberLong("95095918592")
        },
        "tcmalloc" : {
                "pageheap_free_bytes" : NumberLong("23660171264"),
                "pageheap_unmapped_bytes" : NumberLong("12539207680"),
                "max_total_thread_cache_bytes" : NumberLong(1073741824),
                "current_total_thread_cache_bytes" : 247460608,
                "total_free_bytes" : NumberLong("4046197384"),
                "central_cache_free_bytes" : NumberLong("3798717832"),
                "transfer_cache_free_bytes" : 18944,
                "thread_cache_free_bytes" : 247460608,
                "aggressive_memory_decommit" : 0,
                "pageheap_committed_bytes" : NumberLong("82556710912"),
                "pageheap_scavenge_count" : 20418440,
                "pageheap_commit_count" : 41285079,
                "pageheap_total_commit_bytes" : NumberLong("9607290798080"),
                "pageheap_decommit_count" : 27551593,
                "pageheap_total_decommit_bytes" : NumberLong("9524734087168"),
                "pageheap_reserve_count" : 27728,
                "pageheap_total_reserve_bytes" : NumberLong("95095918592"),
                "spinlock_total_delay_ns" : NumberLong("395391394174"),
                "release_rate" : 1,
                "formattedString" : "------------------------------------------------\nMALLOC:    54850342840 (52309.4 MiB) Bytes in use by application\nMALLOC: +  23660171264 (22564.1 MiB) Bytes in page heap freelist\nMALLOC: +  3798717832 ( 3622.7 MiB) Bytes in central cache freelist\nMALLOC: +        18944 (    0.0 MiB) Bytes in transfer cache freelist\nMALLOC: +    247460032 (  236.0 MiB) Bytes in thread cache freelists\nMALLOC: +    468451328 (  446.8 MiB) Bytes in malloc metadata\nMALLOC:  ------------\nMALLOC: =  83025162240 (79179.0 MiB) Actual memory used (physical + swap)\nMALLOC: +  12539207680 (11958.3 MiB) Bytes released to OS (aka unmapped)\nMALLOC:  ------------\nMALLOC: =  95564369920 (91137.3 MiB) Virtual address space used\nMALLOC:\nMALLOC:        5004341              Spans in use\nMALLOC:            181              Thread heaps in use\nMALLOC:          4096              Tcmalloc page size\n------------------------------------------------\nCall ReleaseFreeMemory() to release freelist memory to the OS (via madvise()).\nBytes released to the OS take up virtual address space but no physical memory.\n"
        }
}

지표들 내역

  • pageheap_free_bytes : 페이지 힙에 매핑된 사용 가능한 페이지 byte
    • 해당 영역은 요청 시 할당하여 사용 가능한 페이지
    • OS에 의해 swap이 발생하지 않는 상태라면, 항상 해당 가상 메모리 사용량으로 계산
  • total_free_bytes : central_cache_free_bytes + transfer_cache_free_bytes + thread_cache_free_bytes 로 구성
  • tcmalloc cache 사이즈를 확인하려면 pageheap_free_bytes 와 total_free_bytes 를 참조하면 가능
  • central_cache_free_bytes   : 클래스 size에 할당된 중앙 캐시 내의 free 바이트 수
    • 항상 가상 메모리 샤용량으로 계산되며, os에서 기본 메모리를 swap 하여 사용하지 않는 한 물리적 메모리 사용량으로도 계산
  • transfer_cache_free_bytes : 중앙 cache와 Thread Cache 간에 변환되기를 기다리는 free byte 수
    • 항상 가상 메모리 샤용량으로 계산되며, os에서 기본 메모리를 swap 하여 사용하지 않는 한 물리적 메모리 사용량으로도 계산
  • thread_cache_free_bytes : Thread Cache 내의 free byte 수
    • 항상 가상 메모리 샤용량으로 계산되며, os에서 기본 메모리를 swap 하여 사용하지 않는 한 물리적 메모리 사용량으로도 계산

 

MongoDB 에서 spinlock

  • collection 에 대한 작업을 하려고 할 때 해당 collection document에 lock 이 걸려 있으면, 지속적으로 앞에 있는 lock 이 만료되었는지 확인하는 작업(spin)
    • spinlock 값이 증가한다면, lock 이 길어지고 있다는 것을 의미하며, slow query 등을 확인하여 오랫동안 동작하는 쿼리 등을 확인
  • getmore 쿼리는 mongodb의 cursor 발생 하므로, spinlock 발생 시키지만, 이거는 DB log에서는 lock 으로 안 잡힘

 

spin lock 개념

  • Thread가 단순히 loop(spin) 돌면서 Lock을 소유하고 있는 Thread가 lock 반환될 때까지 계속 확인하며 기다리는 상태
  • Context Switching 으로 부하를 주기 보다는 잠시 기다리자는 컨셉으로 스위칭을 하지 않고 잠시 루프를 돌면서 재시도를 진행

그외 tcmalloc 관련 이슈

상황

 

[SERVER-37541] MongoDB Not Returning Free Space to OS - MongoDB Jira

 

jira.mongodb.org

 

주로 primary 만 사용하는데, 메모리가 해제되지 않는 이슈

해결방안

  • tcmallocRelease:1 를 실행하여 (release free) pageheap을 재활용
    • db.adminCommand({tcmallocRelease: 1})
    • 이 때 pageheap 전체를 lock 하기 때문에 온라인에서 사용할때는 주의 (사용량이 적을 때 사용)
  • 하지만 해당 명령어는 가급적 사용하지 않는 것이 좋음(문제라고 판단되기 전까지..)
    • 실제로는 메모리를 낭비하지 않고 해당 메모리를 이용하여 다른 곳에서도 사용할 수 있기 때문

tcmallocRelease:1 처리 후 메모리 해제된 내역

 

 


https://developer.aliyun.com/article/685044
https://jira.mongodb.org/browse/SERVER-37541
https://jira.mongodb.org/browse/SERVER-33296

  • current_allocated_byutes 가 8gb
    • 하지만 heap_size는 현재 14gb 에 이르고 있음 (swap 사용한 내용 포함 / mem-resident와 비슷)
    • pageheap_free_bytes의 누적으로 인한 것으로 예상
    • TCMALLOC_AGGRESSIVE_DECOMMIT 를 이용하여 해결(설정하게 되면 tcmalloc이 여유 페이지를 os로 적극적으로 반환하도록 하는 역할)
      • 하지만 부정적인 성능 영향이 있을것 같아 원인 해결이 필요해 보임
      • mongodb에서는 tcmalloc 이 해당 부정적인 영향보다 더 큰 이점(성능)이 있다고 하여 우선순위에서 밀려 미해결중
      • Mongo 4.4.10 에서도 발생하고 있다 함.
  • https://jira.mongodb.org/browse/SERVER-31417
 

Analysis of MongoDB tcmalloc memory cache

Keywords: Database MongoDB background From the perspective of monitoring, Secondary uses about 11GB more physical memory than Primary, For basic memory analysis, you can read this written by another student of the team first Troubleshooting documents, Th

programmer.group

 

반응형
반응형

MongoDB 를 Sharded cluster 로 구축 후 운영하면서 수정했던 파라메터 중 하나를 공유합니다.

TaskExecutorPool은 mongos 에서 설정하는 파라메터 값 중 하나입니다.
(해당 문서는 4.4 위주로 작성 되었습니다.)

 

TaskExecutorPool?

  • Real MongoDB(235page)
  • MongoDB 라우터(mongos)는 MongoDB 클라이언트로부터 요청되는 쿼리들을 처리하기 위해서 내부적으로 서버의 CPU 코어 개수만큼 TaskExecutorPool 를 준비
  • Thread Pool 과 동일한 개념으로 생각하면 이해가 쉬움
  • MongoDB Shard 노드(Member)와의 연결 정보를 가지는 connection pool를 하나씩 가지며, Connection pool은 내부적으로 sub-connectionpool를 보유
  • 샤드 서버당 하나씩 생성
  • 만약 2개의 샤드(노드)가 존재한다면, 하나의 샤드당 connnection pool은 2개씩의 sub-connectionpool를 보유 (소스 상 specific-pool 이라고 명칭)
  • taskExecutorPoolSize 조정의 예시
    • app과 같은 서버에서 mongos가 실행된다면, app에서 많은 연결 및 작업을 한다면 TaskExecutorPool의 개수를 수동으로 증가 시키는 것도 가능
    • CPU 코어가 많은 서버라면, connection 이 너무 과도하게 생성되어 오히려 mongo shard(node)에 부하가 발생한다고 판단되면, TaskExecutorPool 개수를 제한도 가능
  • 모니터링 시 해당 수치가 높게 나오면 Sharded Clsuter 에 문제가 있기 때문에 반드시 체크가 필요 합니다.

 

taskExecutorPoolSize
  • 주어진 mongos에 사용할 Task Executor Connection Pool 의 수
  • 사용 가능한 코어 수로 default 설정 (최소 4, 최대 64)
    • 4.2 에서는 Default 가 1이며, cpu core 수에서 해당 값 만큼 설정
    • 0 으로 설정 시 자동으로 설정
    • 4.0 이전에는 core 수가 4 이하면 4, core 수가 64 이상일 경우 64로 설정
  • open connection 수를 줄이려면 낮은 값으로 설정
    • 부하 발생 시 적절하게 대처하기 힘들 수 있음.
  • default 값이 적절하며, 코어 수가 많은 서버에서는 해당 옵션을 16 이하로 설정하는 것이 좋음
  • mongos는 multiple thread pool을 유지 가능
  • 코어 수당 최대 connection 는 ShardingTaskExecutorPoolMaxSize 만큼 설정 가능
    • ex > ShardingTaskExecutorPoolMaxSize : 100 으로 설정 하고, taskExecutorPoolSize 를 4로 설정 시 최대 400개의 connection 을 생성 및 연결

Task Executor Pool

sub-ConnectionPool (SpecificPool)
  • connection pool의 connection을 얼마나 보유할지 결정
  • ShardingTaskExecutorPool로 시작
  • value 값들은 모두 3.2.11 이후부터 설정가능

 

ShardingTaskExecutorPoolHostTimeoutMS

  • mongos 가 host 와 통신하지 않아 끊는 시간(Timeout)
  • Default 300000 (5 분)
  • 시간이 길수록 피크 발생 시 유연하게 대처가 가능.
  • 일반적으로 피크 기간?의 3~4배 시간으로 설정하는 것이 tip (피크-spike 치는 시간이 가령 5분동안 지속된다면, 해당 ShardingTaskExecutorPoolHostTimeoutMS을 15~20분 으로 설정하는 것을 추천)
    • Real MongoDB에서는 30분에서 1시간 정도를 추천

 

ShardingTaskExecutorPoolMaxSize

  • taskExecutor connection pool 이 mongod(sharded) 에 대해 connection 할 수 있는 최대 개수 ( 하나의 coonection pool 이 접속할 수 있는 최대 connection 수)
  • default 값이 무제한
  • 최대 connection 수는 ShardingTaskExecutorPoolMaxSize * taskExecutorPoolSize 로 계산
  • connection floods 가 발생하면 해당 값을 제한하여 설정하는 것이 유용
    • connection floods : TCP connection floods라고 하며, 공격자가 서버에 사용 가능한 TCP connection slot 을 고갈시키는 행위 (여기서는 사용 가능한 connection 이 없을 경우를 의미)


ShardingTaskExecutorPoolMinSize

  • 각 TaskExecutor connection pool 이 sharded node에 connection 할 수 있는 최소 수
  • default 1
  • cold start 시 대기 시간 문제가 있는 경우 해당 값 증가가 도움
  • 해당 값을 증가시키면, mongos 프로세스가 ShardingTaskExecutorPoolHostTimeoutMS 가 만료될때까지 open 된 상태 유지 (TaskExecutorPoolSize * PoolMinSize * mongos 개수 per shard)
    • Real MongoDB에서는 10개 정도의 값도 충분

 

ShardingTaskExecutorPoolRefreshRequirementMS

  • connection pool 안에서 connection heartbeat로 시도할 때 wait 최대 시간
  • Default 60000 (1 분)
  • default 값을 추천
  • 해당 값을 높이면 heartbeat 트래픽이 증가하여 idle load 가 증가
  • 해당 값을 낮추면 일시적인 네트워크 오류 수를 줄일 수 있음(connection timeout 으로 인한 오류 내역을 줄일 수 있음)

 

ShardingTaskExecutorPoolRefreshTimeoutMS

  • mongos가 heartbeat timeout 을 기다리는 최대 시간
  • Default 20000 (20 초)
  • 해당 값이 낮으면 mongos가 pool 안의 connection을 유지할 수 없음
  • 네트워크 대기 시간이 긴 경우 해당 값을 늘려 네트워크 연결 유지를 향상 가능
# 설정 방법 1 (mongos config 로 등록)
sharding:
  #configDB: config_replSet/10.28.195.139:27017,10.28.195.140:27017,10.28.195.141:27017
  configDB: config_replSet/10.6.98.32:27017,10.6.102.126:27017,10.6.98.62:27017
net:
  bindIp: 0.0.0.0
  port: 27019
processManagement:
  fork: true
  pidFilePath: "/data/mongos/mongos.pid"
security:
#  authorization: enabled
  keyFile: /usr/local/mongodb/mongo_repl.key
systemLog:
  destination: file
  path: "/data/mongos/log/mongos.log"
# logAppend: true


setParameter:
  taskExecutorPoolSize: 0
# 설정 방법 2 (명령어로)
mongos> db.runCommand({setParameter:1,taskExecutorPoolSize:0})
{
    "was" : 1,
"ok" : 1,
  "$clusterTime" : {
        "clusterTime" : Timestamp(1631672362, 1),
          "signature" : {
                    "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                "keyId" : NumberLong(0)
            }
},
        "operationTime" : Timestamp(1631672362, 1)
}

#확인 방법
mongos> db.runCommand({getParameter:1,taskExecutorPoolSize:1})
{
    "taskExecutorPoolSize" : 0,
        "ok" : 1,
  "$clusterTime" : {
        "clusterTime" : Timestamp(1631672363, 1),
          "signature" : {
                    "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                "keyId" : NumberLong(0)
            }
},
        "operationTime" : Timestamp(1631672363, 1)
}

 

반응형

Connection pool 확인

  • TaskExecutorPool 개수를 확인 가능 (16개)
    • 내부에 각 Shard DB들로 추가 connection 확인 가능
mongos> db.runCommand({"connPoolStats":1})
{
        "numClientConnections" : 0,
        "numAScopedConnections" : 0,
        "totalInUse" : 1,
        "totalAvailable" : 180,
        "totalCreated" : 5871,
        "totalRefreshing" : 0,
        "replicaSetMatchingStrategy" : "matchPrimaryNode",
        "pools" : {
                "NetworkInterfaceTL-ShardRegistry" : {
                        "poolInUse" : 0,
                        "poolAvailable" : 3,
                        "poolCreated" : 41,
                        "poolRefreshing" : 0,
                        "192.168.0.126:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 4,
                                "refreshing" : 0
                        },
                        "192.168.1.32:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 35,
                                "refreshing" : 0
                        },
                        "192.168.1.62:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 2,
                                "refreshing" : 0
                        }
                },
                "NetworkInterfaceTL-TaskExecutorPool-0" : {
                        "poolInUse" : 0,
                        "poolAvailable" : 9,
                        "poolCreated" : 355,
                        "poolRefreshing" : 0,
                        "192.168.0.101:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 2,
                                "refreshing" : 0
                        },
                        "192.168.0.199:27017" : {
                        ...
                        
                   "NetworkInterfaceTL-TaskExecutorPool-1" : {
                        "poolInUse" : 1,
                        "poolAvailable" : 8,
                        "poolCreated" : 366,
                        "poolRefreshing" : 0,
                        "192.168.0.101:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 5,
                                "refreshing" : 0
                        },
                        "192.168.0.199:27017" : {
                        ...
                  "NetworkInterfaceTL-TaskExecutorPool-10" : {
                        "poolInUse" : 0,
                        "poolAvailable" : 12,
                        "poolCreated" : 342,
                        "poolRefreshing" : 0,
                        "192.168.0.101:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 2,
                                "refreshing" : 0
                        },
                        "192.168.0.199:27017" : {
                        ...
               "NetworkInterfaceTL-TaskExecutorPool-15" : {
                        "poolInUse" : 0,
                        "poolAvailable" : 10,
                        "poolCreated" : 349,
                        "poolRefreshing" : 0,
                        "192.168.0.101:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 2,
                                "refreshing" : 0
                        },
                        "192.168.0.199:27017" : {
                                "inUse" : 0,
                                "available" : 1,
                                "created" : 1,
                                "refreshing" : 0
                        },
                        "192.168.0.92:27017" : {
                        ...

 

[참고]

Real MongoDB

Line Games 성세일님

AWS 이덕현님

https://www.mongodb.com/docs/v4.4/reference/parameters/#mongodb-parameter-param.taskExecutorPoolSize

https://muralidba.blogspot.com/2018/03/what-are-tunable-options-for-mongos.html

이미지 : https://www.modb.pro/db/52603

반응형

+ Recent posts