Router 서비스

Router 서비스 (Router service)

Router 서비스는 서로 다른 Broker 서비스 간에 쿼리를 분배해요. 기본적으로 Broker는 사전 구성된 데이터 보존 규칙에 따라 쿼리를 라우팅해요. 쿼리 라우팅 외에도 Router는 웹 콘솔도 실행해요.

출처: 문서

본문

Router 서비스는 서로 다른 Broker 서비스 간에 쿼리를 분배해요. 기본적으로 Broker는 사전 구성된 데이터 보존 규칙에 따라 쿼리를 라우팅해요. 예를 들어 최근 한 달의 데이터가 hot 클러스터에 로드되어 있다면, 최근 한 달에 해당하는 쿼리는 전용 Broker 집합으로 라우팅할 수 있어요. 이 범위 밖의 쿼리는 다른 Broker 집합으로 라우팅돼요. 이 구성은 더 중요한 데이터에 대한 쿼리가 덜 중요한 데이터에 대한 쿼리에 영향을 받지 않도록 쿼리 격리를 제공해요.

쿼리 라우팅 목적으로는 Druid 클러스터가 테라바이트 범위에 들어섰을 때만 Router 서비스가 필요해요.

쿼리 라우팅 외에도 Router는 데이터 로드, 데이터소스·task 관리, 서버 상태·segment 정보 확인을 위한 UI인 웹 콘솔도 실행해요.

설정 (Configuration)

Apache Druid Router 서비스 설정은 Router configuration을 참고하세요.

Router 서비스에 대한 기본 튜닝 지침은 Basic cluster tuning을 참고하세요.

HTTP 엔드포인트

Router가 지원하는 API 엔드포인트 목록은 Legacy metadata API reference를 참고하세요.

실행 (Running)

org.apache.druid.cli.Main server router

관리 프록시로서의 Router

Router를 구성해서 요청을 활성 Coordinator 또는 Overlord 서비스로 전달할 수 있어요. 이것은 비활성에서 활성 Coordinator 또는 Overlord 서비스로의 HTTP 리다이렉트 메커니즘이 제대로 동작하지 않는 상황 — 예를 들어 서버가 로드 밸런서 뒤에 있거나 리다이렉트에 사용되는 호스트명이 내부에서만 해석 가능할 때 — 에서 고가용성 클러스터를 설정하는 데 유용할 수 있어요.

관리 프록시 활성화

관리 프록시를 활성화하려면 Router의 runtime.properties에 다음을 설정하세요:

druid.router.managementProxy.enabled=true

관리 프록시 라우팅

