LabHub
배우기 러닝패스 코스

Envoyの内部構造

同じアップストリームで方式だけ変えて数える

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

부하 분산 방식을 하나씩 바꿔 가며 실제 분배를 세고, 해시 기반 방식의 두 가지 성질(같은 열쇠는 같은 곳으로 · 한 대를 빼도 그 대의 몫만 옮김)을 직접 확인한다.

왜 중요한가

부하 분산은 설정 한 줄이지만 그 한 줄이 캐시 적중률과 세션 유지, 그리고 서버를 뺄 때의 충격 크기를 모두 정한다. 문서로 읽으면 다 그럴듯해 보이는데, 숫자를 직접 세어 보면 '무작위는 작은 표본에서 이만큼 치우치는구나' 와 '한 대를 빼도 이 정도만 옮기는구나' 가 몸에 남는다. 특히 열쇠를 뽑지 못한 요청이 무작위로 흘러간다는 사실은 세션 고정 장애의 단골 원인인데, 설정만 봐서는 보이지 않는다.

단계

  1. 업스트림 셋을 ok 로 띄우세요(8088·8089·8090). /root/envd-lb/lb-rr.yamllb_policy: ROUND_ROBINSTATIC 클러스터 pool/ 라우트를 두고 --concurrency 1 로 띄우세요(관리 9951, 리스너 127.0.0.1:10051). 9번 요청해 /root/envd-lb/01-rr.txtp8088=·p8089=·p8090=·total= 네 줄을 적으세요.
  2. /root/envd-lb/lb-rr.yaml/root/envd-lb/lb-weight.yaml 로 복사하고 엔드포인트마다 load_balancing_weight 를 주세요 — 8088 은 2, 나머지 둘은 1 입니다. 그 설정으로 다시 띄워 12번 요청하고 /root/envd-lb/02-weight.txtp8088=·p8089=·p8090=·total= 네 줄을 적으세요.
  3. /root/envd-lb/lb-random.yaml 을 만드세요 — 가중치는 두지 않고 lb_policyRANDOM 으로 바꾼 설정입니다. 그 설정으로 띄워 40번 요청해 /root/envd-lb/03-random.txtp8088=·p8089=·p8090=·total=·max_gap= 다섯 줄을 적으세요(max_gap 은 가장 많이 받은 수에서 가장 적게 받은 수를 뺀 값).
  4. /root/envd-lb/lb-ring.yaml 을 만드세요 — lb_policyRING_HASH, ring_hash_lb_config.minimum_ring_size 는 1024, 라우트의 hash_policy 는 헤더 x-user 입니다. 그 설정으로 띄운 뒤 u1 부터 u9 까지 아홉 사용자로 각각 한 번씩 요청해 /root/envd-lb/04-map.txt사용자 포트 아홉 줄을 적으세요.
  5. 사용자 u1 로 네 번, u2 로 네 번 요청해 /root/envd-lb/05-sticky.txtu1_ports=(받은 포트 네 개를 공백으로), u1_distinct=(서로 다른 포트 수), u2_distinct= 세 줄을 적으세요.
  6. /root/envd-lb/lb-ring2.yaml 을 만드세요 — 4단계 설정에서 엔드포인트 8090 만 뺀 것입니다. 그 설정으로 다시 띄운 뒤 같은 아홉 사용자로 다시 요청해 /root/envd-lb/06-remap.txt사용자 포트 아홉 줄을 적으세요. 그다음 4단계의 표와 견주어 /root/envd-lb/06-moved.txtmoved=(자리가 바뀐 사용자 수), stayed=, total=9 세 줄을 적으세요.
  7. /root/envd-lb/lb-query.yaml 을 만드세요 — 엔드포인트는 다시 셋이고, hash_policy 는 헤더 대신 질의 파라미터 uid 입니다. 그 설정으로 띄운 뒤 ?uid=u1 로 세 번, ?uid=u2 로 세 번 요청해 /root/envd-lb/07-key.txtu1_distinct=, u2_distinct=, header_ignored=(헤더 x-user: u1 만 붙이고 질의는 없이 세 번 요청했을 때 서로 다른 포트 수) 세 줄을 적으세요.
  8. /root/envd-lb/08-report.mdeven_spread=(1단계의 세 값을 쉼표로), heavy_share=(2단계에서 가중치 2 를 준 엔드포인트가 받은 비율, 백분율 정수), sticky=(5단계에서 같은 사용자가 한 곳에 붙었으면 yes), moved_users=(6단계 값) 네 줄을 적고, 그 아래 배운 것을 네 줄 이상 적으세요.

