Dropbox ने Nginx से Envoy पर स्विच क्यों और कैसे किया
(dropbox.tech)<p>Dropbox, जो करोड़ों concurrent connections, प्रति सेकंड लाखों requests और terabyte-स्तर की bandwidth संभालता है, ने एक लेख में Nginx की तुलना में Envoy के फायदों को अच्छी तरह समझाया है.<br />
<br />
पहले: nginx (open source version) + python2 + Jinja2 + YAML <br />
→ एक चीज़ बदलने पर भी पूरा redeploy ज़रूरी<br />
→ dynamic हिस्से Lua में विकसित किए गए<br />
→ जटिल logic, Go-आधारित proxy Bandaid में संभाला जाता था<br />
<br />
करीब 10 साल तक यह अच्छी तरह चला, लेकिन मौजूदा environment के लिए अब उतना उपयुक्त नहीं था<br />
→ internal और external (private) APIs धीरे-धीरे REST से gRPC में जा रहे हैं, इसलिए proxy में transcoding फ़ीचर की ज़रूरत है<br />
→ Protocol Buffers internal service definition का standard बन गया है <br />
→ सभी software, language की परवाह किए बिना, Bazel से build और test होते हैं<br />
→ बड़े infrastructure projects की open source communities में कर्मचारी काफ़ी सक्रिय रूप से भाग लेते हैं<br />
<br />
Nginx को operational दृष्टि से maintain करना भी महंगा था<br />
→ config generation logic बहुत ज़्यादा flexible है और YAML, Jinja2, Python में बंटी हुई है<br />
→ monitoring, Lua / log parsing / system-based monitoring का मिश्रण है<br />
→ third-party modules पर बढ़ती dependency, stability/performance को प्रभावित करती है और बार-बार upgrades की लागत बढ़ाती है <br />
→ nginx की deployment और process management अन्य services से काफ़ी अलग है; syslog, logrotate जैसी default system चीज़ों से हटकर बहुत सी अलग dependencies हैं<br />
<br />
इसलिए 10 साल में पहली बार Nginx को replace करने का फैसला किया गया<br />
<br />
* Bandaid (Dropbox का खुद बनाया Go-आधारित proxy) क्यों नहीं? * <br />
→ Go, C/C++ की तुलना में ज़्यादा resources खाता है. <br />
→ Go का TLS stack FIPS support नहीं करता (U.S. Federal Information Processing Standards)<br />
→ यह internal tool है, इसलिए external community support नहीं मिल सकता <br />
<br />
अब: Envoy-आधारित traffic infrastructure में migration <br />
<br />
----- Nginx की तुलना में Envoy बेहतर क्यों था ------<br />
<br />
* Performance *<br />
<br />
Nginx की architecture event-driven / multi-process है. SO_REUSEPORT & EPOLLEXCLUSIVE support है<br />
यह event loop पर आधारित है, लेकिन पूरी तरह non-blocking नहीं है. File open/logging के समय event loop रुक सकता है. (`aio`, `aio_write` और threadpool enable होने पर भी)<br />
इससे tail latency बढ़ती है और कभी-कभी कई सेकंड की delay भी हो सकती है<br />
<br />
Envoy भी इसी तरह event-driven architecture पर आधारित है, लेकिन process नहीं बल्कि thread-आधारित है <br />
SO_REUSEPORT support (BPF filter support सहित), और `libevent` के जरिए event loop support <br />
event loop में blocking I/O नहीं है. Event logging भी non-blocking तरीके से implement किया गया है.<br />
<br />
सैद्धांतिक रूप से दोनों की performance characteristics समान लगती थीं, और ज़्यादातर workload tests में वैसी ही रहीं.<br />
लेकिन long tail में Nginx की latency ज़्यादा थी. वजह थी कि I/O ज़्यादा होने पर event loop रुक जाता था.<br />
<br />
stats collection के बिना Nginx की performance Envoy जैसी थी, लेकिन internal Lua stats collection tool ने high-RPS tests में Nginx को 3 गुना धीमा बना दिया. (यह `lua_shared_dict` के mutex-based synchronization की वजह से था). Dropbox मानता है कि उनके stats collection approach में भी समस्या थी, लेकिन इसे कुशलता से फिर से बनाना छोड़ दिया गया. (क्योंकि Nginx के अंदर instrumentation करने से future upgrades मुश्किल हो जाते)<br />
<br />
कुल मिलाकर, ये समस्याएँ Envoy में नहीं थीं, इसलिए migration के बाद Dropbox उन servers का अधिकतम 60% तक release कर सका जो पहले Nginx चला रहे थे.<br />
<br />
* Observability *<br />
<br />
Nginx का free version, stub status module के जरिए केवल 7 तरह के stats देता है <br />
यह स्पष्ट रूप से पर्याप्त नहीं था, इसलिए `log_by_lua` handler जोड़कर अधिक stats निकाले जा रहे थे.<br />
साथ ही, `error.log` parser के जरिए error जानकारी export की जाती थी, और nginx internal state values को export करने के लिए अलग exporter भी था.<br />
<br />
एक बुनियादी Envoy setup, Prometheus format में हज़ारों तरह के metrics देता है <br />
proxy traffic जानकारी से लेकर server की internal state तक,<br />
cluster-wise/upstream-wise/virtual host-wise stats और listener-wise TCP/HTTP/TLS downstream stats आदि<br />
<br />
इन विविध stats के साथ, Envoy tracing provider को plugin के रूप में जोड़ने की सुविधा भी देता है.<br />
यह सिर्फ traffic team ही नहीं, application developers के लिए भी उपयोगी है.<br />
<br />
अंत में, Envoy gRPC के जरिए access logs को stream भी कर सकता है.<br />
इससे traffic team पर syslog-to-hive bridge को support करने का बोझ घटता है.<br />
custom TCP/UDP listeners जोड़ने की तुलना में सामान्य gRPC service चलाना कहीं ज़्यादा आसान और सुरक्षित है.<br />
<br />
* Integration *<br />
<br />
Nginx का integration बहुत Unix-जैसा है. Configuration बहुत static है.<br />
यह config files, TLS certificates, allowlist/blocklist जैसी चीज़ों के लिए files पर निर्भर करता है.<br />
यह सरल है और backward-compatible भी, इसलिए कुछ shell scripts से automation संभव है,<br />
लेकिन system बढ़ने के साथ testability और standardization कहीं अधिक महत्वपूर्ण हो जाते हैं.<br />
<br />
Envoy का इस integration के लिए अपना अलग तरीका है.<br />
यह `xDS` नाम का API देता है और protobuf तथा gRPC के उपयोग को बढ़ावा देता है.<br />
Envoy इन `xDS` queries के जरिए dynamic resources खोजता है.<br />
<br />
- यह `xDS`, अब Envoy से आगे बढ़कर Universal Data Place API (UDPA) के नाम से L4/L7 load balancers के de facto standard की दिशा में विकसित हो रहा है, और हमारे अनुभव में यह काफ़ी सफल रहा है. Envoy के अलावा Katran eBPF/XDP L4 load balancer में भी UDPA इस्तेमाल करने की कोशिश चल रही है.<br />
<br />
Dropbox के लिए यह और भी बेहतर है, क्योंकि उसकी internal services पहले से ही gRPC के जरिए integrate होती हैं.<br />
<br />
* Configuration *<br />
<br />
Nginx की एक बड़ी ताकत यह है कि इसकी config files मनुष्यों के लिए पढ़ने में आसान होती हैं. <br />
लेकिन जैसे-जैसे configs जटिल हुईं और auto-generated होने लगीं, यह फायदा कम हो गया.<br />
Dropbox में ये Python2, Jinja2, YAML आदि से generate होती थीं, जिससे data model भी उलझा हुआ और जटिल बन गया.<br />
<br />
Envoy के पास configuration के लिए एक unified data model है. सभी config values Protocol Buffer में परिभाषित हैं. इससे data modeling की समस्याएँ हल होती हैं और config values में type information भी जुड़ती है.<br />
Dropbox के अंदर protobuf का बहुत उपयोग होता है, इसलिए integration आसान हो गया <br />
<br />
* Extensibility * <br />
<br />
Nginx में extensibility के लिए C modules लिखने पड़ते हैं. सुरक्षित module development के लिए senior developers की ज़रूरत होती है. हल्के modules के लिए Perl / JS interfaces भी दिए गए हैं, लेकिन वे बहुत सीमित हैं. इसलिए सबसे आम तरीका `lua-nginx-module` के जरिए विस्तार करना है. <br />
<br />
Envoy का मुख्य extension mechanism C++ plugins है. इसकी documentation, nginx जितनी अच्छी नहीं है, लेकिन यह बहुत सरल है. इसकी वजह है साफ़-सुथरे और अच्छी तरह commented interfaces, C++14 language और standard library वगैरह <br />
<br />
Envoy को दूसरे web servers से अलग करने वाली बड़ी बात है WebAssembly (WASM) support.<br />
इससे Rust जैसी अलग-अलग languages के जरिए extensions विकसित किए जा सकते हैं. <br />
Dropbox अभी WASM का उपयोग नहीं कर रहा, लेकिन अगर कभी `Go SDK for proxy-wasm` support मिलता है तो यह बदल सकता है<br />
<br />
* Building and Testing *<br />
<br />
Nginx मूल रूप से custom shell-based configuration और `make`-based build का उपयोग करता है. यह सरल और उत्कृष्ट है, लेकिन इसे Bazel से build होने वाले monorepo में integrate करने में काफ़ी मेहनत लगी <br />
Nginx में Perl-आधारित integration tests हैं, लेकिन unit tests नहीं हैं.<br />
<br />
Envoy का build system पहले से Bazel-आधारित है और इसे हमारे monorepo में आसानी से integrate किया गया.<br />
यह gtest/gmock-आधारित unit tests और integration test framework support करता है<br />
<br />
* Security *<br />
<br />
Nginx का codebase बहुत छोटा है और इसकी external dependencies भी कम हैं, इसलिए security vulnerabilities अपेक्षाकृत कम हैं.<br />
<br />
Envoy का codebase बड़ा है, इसलिए attack surface भी ज़्यादा दिखता है. इसके लिए Envoy आधुनिक security practices पर काफ़ी निर्भर है. यह AddressSanitizer, ThreadSanitizer, MemorySanitizer आदि का उपयोग करता है. <br />
<br />
* Features * <br />
<br />
यह हिस्सा काफ़ी हद तक subjective है, इसलिए संदर्भ के साथ पढ़ें<br />
<br />
Nginx की शुरुआत बहुत कम resources में static files serve करने वाले web server के रूप में हुई थी. <br />
यानी static serving, caching, range caching इसके मुख्य काम थे<br />
proxy के नज़रिए से देखें तो आज की infrastructure ज़रूरतों के लिए Nginx में कई कमियाँ हैं. <br />
यह backend से HTTP/2 connections नहीं करता, multi-connection gRPC proxying नहीं कर पाता, और gRPC transcoding भी नहीं कर सकता.<br />
इसका open-core licensing model भी ऐसा है कि कुछ अहम features “community version” में नहीं हैं<br />
<br />
Envoy की शुरुआत ही ingress/egress proxy के रूप में हुई थी, और यह gRPC-heavy environments में व्यापक रूप से उपयोग होता है.<br />
web serving features अभी बहुत शुरुआती स्तर के हैं. File serving नहीं, caching अभी बन रही है, और brotli का support भी नहीं है <br />
ऐसे environments के लिए Nginx setup भी उपयोग में है, जिसमें Envoy को upstream cluster की तरह इस्तेमाल किया जाता है <br />
उम्मीद है कि जब Envoy HTTP cache support करने लगेगा, तब ऐसे static serving environments भी migrate किए जा सकेंगे <br />
<br />
Envoy, gRPC से जुड़े कई features support करता है<br />
- gRPC proxying<br />
- HTTP/2 to backends<br />
- gRPC → HTTP bridge (+ reverse.) <br />
- gRPC-WEB <br />
- gRPC JSON transcoder<br />
<br />
इसके अलावा Envoy को outbound proxy की तरह भी इस्तेमाल किया जा सकता है <br />
- Egress Proxy<br />
- Courier gRPC library के साथ third-party software service discovery <br />
<br />
* Community *<br />
<br />
Nginx development काफ़ी centralized है और उसका अधिकांश हिस्सा छिपा रहता है. <br />
Envoy development खुला और decentralized है. यह GitHub issues/PRs के जरिए चलता है, और mailing lists/Slack आदि पर भी काफ़ी सक्रिय है </p><p>----- Dropbox की मौजूदा migration स्थिति -----<br />
<br />
Nginx और Envoy को पिछले आधे साल से साथ में चलाया जा रहा है, और DNS के जरिए traffic धीरे-धीरे migrate किया जा रहा है <br />
migration पूरी तरह बिना समस्या के नहीं हुई; कुछ छोटे issues थे, लेकिन कोई गंभीर outage नहीं हुआ.<br />
"unusual" या "non-RFC" behavior के कारण आए issues के solutions भी संकलित किए गए हैं (विस्तार के लिए मूल लेख देखें)<br />
<br />
** आगे की योजनाएँ **<br />
<br />
- HTTP/3 : Envoy ने भी experimental support शुरू कर दिया है. UDP acceleration के लिए Linux kernel upgrade करने के बाद इसे आज़माने की योजना है<br />
- internal xDS-based load balancer और Outlier Detection<br />
- WASM-based Envoy extensions <br />
- Bandaid (Go-आधारित proxy) को Envoy से replace करना <br />
- Envoy Mobile के जरिए mobile apps में भी Envoy लागू करना</p>
3 टिप्पणियां