관리 프록시는 암시적(implicit) 경로와 명시적(explicit) 경로를 지원해요. 암시적 경로는 Druid API 경로 관례에 따라 원래 요청 경로에서 목적지를 결정할 수 있는 경로예요. Coordinator의 관례는 /druid/coordinator/*, Overlord의 관례는 /druid/indexer/*예요. 이는 편리한데, 요청을 Coordinator나 Overlord 대신 Router에 보내는 것 외에 API 요청을 수정할 필요가 없기 때문이에요. 대부분의 Druid API 요청은 암시적으로 라우팅될 수 있어요.

명시적 경로는 Router에 대한 요청에 요청이 라우팅되어야 하는 서비스를 나타내는 경로 접두사가 포함된 경로예요. Coordinator의 접두사는 /proxy/coordinator, Overlord의 접두사는 /proxy/overlord예요. 이것은 목적지가 모호한 API 호출에 필요해요. 예를 들어 /status API는 모든 Druid 서비스에 존재하므로, 프록시 목적지를 나타내려면 명시적 라우팅을 사용해야 해요.

이를 표로 정리하면 다음과 같아요:

Request Route Destination Rewritten Route Example
/druid/coordinator/* Coordinator /druid/coordinator/* router:8888/druid/coordinator/v1/datasources -> coordinator:8081/druid/coordinator/v1/datasources
/druid/indexer/* Overlord /druid/indexer/* router:8888/druid/indexer/v1/task -> overlord:8090/druid/indexer/v1/task
/proxy/coordinator/* Coordinator /* router:8888/proxy/coordinator/status -> coordinator:8081/status
/proxy/overlord/* Overlord /* router:8888/proxy/overlord/druid/indexer/v1/isLeader -> overlord:8090/druid/indexer/v1/isLeader

Router 전략

Router에는 쿼리를 라우팅할 Broker를 결정하는 구성 가능한 전략 목록이 있어요. 전략 조건이 충족되는 즉시 Broker가 선택되므로 전략의 순서가 중요해요.

timeBoundary

{
	"type":"timeBoundary"
}

이 전략을 포함하면 모든 timeBoundary 쿼리가 항상 최고 우선순위 Broker로 라우팅돼요.

priority

{
	"type":"priority",
	"minPriority":0,
	"maxPriority":1
}

.minPriority보다 작게 설정된 우선순위를 가진 쿼리는 가장 낮은 우선순위 Broker로 라우팅돼요. maxPriority보다 크게 설정된 우선순위를 가진 쿼리는 가장 높은 우선순위 Broker로 라우팅돼요. 기본적으로 minPriority는 0, maxPriority는 1이에요. 이 기본값을 사용할 때 우선순위 0인 쿼리(기본 쿼리 우선순위는 0)를 보내면, 쿼리는 priority 선택 로직을 건너뛰어요.

manual

이 전략은 쿼리 컨텍스트에서 brokerService 파라미터를 읽고 그 broker 서비스로 쿼리를 라우팅해요. 쿼리 컨텍스트에 유효한 brokerService가 지정되지 않으면, 값이 유효하고 null이 아닐 때 defaultManualBrokerService 필드로 대상 broker 서비스를 결정해요. 값이 druid.router.tierToBrokerMap에 있으면 유효한 것으로 간주해요.

이 전략은 native 쿼리와 SQL 쿼리를 모두 라우팅할 수 있어요.

다음 예시 전략은 쿼리 컨텍스트에서 유효한 brokerService를 찾지 못하면 쿼리를 Broker druid:broker-hot으로 라우팅해요.

{
	"type": "manual",
	"defaultManualBrokerService": "druid:broker-hot"
}

JavaScript

JavaScript 함수로 임의의 라우팅 규칙을 정의할 수 있게 해줘요. 함수는 구성과 실행할 쿼리를 받아 라우팅해야 할 tier를 반환하거나, 기본 tier를 위해 null을 반환해요.

다음 예시 함수는 aggregator를 세 개 이상 포함한 쿼리를 가장 낮은 우선순위 Broker로 보내요.

{
	"type" : "javascript",
	"function" : "function (config, query) { if (query.getAggregatorSpecs && query.getAggregatorSpecs().size() >= 3) { var size = config.getTierToBrokerMap().values().size(); if (size > 0) { return config.getTierToBrokerMap().values().toArray()[size-1] } else { return config.getDefaultBrokerServiceName() } } else { return null } }"
}

info

JavaScript 기반 기능은 기본적으로 비활성화되어 있어요. Druid의 JavaScript 기능 사용에 대한 지침(활성화 방법 포함)은 Druid JavaScript 프로그래밍 가이드를 참고하세요.

전략을 사용한 SQL 쿼리 라우팅

전략을 사용한 SQL 쿼리 라우팅을 활성화하려면 druid.router.sql.enable을 true로 설정하세요. 주어진 SQL 쿼리의 Broker 서비스는 제공된 Router 전략만 사용해 결정돼요. 어떤 전략으로도 결정되지 않으면 Router는 defaultBrokerServiceName을 사용해요. 이 동작은 native 쿼리와 약간 달라요. native 쿼리에서는 Router가 먼저 전략으로 Broker 서비스를 결정하려 하고, 그다음 load rules, 마지막으로 여전히 결정되지 않으면 defaultBrokerServiceName을 사용해요. druid.router.sql.enable이 false(기본값)로 설정되면 Router는 defaultBrokerServiceName을 사용해요.

druid.router.sql.enable을 설정하는 것은 Avatica JDBC 요청이나 native 쿼리에는 영향을 주지 않아요.

Druid는 항상 문서화된 대로 전략과 load rules를 사용해 native 쿼리를 라우팅해요.

Druid는 항상 connection ID를 기반으로 Avatica JDBC 요청을 라우팅해요.

Avatica 쿼리 밸런싱

주어진 connection ID를 가진 모든 Avatica JDBC 요청은 같은 Broker로 라우팅되어야 해요. Druid Broker는 서로 연결 상태를 공유하지 않기 때문이에요.

이를 위해 Druid는 두 개의 내장 밸런서를 제공해요. 각각 요청의 connection ID에 rendezvous hashing과 consistent hashing을 사용해 요청을 Broker에 할당해요.

Router를 여러 개 사용할 때는 모든 Router가 동일한 밸런서 구성을 가져야 같은 라우팅 결정을 내린다는 점에 유의하세요.

Rendezvous hash 밸런서

이 밸런서는 Avatica 요청의 connection ID에 Rendezvous Hashing을 사용해 요청을 Broker에 할당해요.

이 밸런서를 사용하려면 다음 속성을 지정하세요:

druid.router.avatica.balancer.type=rendezvousHash

druid.router.avatica.balancer 속성이 설정되지 않으면 Router는 기본적으로 rendezvous hash 밸런서를 사용해요.

Consistent hash 밸런서

이 밸런서는 Avatica 요청의 connection ID에 Consistent Hashing을 사용해 요청을 Broker에 할당해요.

이 밸런서를 사용하려면 다음 속성을 지정하세요:

druid.router.avatica.balancer.type=consistentHash

이것은 실험 목적으로 제공되는 non-default 구현이에요. consistent hasher는 초기화 시와 Broker 집합이 변경될 때 설정 시간이 더 길지만, 5개 Broker로 테스트했을 때 rendezvous hasher보다 Broker 할당 시간이 더 빨라요. 두 구현의 벤치마크는 ConsistentHasherBenchmark와 RendezvousHasherBenchmark에 제공되어 있어요. consistent hasher는 locking도 필요하지만, rendezvous hasher는 그렇지 않아요.

프로덕션 구성 예시

이 예시에서 프로덕션 클러스터에는 hot과 _default_tier 두 개의 tier가 있어요. hot tier의 쿼리는 broker-hot Broker 집합으로, _default_tier의 쿼리는 broker-cold Broker 집합으로 라우팅돼요. 예외나 네트워크 문제가 발생하면 쿼리는 broker-cold Broker 집합으로 라우팅돼요. 이 예시에서는 c3.2xlarge EC2 인스턴스에서 실행하며, common.runtime.properties가 이미 존재한다고 가정해요.

JVM 설정:

-server
-Xmx13g
-Xms13g
-XX:NewSize=256m
-XX:MaxNewSize=256m
-XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+UseLargePages
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/mnt/galaxy/deploy/current/
-Duser.timezone=UTC
-Dfile.encoding=UTF-8
-Djava.io.tmpdir=/mnt/tmp
-Dcom.sun.management.jmxremote.port=17071
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Runtime.properties:

druid.host=#{IP_ADDR}:8080
druid.plaintextPort=8080
druid.service=druid/router
druid.router.defaultBrokerServiceName=druid:broker-cold
druid.router.coordinatorServiceName=druid:coordinator
druid.router.tierToBrokerMap={"hot":"druid:broker-hot","_default_tier":"druid:broker-cold"}
druid.router.http.numConnections=50
druid.router.http.readTimeout=PT5M
# Number of threads used by the Router proxy http client
druid.router.http.numMaxThreads=100
druid.server.http.numThreads=100

더 알아보기 (Learn more)

  • Rule configuration — 데이터 보존 규칙으로 쿼리를 라우팅하는 방법을 알아봐요.
  • 웹 콘솔 — Router가 실행하는 관리 UI를 살펴봐요.
  • Router configuration — Router 서비스 설정을 자세히 알아봐요.