OpenResty와 NGINX의 차이점은 무엇인가요?
API7.ai
September 9, 2022
OpenResty의 장점은 명확합니다. 자세히 학습하기 전에, OpenResty의 개발 과정을 간략히 살펴보면 이후 내용을 더 잘 이해하는 데 도움이 될 것입니다.
OpenResty의 개발 과정
OpenResty는 다른 개발 언어처럼 처음부터 구축된 것이 아니라, 성숙한 오픈소스 컴포넌트인 NGINX와 LuaJIT를 기반으로 합니다. OpenResty는 2007년에 탄생했지만, 첫 번째 버전에서는 Lua를 선택하지 않고 Perl을 선택했습니다. 이는 저자의 기술적 선호와 관련이 깊습니다.
하지만 Perl의 성능은 요구 사항을 충족시키기에는 부족했기 때문에, 두 번째 버전에서는 Perl을 Lua로 대체했습니다. 그러나 OpenResty의 공식 프로젝트에서 Perl은 여전히 중요한 역할을 합니다. OpenResty 생태계 프로젝트는 Perl로 구축되었으며, 테스트 프레임워크, Linter, CLI 등이 이에 해당합니다. 이에 대해서는 차차 소개하겠습니다.
OpenResty의 높은 성능과 동적 특성은 CDN 비즈니스 요구에 매우 적합했기 때문에, OpenResty는 곧 CDN의 기술 표준이 되었습니다. 또한, 풍부한 lua-resty-*
라이브러리를 통해 OpenResty는 NGINX의 그림자에서 벗어나 자체 생태계를 형성하기 시작했으며, API 게이트웨이, 소프트 WAF 등 다양한 분야에서 널리 사용되고 있습니다.
저는 종종 OpenResty가 널리 사용되는 기술이지만, 인기 있는 기술은 아니라고 말합니다. 이는 모순적으로 들릴 수 있습니다. 무슨 의미일까요?
널리 사용된다는 것은 OpenResty가 현재 세계에서 다섯 번째로 많이 사용되는 웹 서버라는 것을 의미합니다.
인기 없다는 것은 OpenResty를 사용하여 비즈니스 시스템을 구축하는 비율이 높지 않다는 것을 의미합니다. 대부분의 사용자는 OpenResty를 인그레스 트래픽 처리에 사용하며, 비즈니스 깊숙이 들어가지는 않습니다. 따라서 자연스럽게 OpenResty의 사용은 얕은 수준에 머무르며, 현재의 요구 사항을 충족시키기에 충분합니다. 이는 물론 OpenResty가 Java나 Python과 같은 성숙한 웹 프레임워크와 생태계를 갖추지 못한 것과도 관련이 있습니다.
이렇게 많은 이야기를 했으니, 이제 OpenResty라는 오픈소스 프로젝트가 칭찬받고 배울 만한 몇 가지 부분을 중점적으로 소개하겠습니다.
OpenResty의 주요 특징
상세한 문서와 테스트 케이스
네, 문서와 테스트는 오픈소스 프로젝트가 신뢰할 수 있는지 여부를 판단하는 중요한 지표입니다. 이는 코드 품질과 성능보다 앞서는 요소입니다.
OpenResty의 문서는 매우 상세하며, 저자는 문서에 주의해야 할 모든 사항을 기록해 두었습니다. 대부분의 경우, 우리는 문서를 주의 깊게 살펴보는 것만으로도 문제를 해결할 수 있으며, 구글 검색이나 소스 코드를 추적할 필요가 없습니다. 편의를 위해 OpenResty는 restydoc
이라는 명령줄 도구를 제공하며, 이는 쉘을 통해 문서를 볼 수 있게 해주어 코딩 과정에서의 중단을 방지합니다.
그러나 문서에는 사용 가능한 코드 조각이 하나 또는 두 개뿐이며, 완전하고 복잡한 예제는 없습니다. 그러한 예제는 어디에서 찾을 수 있을까요?
OpenResty의 경우, 자연스럽게 /t
디렉토리가 그 역할을 합니다. 이 디렉토리에는 모든 테스트 케이스가 포함되어 있습니다. 각 테스트 케이스는 완전한 NGINX 구성과 Lua 코드, 테스트 입력 및 예상 출력 데이터를 포함합니다. 그러나 OpenResty의 테스트 프레임워크는 다른 어설션 스타일의 테스트 프레임워크와는 완전히 다릅니다. 이에 대해서는 나중에 특별한 장에서 소개하겠습니다.
동기식 비차단
코루틴은 최근 몇 년 동안 많은 스크립트 언어가 성능을 개선하기 위해 추가한 새로운 기능입니다. 하지만 이들은 완벽하게 구현되지 않았으며, 일부는 문법적 설탕(syntactic sugar)이고, 일부는 명시적인 키워드 선언이 필요합니다.
OpenResty는 처음부터 코루틴을 지원했으며, 동기식 비차단 프로그래밍 모델을 구현했습니다. 이는 중요합니다. 프로그래머도 인간이기 때문에 코드는 인간의 사고 방식에 더 부합해야 합니다. 명시적인 콜백과 비동기 키워드는 사고를 방해하고 디버깅을 어렵게 만듭니다.
그렇다면 동기식 비차단이란 무엇일까요? 먼저 동기식에 대해 이야기해 보겠습니다. 이는 매우 간단합니다: 코드에 따라 순차적으로 실행하는 것입니다. 예를 들어, 다음의 의사 코드를 보겠습니다:
local res, err = query-mysql(sql)
local value, err = query-redis(key)
동일한 요청에서 MySQL의 쿼리 결과가 반환될 때까지 기다린 후에 Redis를 쿼리해야 한다면, 이는 동기식입니다; MySQL의 반환을 기다리지 않고 Redis를 쿼리할 수 있다면, 이는 비동기식입니다. OpenResty의 경우, 대부분은 동기식 작업입니다. ngx.timer
와 같은 백그라운드 타이머와 관련된 API만이 비동기식 작업입니다.
비차단에 대해 이야기해 보겠습니다. 이는 비동기와 혼동하기 쉬운 개념입니다. 여기서 차단이란 운영체제 스레드를 차단하는 것을 의미합니다. 위의 예제를 계속 살펴보겠습니다. MySQL을 쿼리하는 데 1초
가 걸린다고 가정해 보겠습니다. 이 1초
동안 운영체제의 리소스(CPU)가 유휴 상태로 있고, 반환을 기다리기만 한다면, 이는 차단입니다; CPU가 이 기회를 활용하여 다른 연결 요청을 처리한다면, 이는 비차단입니다. 비차단은 C10K 및 C100K와 같은 높은 동시성을 실현하는 데 있어 핵심입니다.
동기식 비차단의 개념은 중요합니다. 그러나 제 생각에는 이 개념을 비유로 이해해서는 안 됩니다. 부적절한 비유는 오히려 더 혼란을 가중시킬 수 있습니다.
OpenResty에서는 위의 의사 코드가 명시적인 키워드 없이도 동기식 비차단을 직접 달성할 수 있습니다. 이는 다시 한 번 개발자가 더 쉽게 사용할 수 있도록 하는 것이 OpenResty의 개념 중 하나임을 보여줍니다.
동적 특성
OpenResty의 큰 장점 중 하나는 동적 특성입니다. 이는 아직 충분히 활용되지 않았습니다.
전통적인 웹 서버, 예를 들어 NGINX는 런타임 동작을 제어할 수 있는 API를 제공하지 않기 때문에, 변경 사항이 발생하면 디스크의 구성 파일을 수정하고 다시 로드해야 합니다. 따라서 빈번한 변경이 필요한 마이크로서비스 환경에서 NGINX는 여러 번 시도했지만 개선되지 않았습니다. 그리고 Envoy가 갑자기 등장하면서 xDS의 동적 제어 API를 통해 NGINX에 차원 공격을 가하고 있습니다.
NGINX와 Envoy와 달리, OpenResty는 스크립트 언어인 Lua로 제어되며, 동적 특성은 Lua의 자연스러운 장점입니다. 예를 들어, OpenResty의 lua-nginx-module
모듈에서 제공하는 Lua API를 통해 우리는 동적으로 라우트, 업스트림, SSL 인증서, 요청, 응답 등을 제어할 수 있습니다. 더 나아가, OpenResty를 재시작하지 않고도 비즈니스 로직의 처리 방식을 수정할 수 있으며, 이는 OpenResty가 제공하는 Lua API에 국한되지 않습니다.
위에서 말한 동적 특성을 이해하는 데 도움이 되는 좋은 비유를 하나 들겠습니다. 웹 서버를 고속도로에서 달리는 자동차로 생각해 보세요. NGINX는 타이어를 교체하고 페인트 색상을 변경하기 위해 정차해야 합니다; Envoy는 주행 중에 타이어와 색상을 변경할 수 있습니다; 그리고 OpenResty는 전자의 능력 외에도 주차하지 않고도 SUV로 변신할 수 있습니다.
이 마법 같은 능력을 마스터한 후, OpenResty의 역량과 상상력은 Serverless 및 Edge 컴퓨팅과 같은 다른 분야로 확장됩니다.
무엇을 배워야 할까요?
OpenResty의 중요한 특징에 대해 이렇게 많이 이야기했으니, 무엇을 배워야 할까요? 저는 주된 흐름에 집중하는 것을 선호합니다. 모든 것을 잡으려고 하기보다는, 명확한 맥락을 가진 지식 체계를 구축하는 것이 중요합니다.
아무리 포괄적인 강의라도 모든 문제를 다룰 수는 없으며, 온라인에서 발생하는 모든 버그와 예외를 직접 해결해 줄 수는 없다는 것을 알아야 합니다.
OpenResty 학습으로 돌아가서, 제 생각에 OpenResty를 잘 배우려면 다음 여덟 가지 핵심 사항을 이해해야 합니다:
- 동기식 비차단 프로그래밍 모델
- 다양한 Request/Response 단계의 역할
- LuaJIT와 Lua의 차이점
- OpenResty API 및 주변 라이브러리
- 코루틴과 cosocket
- 단위 테스트 프레임워크 및 성능 테스트 도구
- 플레임 그래프 및 주변 도구 체인
- 성능 최적화
이러한 사항들은 우리의 학습에서 필수적이며, 각 장에서 별도로 논의할 것입니다. 그러나 학습 과정에서 여러분은 한 가지 사례에서 유추하여, 자신의 관심사와 배경에 따라 일부 장을 깊이 있게 읽기를 바랍니다.
OpenResty 초보자라면, 강의의 진행에 따라 환경에 OpenResty를 설치하고 샘플 코드를 실행하고 수정해 보세요. 기억하세요, 여러분의 초점은 OpenResty의 큰 그림을 구축하는 데 있으며, 단일 지식에 얽매이지 않는 것입니다. 물론, 질문이 있다면 실시간 채팅을 통해 언제든지 문의하세요.
프로젝트에서 OpenResty를 사용하고 있다면, 훌륭합니다! 그러나 LuaJIT와 성능 최적화 장을 읽을 때 더 많은 공감과 실질적인 응용을 얻을 수 있으며, 프로젝트에서 최적화 전후의 성능 향상을 확인할 수 있을 것입니다.
또한, OpenResty 및 주변 라이브러리에 코드를 기여하고 싶다면, 가장 큰 장벽은 OpenResty의 원리를 이해하거나 NGINX C 모듈을 작성하는 방법이 아니라, 테스트 케이스와 코드 규범입니다. 저는 너무 많은 OpenResty 기여자(저를 포함하여)가 PR에서 테스트 케이스와 코드 스타일을 반복적으로 수정하는 것을 보았으며, 너무 많은 암묵적인 규칙이 있습니다. 따라서 강의의 코드 규범과 단위 테스트 섹션은 여러분을 위한 것입니다.
QA 엔지니어라면, OpenResty를 사용하지 않더라도, OpenResty의 테스트 프레임워크와 성능 분석 도구 세트는 많은 영감을 줄 것입니다. 결국 OpenResty는 테스트에 상당한 투자와 축적이 되어 있습니다.