こんにちは! Redisの奥深い世界へようこそ。
今日は、Redisの中身をぐっと便利に、そして安全に使いこなすための秘密兵器「Lua(ルア)スクリプト」についてお話しするね。
「データベースの中でプログラムを動かす? なんだか難しそう……」と思ったかもしれないけれど、大丈夫。専門用語はできるだけ使わずに、僕たちが普段暮らしている世界に例えて、優しく丁寧にほどいていくよ。
ここをクリアすれば、君もRedisの裏側を自由自在に操るマスターに一歩近づけます。さあ、一緒に冒険に出かけよう!
—
1. なぜRedisの中でプログラムを動かしたいの?
想像してみてほしい。君が人気カフェの店長で、レジ(Redis)の前に行列ができてたとしよう。
お客さんから「このクーポンを使って、ポイントを半分引いて、残りを別のカードで払って、あ、でも残高が足りなかったら……」という、ちょっと複雑な注文を受けたとするよね。
これをふつうにやろうとすると、こうなるんだ。
1. レジから今のデータをいったん全部自分の手元(アプリ側)に持ってくる。
2. 電卓を叩いて、計算する。
3. 計算結果をまたレジに打ち込んで書き換える。
もし、この作業をしている最中に、別のお客さんの注文が割り込んできたらどうなる? レジの中身がめちゃくちゃになって、大パニックになっちゃうよね。これをエンジニアの世界では「データの食い違い」って呼ぶんだ。
そこで登場するのが、「レジのカウンターの上で、一筆書きでパパッと複雑な計算を済ませちゃう魔法」。これがRedisのLuaスクリプトなんだよ。
—
2. RedisのLua環境は「ガラス張りの厳重な小部屋」
Redisの中には、Luaというコンパクトで素早く動くプログラム言語を実行できる、小さな小部屋(サンドボックス環境)が用意されているんだ。
ただ、この小部屋、すごく厳格なルールで作られている。
外のルールとは切り離されていて、自由勝手には振る舞えないようになっているんだ。なぜそんなに厳しいのか? それには、Redisが持つ「世界一のスピード」と「絶対にデータを壊さない信頼性」を守るための理由があるんだよ。
そのルールを、日常の例えで2つに分けて見てみよう。
—
3. ルールその1:「グローバル変数」の持ち込み禁止!
日常の例え:会社の机に私物を置きっぱなしにしちゃダメ!
君がシェアオフィス(Redis)で仕事をするとき、共有の机の上に昨日使ったメモや、自分のマグカップを置きっぱなしにして帰ったらどうかな? 次にその机を使う人が困っちゃうよね。
Luaの小部屋でも全く同じ。
プログラムの中で、うっかり名前をつけただけの変数(これを「グローバル変数」って言うんだ)を外の世界に置きっぱなしにしようとすると、Redisはこう怒るんだ。
> 「おいおい、そんな散らかされたら次の人の邪魔になるから禁止!」
コードで見てみよう
RedisでLuaを書くときは、必ず変数を `local`(ローカル)という言葉をつけて宣言しなきゃいけないルールになっているよ。
— 【良い例】ちゃんとお片付けできる(ローカル変数)
local total_price = 1000
return total_price
— 【ダメな例】勝手に共有スペースに私物を置いちゃう(グローバル変数)
— これをやるとRedisに怒られてエラーになります!
bad_variable = 1000
「変数の前には必ず `local` をつける」。これだけ覚えておけば、お片付け上手なプログラマの仲間入りさ!
—
4. ルールその2:「いつ実行しても同じ結果になる」こと(決定論)
日常の例え:占いや「今日の気分」で結果が変わっちゃダメ!
例えば、自動販売機でお茶を買うとするよね。
「ボタンを押した瞬間の、店長の気分によって値段が変わります」だったら、怖くて買えないよね? いつ誰がボタンを押しても、「130円」を入れれば確実にお茶が出てこなくちゃ困る。
Redisの裏側では、マスター(親機)のデータが、世界中にいるスレーブ(子機)たちに正確にコピーされていく仕組み(レプリケーション)があるんだ。
もし、Luaスクリプトの中で「いま何時だっけ? (現在時刻)」とか「適当なランダムの数字を作って!」なんて気まぐれなことをやらせるとどうなる?
- マスターの部屋で作られた結果と、子機の部屋で作られた結果が微妙にズレてしまうんだ。
- 結果、世界中のデータがバラバラになって、システムが大崩壊してしまう。
だから、RedisのLua小部屋の中では、「いつ、どこで、何度実行しても、100%同じ結果になる計算」しかやっちゃいけないという鉄の掟があるんだ。
—
5. 実践!安全でスマートなLuaスクリプトを書いてみよう
じゃあ、実際にRedis上で動く簡単なスクリプトを見てみようか。
今回は、「お財布残高が足りていれば、お金を引いて『買えました!』と返す」という処理を、安全な一筆書き(トランザクション)でやってみるよ。
Redisのコマンドライン(`redis-cli`)から動かすイメージで見てみてね。
EVALコマンドを使って、その場でLuaスクリプトを実行するよ
意味:KEYS[1]番目の財布から、ARGV[1]円を引き落とす!
EVAL ”
local current_balance = tonumber(redis.call(‘GET’, KEYS[1]))
local cost = tonumber(ARGV[1])
— お金が足りるかチェック
if current_balance >= cost then
— 足りたら引き落としを実行
redis.call(‘DECRBY’, KEYS[1], cost)
return ‘SUCCESS: お買い上げありがとうございます!’
else
— 足りなかったらそのまま返す
return ‘ERROR: 残高が不足しています…’
end
” 1 my_wallet 500
ここがポイント!
- `redis.call(…)` を使って、Redisの中のデータを安全に操作しているよ。
- 外から渡す「財布のキー(`my_wallet`)」や「金額(`500`)」は、ちゃんと整理された場所(`KEYS`や`ARGV`)から受け取っているから、余計な混乱が起きないんだ。
—
おわりに:ここをクリアすれば、君はもう中級者!
お疲れ様! どうだったかな?
RedisのLuaサンドボックス環境のルールをまとめると、たったこれだけ。
1. 変数は必ず `local` をつけてお片付けする(グローバル変数の禁止)
2. 気まぐれ(現在時刻やランダム)な処理は持ち込まず、いつ実行しても同じ結果にする(決定論の維持)
この2つのルールさえ守れば、Redisの持つ爆発的なスピード感を損なうことなく、安全かつ複雑なデータ処理を思い通りに組み立てられるようになるんだ。
「制約があるからこそ、美しく安全なコードが書ける」。この感覚が掴めれば、君はもう立派なRedis使いだよ。
日々の開発で、ぜひこの魔法の小部屋を試してみてね。応援しているよ!
コメント