참고

고르게 나누는 것이 기본값이다

업스트림 셋을 ok 로 띄우세요(8088·8089·8090). /root/envd-lb/lb-rr.yamllb_policy: ROUND_ROBINSTATIC 클러스터 pool/ 라우트를 두고 --concurrency 1 로 띄우세요(관리 9951, 리스너 127.0.0.1:10051). 9번 요청해 /root/envd-lb/01-rr.txtp8088=·p8089=·p8090=·total= 네 줄을 적으세요.

라운드 로빈은 목록을 돌아가며 하나씩 고릅니다. 기본값이고, 서버 체급이 같고 요청 비용이 비슷할 때 가장 예측하기 쉽습니다. 워커 스레드마다 자기 차례를 따로 기억하므로 기본 concurrency(코어 수)로 세면 9번으로는 3 대 3 대 3 이 나오지 않습니다. 이 실습에서 워커를 하나로 묶는 이유가 그것입니다.

체급이 다른 서버를 한 묶음에 넣는다

/root/envd-lb/lb-rr.yaml/root/envd-lb/lb-weight.yaml 로 복사하고 엔드포인트마다 load_balancing_weight 를 주세요 — 8088 은 2, 나머지 둘은 1 입니다. 그 설정으로 다시 띄워 12번 요청하고 /root/envd-lb/02-weight.txtp8088=·p8089=·p8090=·total= 네 줄을 적으세요.

서버를 늘릴 때 늘 같은 체급으로만 늘어나지는 않습니다. 새로 산 장비가 두 배 빠르면 두 배를 받게 하는 편이 낫고, 그때 쓰는 것이 엔드포인트 가중치입니다. 라운드 로빈은 가중치를 반영해 도는데, 가중치 2 는 '두 번에 한 번씩 더' 가 아니라 '전체에서 차지하는 몫이 두 배' 라는 뜻입니다. 합이 4 이므로 12번이면 6 대 3 대 3 이 됩니다.

고르게 보이지만 고르지 않다

/root/envd-lb/lb-random.yaml 을 만드세요 — 가중치는 두지 않고 lb_policyRANDOM 으로 바꾼 설정입니다. 그 설정으로 띄워 40번 요청해 /root/envd-lb/03-random.txtp8088=·p8089=·p8090=·total=·max_gap= 다섯 줄을 적으세요(max_gap 은 가장 많이 받은 수에서 가장 적게 받은 수를 뺀 값).

무작위는 상태를 하나도 기억하지 않는 방식입니다. 그래서 워커가 몇 개든 결과가 같고, 엔드포인트가 들고 날 때 재계산할 것도 없습니다. 대신 표본이 작으면 눈에 띄게 치우칩니다 — 라운드 로빈이 9번에 정확히 3 대 3 대 3 이던 것과 비교해 보세요. 요청이 초당 수천 건인 곳에서는 이 차이가 사라지므로, 규모가 큰 곳에서 기본으로 쓰기도 합니다.

같은 사용자는 늘 같은 서버로

/root/envd-lb/lb-ring.yaml 을 만드세요 — lb_policyRING_HASH, ring_hash_lb_config.minimum_ring_size 는 1024, 라우트의 hash_policy 는 헤더 x-user 입니다. 그 설정으로 띄운 뒤 u1 부터 u9 까지 아홉 사용자로 각각 한 번씩 요청해 /root/envd-lb/04-map.txt사용자 포트 아홉 줄을 적으세요.

