Ubuntu 18.04 + nginx + lua拡張モジュールでRedis Serverへ接続
事の発端はLINE APIを触っていた時。LINE API + Google App Engine + Pythonでボットを作成する
POSTされた値を処理した後にレスポンスを返すわけですが、処理に手間取るとタイムアウトするんじゃないか。
だったら、受け取ったPOSTデータを一旦退避してとりあえず200レスポンスを返す。
退避しておいたデータをじっくり眺めて処理すれば、タイムアウトを気にしなくてよいのでは。
というわけで、nginxをlua拡張モジュール付きでUbuntu Server 18.04にインストール。
Redisにpostされたデータを登録してみます。
nginx-extras
nginx-extrasをインストールすれば、lua拡張モジュール付きでビルドされた
nginxがインストールできます。
apt-getでDebian 8 + lua nginx moduleの環境構築(nginx-extras)
$ sudo apt install nginx-extras
動作確認のため、/etc/nginx/sites-available/defaultを編集。
$ sudo vi /etc/nginx/sites-available/default
locationの部分を編集します。
- location / {
- default_type 'text/plain';
- content_by_lua "ngx.say('Hello,lua!')";
- }
nginxの設定ファイルをリロード
$ sudo service nginx reload
ブラウザでアクセスしてみます。
luaが動いていますね。
スクリプトファイルの準備とデバッグ設定
毎回nginxの設定ファイルを変更するのは面倒なので、プログラム部分を別ファイルに記載できるようにします。
また、プログラムを書き換えるたびに設定ファイルをリロードするのも手間なので、
「lua_code_cache off」でスクリプトファイルをキャッシュしないよう指定しておきます。
※本番環境では使用しないほうが良いです。
- location / {
- lua_code_cache off;
- default_type 'text/plain';
- content_by_lua_file /var/dev/lua/sample.lua;
- }
編集がおわったらリロード。
$ sudo service nginx reload
/var/dev/lua/sample.luaにプログラムを記載してみます。
・sample.lua
- ngx.say('Hello, from script')
ちゃんと読み込まれていますね。
lua-nginx-redis
redisへの接続はlua-nginx-redisを使ってみます。
https://github.com/openresty/lua-resty-redis
aptでインストール。
$ sudo apt install lua-nginx-redis
サンプルを実行してみます。
- local redis = require "nginx.redis"
- local r = redis:new()
- -- データベース接続
- local ok, err = r:connect("127.0.0.1", 6379, 0)
- if not ok then
- ngx.say("failed to connect: ", err)
- return
- end
- -- データ登録
- ok, err = r:set("dog", "an animal")
- if not ok then
- ngx.say("failed to set dog: ", err)
- return
- end
- -- データ取得
- local res, err = r:get("dog")
- if not res then
- ngx.say("failed to get dog: ", err)
- return
- end
- if res == ngx.null then
- ngx.say("dog not found.")
- return
- end
- -- 取得したデータを表示
- ngx.say("dog: ", res)
いい感じです。
postデータの登録
postされたデータを登録してみます。
過去記事が参考になりました。
nginx + luaで簡易ファイルストレージ
・sample.lua
- local method = ngx.req.get_method()
- if method ~= 'POST' then
- ngx.say('post only')
- return
- end
- -- bodyの解析
- ngx.req.read_body()
- -- body_dataを取得してみる
- local req_body = ngx.req.get_body_data()
- -- 取得できなかったら、ファイルに保存されている
- if not req_body then
- -- テンポラリファイル名を取得
- local req_body_file_name = ngx.req.get_body_file()
- -- 内容をすべて読み込み
- local file = io.open(req_body_file_name, 'rb')
- req_body = file:read('*a')
- file.close()
- end
- local redis = require "nginx.redis"
- local r = redis:new()
- -- データベース接続
- local ok, err = r:connect("127.0.0.1", 6379, 0)
- if not ok then
- ngx.say("failed to connect: ", err)
- return
- end
- -- データ登録
- ok, err = r:set("body", req_body)
- if not ok then
- ngx.say("failed to set body: ", err)
- return
- end
- ngx.say('ok')
データ登録用のPythonスクリプトです。
・post.py
- # -*- coding:utf-8 -*-
- import urllib.request
- import json
- # 登録用のデータ
- data = {
- 'num' : 105,
- 'alphabet' : 'alphabet-value',
- 'str': '日本語登録テスト'
- }
- # JSON形式の文字列を取得
- jsonstr = json.dumps(data).encode("utf-8")
- url = 'http://192.168.1.102/'
- request = urllib.request.Request(url, data=jsonstr, method='POST')
- request.add_header('Content-Type', 'application/json')
- # 登録実行
- response = urllib.request.urlopen(request)
- ret = response.read()
- print('Response:', ret)
実行すると「ok」と応答が帰ってきました。
$ python3 post.py
Response: b'ok\n'
次はredisに登録されているはずのpostデータを取得してみます。
- # -*- coding:utf-8 -*-
- import json
- import redis
- r = redis.StrictRedis(host='192.168.1.102', port=6379, db=0)
- rawdata = r.get('body')
- data = json.loads(rawdata)
- print(data['num'])
- print(data['alphabet'])
- print(data['str'])
実行結果
$ python3 sample.py
105
alphabet-value
日本語登録テスト
ちゃんとpostされたデータをredis経由で取得できました。