์๋ ํ์ธ์ Habr. ์ ์ด๋ฆ์ Ilya์ ๋๋ค. ์ ๋ Exness์ ํ๋ซํผ ํ์์ ์ผํ๊ณ ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ ํ ๊ฐ๋ฐ ํ์ด ์ฌ์ฉํ๋ ํต์ฌ ์ธํ๋ผ ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ๋ฐํ๊ณ ๊ตฌํํฉ๋๋ค.
์ด ๊ธ์์๋ ๊ณต๊ฐ ์น์ฌ์ดํธ ์ธํ๋ผ์ ์ํธํ๋ SNI(ESNI) ๊ธฐ์ ์ ๊ตฌํํ ๊ฒฝํ์ ๊ณต์ ํ๊ณ ์ถ์ต๋๋ค.
์ด ๊ธฐ์ ์ ์ฌ์ฉํ๋ฉด ๊ณต๊ฐ ์น์ฌ์ดํธ ์์
์ ๋ณด์ ์์ค์ด ํฅ์๋๊ณ ํ์ฌ๊ฐ ์ฑํํ ๋ด๋ถ ๋ณด์ ํ์ค์ ์ค์ํ๊ฒ ๋ฉ๋๋ค.
์ฐ์ ํด๋น ๊ธฐ์ ์ด ํ์คํ๋์ง ์์ ์์ง ์ด์ ๋จ๊ณ์ ์์ง๋ง CloudFlare์ Mozilla์์๋ ์ด๋ฏธ ์ง์ํ๊ณ ์๋ค๋ ์ ์ ์ง์ ํ๊ณ ์ถ์ต๋๋ค.
์ฝ๊ฐ์ ์ด๋ก
์์ค๋ TLS ํธ๋์ ฐ์ดํฌ "ํด๋ผ์ด์ธํธ Hello" ๋ฉ์์ง์์ SNI ์ํธํ๋ฅผ ํ์ฉํ๋ TLS 1.3 ํ๋กํ ์ฝ์ ํ์ฅ์ ๋๋ค. ESNI๋ฅผ ์ง์ํ๋ Client Hello๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค(์ผ๋ฐ์ ์ธ SNI ๋์ ESNI๋ก ํ์๋จ).
ESNI๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ธ ๊ฐ์ง ๊ตฌ์ฑ ์์๊ฐ ํ์ํฉ๋๋ค.
- DNS;
- ํด๋ผ์ด์ธํธ ์ง์;
- ์๋ฒ ์ธก ์ง์.
DNS
๋ ๊ฐ์ DNS ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค. A๊ณผ TXT (TXT ๋ ์ฝ๋์๋ ํด๋ผ์ด์ธํธ๊ฐ SNI๋ฅผ ์ํธํํ ์ ์๋ ๊ณต๊ฐ ํค๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.) - ์๋๋ฅผ ์ฐธ์กฐํ์ธ์. ๊ฒ๋ค๊ฐ ์ง์์ด ์์ด์ผ์ง DoH (HTTPS๋ฅผ ํตํ DNS) ์ฌ์ฉ ๊ฐ๋ฅํ ํด๋ผ์ด์ธํธ(์๋ ์ฐธ์กฐ)๊ฐ DoH ์์ด๋ ESNI ์ง์์ ํ์ฑํํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ESNI๋ ์ฐ๋ฆฌ๊ฐ ์ก์ธ์คํ๋ ๋ฆฌ์์ค ์ด๋ฆ์ ์ํธํ๋ฅผ ์๋ฏธํ๋ฏ๋ก ์ด๋ ๋
ผ๋ฆฌ์ ์
๋๋ค. ์ฆ, UDP๋ฅผ ํตํด DNS์ ์ก์ธ์คํ๋ ๊ฒ์ ์๋ฏธ๊ฐ ์์ต๋๋ค. ๊ฒ๋ค๊ฐ ์ฉ๋๋
์ง๊ธ ์ฌ์ฉ ๊ฐ๋ฅ
CloudFlare
ะ ๊ธฐ๋ก :
curl 'https://dns.google.com/resolve?name=www.cloudflare.com&type=A'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "www.cloudflare.com.",
"type": 1
}
],
"Answer": [
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.210.9"
},
{
"name": "www.cloudflare.com.",
"type": 1,
"TTL": 257,
"data": "104.17.209.9"
}
]
}
TXT ๊ธฐ๋ก, ์์ฒญ์ ํ ํ๋ฆฟ์ ๋ฐ๋ผ ์์ฑ๋ฉ๋๋ค. _esni.FQDN:
curl 'https://dns.google.com/resolve?name=_esni.www.cloudflare.com&type=TXT'
-s -H 'accept: application/dns+json'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16
}
],
"Answer": [
{
"name": "_esni.www.cloudflare.com.",
"type": 16,
"TTL": 1799,
"data": ""/wEUgUKlACQAHQAg9SiAYQ9aUseUZr47HYHvF5jkt3aZ5802eAMJPhRz1QgAAhMBAQQAAAAAXtUmAAAAAABe3Q8AAAA=""
}
],
"Comment": "Response from 2400:cb00:2049:1::a29f:209."
}
๋ฐ๋ผ์ DNS ๊ด์ ์์ DoH(๋ฐ๋์งํ๊ฒ๋ DNSSEC์ ํจ๊ป)๋ฅผ ์ฌ์ฉํ๊ณ ๋ ๊ฐ์ ํญ๋ชฉ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๊ณ ๊ฐ ์ง์
๋ธ๋ผ์ฐ์ ์ ๊ดํด ์ด์ผ๊ธฐํ๊ณ ์๋ค๋ฉด ํ์ฌ๋ก์๋
๋ฌผ๋ก ESNI๋ TLS 1.3์ ํ์ฅ์ด๋ฏ๋ก ESNI๋ฅผ ์ง์ํ๋ ค๋ฉด TLS 1.3์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
ESNI ์ง์์ผ๋ก ๋ฐฑ์๋๋ฅผ ํ ์คํธํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ํด๋ผ์ด์ธํธ๋ฅผ ๋ค์ ์์น์ ๊ตฌํํ์ต๋๋ค. go, ๊ทธ๋ฌ๋ ๋์ค์ ๋ ์์ธํ ์ค๋ช ํฉ๋๋ค.
์๋ฒ ์ธก ์ง์
ํ์ฌ ESNI๋ nginx/apache ๋ฑ๊ณผ ๊ฐ์ ์น ์๋ฒ์์ ์ง์๋์ง ์์ต๋๋ค. ์๋ํ๋ฉด ๊ณต์์ ์ผ๋ก ESNI๋ฅผ ์ง์ํ์ง ์๋ OpenSSL/BoringSSL์ ํตํด TLS์ ์๋ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋ผ์ ์ฐ๋ฆฌ๋ ESNI๋ฅผ ์ฌ์ฉํ์ฌ TLS 1.3 ์ข ๋ฃ๋ฅผ ์ง์ํ๊ณ ESNI๋ฅผ ์ง์ํ์ง ์๋ ์ ์คํธ๋ฆผ์ ๋ํ ํ๋ก์ HTTP(S) ํธ๋ํฝ์ ์ง์ํ๋ ์์ฒด ํ๋ฐํธ ์๋ ๊ตฌ์ฑ ์์(ESNI ์ญ๋ฐฉํฅ ํ๋ก์)๋ฅผ ๋ง๋ค๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ์ด๋ฅผ ํตํด ์ฃผ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ์ฆ ESNI๋ฅผ ์ง์ํ์ง ์๋ ํ์ฌ ์น ์๋ฒ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ด๋ฏธ ์กด์ฌํ๋ ์ธํ๋ผ์์ ๊ธฐ์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ช ํ์ฑ์ ์ํด ๋ค์ ๋ค์ด์ด๊ทธ๋จ์ ์ฐธ์กฐํ์ธ์.
ํ๋ก์๋ ESNI ์์ด TLS ์ฐ๊ฒฐ์ ์ข
๋ฃํ๊ณ ESNI๊ฐ ์๋ ํด๋ผ์ด์ธํธ๋ฅผ ์ง์ํ๋ ๊ธฐ๋ฅ์ผ๋ก ์ค๊ณ๋์์ต๋๋ค. ๋ํ ์
์คํธ๋ฆผ์ ํต์ ํ๋กํ ์ฝ์ TLS ๋ฒ์ ์ด 1.3๋ณด๋ค ๋ฎ์ HTTP ๋๋ HTTPS์ผ ์ ์์ต๋๋ค(์
์คํธ๋ฆผ์ด 1.3์ ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ). ์ด ๊ตฌ์ฑํ๋ ์ต๋์ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
ESNI ์ง์ ๊ตฌํ go ์ฐ๋ฆฌ๋ ๋น๋ ธ๋ค
ESNI ํค๋ฅผ ์์ฑํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ์ฌ์ฉํ์ต๋๋ค.
Linux(Debian, Alpine) ๋ฐ MacOS์์ go 1.13์ ์ฌ์ฉํ์ฌ ๋น๋๋ฅผ ํ
์คํธํ์ต๋๋ค.
์ด์ ๊ธฐ๋ฅ์ ๋ํ ๋ช ๋ง๋
ESNI ์ญ๋ฐฉํฅ ํ๋ก์๋ rps, ์ ์คํธ๋ฆผ ๋๊ธฐ ์๊ฐ ๋ฐ ์๋ต ์ฝ๋, ์คํจ/์ฑ๊ณต TLS ํธ๋์ ฐ์ดํฌ ๋ฐ TLS ํธ๋์ ฐ์ดํฌ ๊ธฐ๊ฐ๊ณผ ๊ฐ์ Prometheus ํ์์ ๋ฉํธ๋ฆญ์ ์ ๊ณตํฉ๋๋ค. ์ธ๋ป ๋ณด๊ธฐ์ ์ด๋ ํ๋ก์๊ฐ ํธ๋ํฝ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ํ๊ฐํ๊ธฐ์ ์ถฉ๋ถํ ๊ฒ์ฒ๋ผ ๋ณด์์ต๋๋ค.
์ฌ์ฉ ์ ๋ถํ ํ ์คํธ๋ ์ํํ์ต๋๋ค. ์๋ ๊ฒฐ๊ณผ:
wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Running 6m test @ https://esni-rev-proxy.npw:443
50 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.77s 1.21s 7.20s 65.43%
Req/Sec 13.78 8.84 140.00 83.70%
206357 requests in 6.00m, 6.08GB read
Requests/sec: 573.07
Transfer/sec: 17.28MB
์ฐ๋ฆฌ๋ ESNI ์ญ๋ฐฉํฅ ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์๊ณผ ์ฌ์ฉํ์ง ์๋ ๋ฐฉ์์ ๋น๊ตํ๊ธฐ ์ํด ์์ํ๊ฒ ์ ์ฑ์ ์ธ ๋ก๋ ํ ์คํธ๋ฅผ ์ํํ์ต๋๋ค. ์ค๊ฐ ๊ตฌ์ฑ ์์์ "๊ฐ์ญ"์ ์ ๊ฑฐํ๊ธฐ ์ํด ๋ก์ปฌ๋ก ํธ๋ํฝ์ "์์์ต๋๋ค".
๋ฐ๋ผ์ ESNI ์ง์ ๋ฐ HTTP์์ ์ ์คํธ๋ฆผ์ผ๋ก์ ํ๋ก์๋ฅผ ํตํด ESNI ์ญ๋ฐฉํฅ ํ๋ก์์ ํ๊ท CPU/RAM ์๋น์ ํจ๊ป ํ ์ธ์คํด์ค์์ ์ฝ 550rps๋ฅผ ์ป์์ต๋๋ค.
- 80% CPU ์ฌ์ฉ๋(vCPU 4๊ฐ, 4GB RAM ํธ์คํธ, Linux)
- 130MB ๋ฉ๋ชจ๋ฆฌ RSS
๋น๊ต๋ฅผ ์ํด TLS(HTTP ํ๋กํ ์ฝ) ์ข
๋ฃ๊ฐ ์๋ ๋์ผํ nginx ์
์คํธ๋ฆผ์ ๋ํ RPS๋ ~ 1100์
๋๋ค.
wrk -t50 -c1000 -d360s 'http://lb.npw:80' โ-timeout 15s
Running 6m test @ http://lb.npw:80
50 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.11s 2.30s 15.00s 90.94%
Req/Sec 23.25 13.55 282.00 79.25%
393093 requests in 6.00m, 11.35GB read
Socket errors: connect 0, read 0, write 0, timeout 9555
Non-2xx or 3xx responses: 8111
Requests/sec: 1091.62
Transfer/sec: 32.27MB
์๊ฐ ์ด๊ณผ๊ฐ ์๋ค๋ ๊ฒ์ ๋ฆฌ์์ค๊ฐ ๋ถ์กฑํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ(vCPU 4๊ฐ, RAM ํธ์คํธ 4GB, Linux ์ฌ์ฉ) ์ค์ ๋ก ์ ์ฌ์ ์ธ RPS๋ ๋ ๋์ต๋๋ค(๋ณด๋ค ๊ฐ๋ ฅํ ๋ฆฌ์์ค์์ ์ต๋ 2700RPS๋ผ๋ ์์น๋ฅผ ๋ฐ์์ต๋๋ค).
๊ฒฐ๋ก ๋ถํฐ ๋ง์๋๋ฆฌ์๋ฉด ESNI ๊ธฐ์ ์ ๋งค์ฐ ์ ๋งํด ๋ณด์
๋๋ค. ์๋ฅผ ๋ค์ด ๊ณต๊ฐ ESNI ํค๋ฅผ DNS์ ์ ์ฅํ๊ณ ESNI ํค๋ฅผ ์ํํ๋ ๋ฌธ์ ์ ๊ฐ์ ๋ฏธํด๊ฒฐ ์ง๋ฌธ์ด ์ฌ์ ํ ๋ง์ด ์์ต๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ ํ๋ฐํ ๋
ผ์๋๊ณ ์์ผ๋ฉฐ (์์ฑ ๋น์) ESNI ์ด์์ ์ต์ ๋ฒ์ ์ด ์ด๋ฏธ ์์ฑ๋์์ต๋๋ค.
์ถ์ฒ : habr.com