아파치 웹서버 mod_lua 팁 몇 가지

Twitter icon류광, 2014-08-29 01:08
Apache 웹 서버의 mod_lua를 사용해 보고 얻은 팁 몇 가지.

mod_lua는 Apache 웹 서버(이하 그냥 아파치)에서 프로그래밍 언어 루아(Lua)를 사용할 수 있게 해주는 모듈입니다. 아파치 2.4부터는 이 모듈이 아파치 배포본에 기본으로 포함되어 있으로 따로 구해서 설치할 필요가 없습니다. 게다가 PHP처럼 그냥 웹 내용(HTML 페이지 등)을 생성하는 능력은 물론, 아파치의 작동 방식 자체에 좀 더 깊숙하게 관여할 수 있는 능력을 가지고 있습니다. 예를 들어 예전에는 mod_rewrite로 하던 URL 매핑 작업도 mod_lua를 통해서 루아 스크립트로 수행할 수 있습니다. 본격적인 프로그래밍 언어로 매핑 논리를 짤 수 있으므로 예전보다 훨씬 복잡하고 지능적인 처리가 가능합니다. 이런 점으로 볼 때 루아가 아파치의 '일급시민' 언어(구현용 언어는 아니고 최종 사용자를 위한)로 자리잡고 있다고 할 수 있겠습니다. 언젠가는 httpd.conf나 .htaccess 같은 설정 파일들까지도 루아 스크립트가 대신하게 될 거라는 예상도 가능합니다.

저는 주로 내용 생성을 목적으로 mod_lua를 사용해 보았는데요. 그 과정에서 알게 된 사항 몇 가지를 써 보겠습니다.

r:parsebody()의 기본 처리 용량

버전 2.4의 mod_lua 문서화의 첫 번째 루아 예제에 이런 부분이 있습니다.

function handle(r)

... 중략 ...

    elseif r.method == 'POST' then
        r:puts("Hello Lua World!\n")
        for k, v in pairs( r:parsebody() ) do
            r:puts( string.format("%s: %s\n", k, v) )
        end

... 후략 ...

이 부분은 POST 요청에 담긴 자료, 즉 사용자가 HTML 양식을 통해 제출한 자료를 추출하는 방법을 보여 줍니다. r:parsebody()는 HTML 양식으로 제출된 키-값 쌍들의 배열을 돌려줍니다.

간단한 텍스트 변환 스크립트를 만들면서 저는 딱 위의 예만 참고해서 입력 텍스트를 얻는 코드를 작성했습니다. 그런데 이상하게도 입력 텍스트가 일정 분량 이상이면 끝이 잘리는 현상이 일어났습니다. 한참 동안 원인을 못 찾고 있다가 매뉴얼 페이지를 다시 자세히 보니,

r:parsebody([sizeLimit]) -- parse the request body as a POST and return two lua tables,
                         -- just like r:parseargs().
                         -- An optional number may be passed to specify the maximum number 
                         -- of bytes to parse. Default is 8192 bytes:

local POST, POSTMULTI = r:parsebody(1024*1024)

sizeLimit 인수를 생략하면 8192바이트만 읽는다는 것이었습니다. 더 많은 내용을 얻으려면 예제 코드처럼 더 큰 수를 인수로 지정해야 합니다.

Sqlite3 연동

mod_lua는 데이터베이스 연결 기능을 제공합니다만 데이터베이스 기능을 직접 구현하고 있는 것은 아니고, 데이터베이스 기능을 가진/또는 실제 데이터베이스 시스템과 연동하는 개별적인 아파치 모듈이 활성화되어 있어야 합니다. 저는 따로 데이터베이스 시스템을 돌릴 필요가 없는 Sqlite3을 사용하기로 했습니다.

