궁금해하시는 모든 분들을 위해 6.5.0 버전에서 FTS의 모든 성능 최적화의 숨겨진 비밀을 알려드리겠습니다,
" 더 적게 그리고 더 자주 ** "
더 아래로 스크롤하면 제 말에 동의하실 거라고 확신합니다.
(놓친 분들을 위해 1부)
gRPC를 통한 분산 수집
일반적으로 FTS 인덱스는 하위 인덱스로 분할되고 인덱스 분할은 다중 노드 클러스터의 노드에 걸쳐 배치됩니다. 그런 다음 들어오는 모든 일반적인 검색 쿼리는 이러한 모든 노드/원격 인덱스 파티션으로 분산되고 검색 결과는 여러 노드에서 수집되어 순위별로 병합된 후 조정 노드 또는 쿼리 처리 노드에서 사용자에게 다시 전송됩니다.
6.5.0 릴리스까지는 FTS의 모든 분산 수집이 http/http2를 통해 이루어집니다. 이 REST 기반 분산 수집에서 벗어나는 것은 팀의 백로그에서 오랫동안 보류 중이던 항목이었습니다. 미루는 것이 오히려 이득이 되었습니다.
N1QL-FTS 통합과 같은 6.5.0 기능이 시작되면서 내부 분산 수집을 위해 gRPC를 실험할 때가 무르익었다는 것을 깨달았습니다. 이미 웹의 모든 곳에서 gRPC의 장점에 대해 많이 언급되었으므로 여기서는 반복하지 않겠습니다.
FTS를 통해 저희는 주로 gRPC의 스트리밍 및 요청 다중화 기능을 탐색하는 데 관심이 있었습니다. 검색 결과를 클라이언트에 다시 스트리밍하면 수백만 개의 비순위(상수 순위) 히트가 있는 검색 결과를 메모리 친화적인 방식으로 제공하는 사용 사례를 해결하는 데 도움이 됩니다.
흥미로운 도전 과제들이 있었습니다,
- 인덱싱 라이브러리 반복기가 스토리지 엔진 내부의 어딘가에서 일치하는 문서를 탐색할 때 상위 수준의 cbft 패키지가 구성 가능한 방식(예: 히트 배치 또는 단일 히트)으로 검색 결과를 클라이언트 스트림에 쓸 수 있도록 하기 위한 올바른 인터페이스를 확보합니다.
- 기존 메시지 유형의 컨텍스트에서 올바른 프로토버프 메시지 유형을 정의합니다.
FTS에는 이미 내부 Golang 유형과 긴밀하게 연결된 기존의 json 메시지 유형이 있었고 모든 고객이 이를 사용하고 있었기 때문에 올바른 프로토부프 메시지를 얻는 것은 그리 간단하지 않았습니다. 따라서 새로운 메시지 형식은 레거시 메시지 형식을 고려해야 했습니다. 이로 인해 이러한 Go 유형과 새로운 프로토부프 유형 사이에 추가적인 수준의 마샬링/언마샬링 작업이 필요하게 되었습니다. 그리고 실제로 초기 테스트 중에 성능 그래프가 크게 찌그러져 패닉 버튼이 작동했습니다.
저희는 새로운 프로토타입 메시지 유형에서 레거시 검색 메시지의 구문 분석 오버헤드를 줄임으로써 이 문제를 즉시 해결했습니다. 레거시 검색 메시지 전체를 새로운 프로토 메시지 내에 바이트 슬라이스로 삽입하여 일부 우회로를 제거하고 가비지를 훨씬 적게 생성하는 아이디어였습니다.
결과
gRPC 기반 분산 수집은 다음을 보여주었습니다. 2X 3노드 클러스터를 사용한 내부 벤치마크에서 저빈도 용어 쿼리에 대한 처리량 개선이 있었습니다.
숫자 범위 쿼리
우리가 사용하는 텍스트 인덱싱 라이브러리(bleve)는 숫자 필드 값을 서로 다른 정밀도로 저장합니다. 즉, 하나의 숫자 필드 값이 여러 개의 시프트된 이진 인코딩 토큰으로 색인됩니다. 이 접근 방식은 인덱스 크기를 더 크게 만들지만 쿼리 시에는 주어진 숫자 범위에서 검색할 용어 수가 줄어들기 때문에 쿼리 속도가 훨씬 빨라집니다.
기회
에 언급된 지리적 쿼리의 작동 방식과 유사합니다. 1부 의 숫자 범위 쿼리 구현도 수학적으로 검색할 정확한 숫자 용어(후보 용어)를 도출합니다. 숫자 범위 쿼리에 사용되는 검색 후보 용어 필터링 로직은 퍼지/레그엑스 쿼리의 로직과 유사합니다. 두 DFA, 즉 용어 사전과 수학적으로 생성된 숫자 범위로 구축된 임시 DFA/FST를 교차시켜 후보 용어를 필터링하려고 시도합니다. 그러나 골랑 플레임 그래프 프로파일링 결과, 이 접근 방식은 메모리와 CPU에서 효율성이 떨어지는 것으로 나타났습니다.
이 필터링 로직을 더 깔끔하고 가벼운 용어 사전 조회 API로 개선하여 메모리와 CPU 사용량을 줄이는 데 도움을 주었습니다. 이를 통해 플레임 그래프에 나타나는 불필요한 스파이크가 제거되었습니다.
결과
이러한 변화는 다음과 같은 결과를 가져왔습니다. 77% 유입되는 돌연변이(10K 세트/초)가 꾸준히 발생하던 FTS 내부 성능 테스트에서 처리량이 개선되었습니다.
접두사/퍼지/와일드카드 쿼리
기회
이러한 모든 쿼리 유형은 FST 트래버스를 많이 사용합니다. 접두사 쿼리는 범위 기반 FST 반복기를 활용하는 반면 와일드카드/퍼지는 오토마톤 기반 반복기, 즉 와일드카드/레그젝트 쿼리는 정규식 오토마톤을, 퍼지 쿼리는 레벤슈타인 오토마톤을 활용합니다.
이러한 쿼리에서 동시에 공유할 수 있는 구조를 식별하고 이를 세그먼트 스냅샷 레벨을 사용하여 쿼리 전반의 재사용성을 개선했습니다. 이 방법은 생성되는 가비지 양을 많이 줄이고 GC 주기를 줄이는 데 도움이 되었습니다.
결과
캐싱 및 재사용 개선으로 다음과 같은 처리량 수치가 개선되었습니다.
와일드카드 기준 25%, 퍼지 작성자 12%, 접두사 by 9%.
{** 최적화는 단 세 가지입니다: "적게 하세요. 덜 자주 수행합니다. 더 빠르게."
1에서 가장 큰 이득을 얻지만, 저희는 3에 모든 시간을 할애합니다.- 마이클 프롬버거}