해시 기반 방식은 요청에서 뽑은 열쇠를 해시해 링 위의 자리를 찾고, 그 자리에서 시계 방향으로 가장 가까운 엔드포인트를 고릅니다. 같은 열쇠는 늘 같은 자리로 가므로 같은 사용자가 같은 서버에 붙습니다 — 로컬 캐시 적중률이 올라가고, 서버가 세션을 들고 있어도 됩니다. 열쇠는 hash_policy 가 고릅니다(헤더·쿠키·질의 파라미터·출발지 IP). minimum_ring_size 가 작으면 링이 성겨 분포가 치우칩니다.

같은 열쇠를 네 번 보내도 자리가 안 바뀐다

사용자 u1 로 네 번, u2 로 네 번 요청해 /root/envd-lb/05-sticky.txtu1_ports=(받은 포트 네 개를 공백으로), u1_distinct=(서로 다른 포트 수), u2_distinct= 세 줄을 적으세요.

이 성질이 없으면 로컬 캐시가 있는 서비스에서 같은 사용자의 요청이 매번 다른 서버로 가 캐시가 거의 맞지 않습니다. 반대로 이 성질에 기대면 특정 사용자 하나가 서버 한 대를 혼자 무겁게 만들 수 있다는 위험도 함께 생깁니다 — 열쇠를 무엇으로 고르느냐가 그래서 중요합니다. 서로 다른 값의 개수는 sort -u | wc -l 로 셉니다.

서버 한 대를 빼면 몇 명이 자리를 옮기나

/root/envd-lb/lb-ring2.yaml 을 만드세요 — 4단계 설정에서 엔드포인트 8090 만 뺀 것입니다. 그 설정으로 다시 띄운 뒤 같은 아홉 사용자로 다시 요청해 /root/envd-lb/06-remap.txt사용자 포트 아홉 줄을 적으세요. 그다음 4단계의 표와 견주어 /root/envd-lb/06-moved.txtmoved=(자리가 바뀐 사용자 수), stayed=, total=9 세 줄을 적으세요.

이것이 해시 링을 쓰는 진짜 이유입니다. 단순히 '해시 값을 서버 수로 나눈 나머지' 를 쓰면 서버 수가 바뀌는 순간 거의 모두가 자리를 옮깁니다. 링 방식은 사라진 서버에 걸려 있던 열쇠만 옮겨 가고 나머지는 그대로 있습니다. 옮긴 사람이 몇 명인지 직접 세어 보세요 — join 이나 paste 로 두 표를 나란히 놓고 비교하면 편합니다.

열쇠를 헤더에서 질의 문자열로 바꾼다

/root/envd-lb/lb-query.yaml 을 만드세요 — 엔드포인트는 다시 셋이고, hash_policy 는 헤더 대신 질의 파라미터 uid 입니다. 그 설정으로 띄운 뒤 ?uid=u1 로 세 번, ?uid=u2 로 세 번 요청해 /root/envd-lb/07-key.txtu1_distinct=, u2_distinct=, header_ignored=(헤더 x-user: u1 만 붙이고 질의는 없이 세 번 요청했을 때 서로 다른 포트 수) 세 줄을 적으세요.

열쇠를 무엇에서 뽑느냐가 곧 '무엇을 같은 것으로 볼 것인가' 입니다. 사용자 세션이면 쿠키, 테넌트면 헤더, 캐시 키면 질의 파라미터가 자연스럽습니다. 열쇠를 못 뽑으면 해시가 없으므로 Envoy 는 그 요청을 무작위로 보냅니다 — 그래서 열쇠가 빠진 요청은 고정되지 않습니다. 마지막 줄은 그것을 확인하는 것입니다.

방식별 성질 표로 정리한다

/root/envd-lb/08-report.mdeven_spread=(1단계의 세 값을 쉼표로), heavy_share=(2단계에서 가중치 2 를 준 엔드포인트가 받은 비율, 백분율 정수), sticky=(5단계에서 같은 사용자가 한 곳에 붙었으면 yes), moved_users=(6단계 값) 네 줄을 적고, 그 아래 배운 것을 네 줄 이상 적으세요.

표를 만드는 목적은 '어느 방식을 언제 쓰는가' 를 다음에 자기가 고를 수 있게 하는 것입니다. 값은 앞 단계 파일에서 가져오고, 설명 줄에는 각 방식이 무엇을 포기하고 무엇을 얻는지를 적으세요.