해당 도움말을 참고해서 코드를 짜는데, 제가 뭘 잘못했는지 아니면 mod_lua나 Sqlite3 모듈의 구현에 문제가 있는지 그냥 r:dbacquire("sqlite3", ... 으로는 잘 되지 않았습니다. 결국은 mod_dbd라는 모듈을 사용하는 것으로 해결을 봤습니다.

mod_dbd는 일종의 DB 추상층으로, 구체적인 데이터베이스 종류와 이름을 코드에 밖아 넣지 않고 외부 설정 파일에서 지정할 수 있게 하는 것입니다. 코드에서는 그냥

local db, err = r:dbacquire("mod_dbd")

로 데이터베이스와 연결을 하고, 대신 구체적인 설정을 httpd.conf에서 다음과 같이 지정해 둡니다.

# DB 구동기 종류
DBDriver sqlite3
# 연결 매개변수(Sqlite3의 경우 DB 파일 이름)
DBDParams "../../db/mydb.sqlite"
## 최대 연결 개수
DBDMax 10

이것이 작동하려면 mod_dbd용 Sqlite3 구동기인 apr_dbd_sqlite3-1.dll가 있어야 합니다. 그런데 이 파일은 표준적인 아파치 배포판의 일부가 아니라서 APR 프로젝트에서 소스를 받아서 직접 빌드해야 합니다. Windows 환경에서 오픈소스 라이브러리를 빌드하다 고생한 경험을 가진 분들이 있겠지만, 다행히 이 프로젝트는 Visual Studio용 빌드 파일들이 잘 갖추어져 있어서 빌드가 그리 어렵지 않습니다. 세 가지만 주의하면 별 문제 없이 apr_dbd_sqlite3-1.dll를 얻을 있을 것입니다.

첫째는, apr_dbd_sqlite3가 포함된 APR-util뿐만 아니라 APR과 APR-iconv도 함께 내려받아야 한다는 점입니다. 짐작하셨겠지만 의존성 때문입니다.

둘째는, 역시 프로젝트 간 의존성 때문에 위의 세 가지 프로젝트들의 디렉터리를 해당 문서에 나온 것처럼 같은 디렉터리 안에 병렬로 배치해야 합니다. 이런 식으로요.

C:\\work\\apr\\
C:\\work\\apr-iconv\\
C:\\work\\apr-util\\

디렉터리 이름 역시 딱 apr, apr-iconv, apr-util이어야 합니다.

마지막으로, apr_dbd_sqlite3-1.dll을 만들려면 공식 sqlite3 라이브러리 자체가 필요한데 다행히 이 라이브러리는 모든 코드를 하나의 C 소스 파일로 통합한 sqlite3.c를 제공하기 때문에, 그냥 그 파일을 apr-util/dbd 에 넣고 해당 프로젝트에 추가하기만 하면 됩니다. sqlite3.c는 http://www.sqlite.org/에서 구할 수 있습니다.

JSON의 작은따옴표 탈출 문제

이것은 사실 mod_lua와는 상관 없는 사항이지만 mod_lua를 활용하면서 한참 헤맸던 부분이라 이야기합니다.

JSON.org의 오토마타 도식

Image

에서 보듯이 역슬래시 탈출이 적용되는 문자들은 딱 정해져 있고, 작은따옴표는 거기에 포함되어 있지 않습니다. 그런대 제가 사용하던 한 JSON 루아 구현은 이를테면 "occam's Razor"라는 문자열을 JSON으로 변환할 때 "occam\\'s Razor"로 탈출시켰습니다. 어쩌면 C나 C++, PHP와는 달리 루아에서는 작은따옴표(')와 큰따옴표(")의 구분이 없다는 게 그런 실수에 영향을 미쳤을지도 모르겠습니다.

어쨌든 "occam\\'s Razor"는 잘못된 표기이고, 그런 문자열이 포함된 JSON 객체는 유효한 JSON이 아닙니다. 요즘 버전은 모르겠지만 당시 사용하던 버전의 크롬 브라우저는 그런 문자열이 포함된 JSON 객체를 (정당하게)거부했고, 그래서 제가 만들던 텍스트 변환 스크립트가 JSON 형태로 브라우저에게 보낸 내용이 제대로 표시되지 않는 오류가 생겼습니다.

지금은 그런 문제가 없는 dkjson을 사용하고 있습니다.


불특정 다수를 위한 웹 응용 프로그램에 사용하기에는 아직 어설픈 구석이 있고 보안상의 검증도 충분하지 않지만, 개인용 브라우저 앱을 만드는 데에는 아파치+mod_lua가 아주 쓸만해 보입니다. 물론 전통의 아파치+PHP 조합이나 요즘 많이 회자되는 node.js도 있지만, 루아를 좋아하는 사람에게는 mod_lua가 아주 매력적일 것입니다.

태그: 프로그래밍 Lua

comments powered by Disqus