私が所属する謎社では、Cache として Redis をフルに活用しています。Redis大好き最高です。
そんなRedis ですが、 インタラクティブに操作するクライアントとして誰もがお世話になったことがあるのが redis-cli でしょう。
ビルトインで使えるとても有用なクライアントです。
しかしこのクライアントはLinux用で、Windowsで使えません。
Windowsから、かつ C#、PowerShellからRedis Commandをインタラクティブに叩きたい。そんなあなたに今回は 謎社で利用しているクライアントの紹介です。
目次
RespClient
ResClient
弊社で使っているのは、 弊社の neuecc が作った RespClientです。
このクライアントの特徴は、Redis Protocol specification つまり、RESP プロトコルを解釈してSocket経由で叩いていることです。
しかも、C# から呼ぶだけではなく、PowerShell Cmdletとしても実装されています。
MSOpenTech の Redisクローンはどうなのか
MSOpenTech 大センセーの cloneならWindowsでもRedisが使えます。
しかし、C#、PowerShell から呼び出して制御したいのであって、外部コマンドをラップするのがどう考えてもいやです。そういう意味でも、RespClientのRESPを解釈してSocketで叩けるのはPowerShellから呼び出すにあたって正にあってほしい機能となります。
PowerShell から Cmdlet として使ってみよう
PowerShell Cmdlet が実装されているということは、Moduleとしてdll提供されているということです。
PowerShell から呼び出す流れを見てみましょう。
Github
このクライアントは Github で公開されています。
まずはクローンなり、Zipをダウンロードするなりしてください。
ビルド
RespClient.slnを開いてさくっとビルドします。
VS2013 であれば何も問題なくビルドできるかと思います。
Binary Module (.dll) の配置
生成された、RespClient\bin\Release\RespClient.dll
をモジュールパスに配置するか、任意のパスにおきましょう。
$env:USERPROFILE\Documents\WindowsPowerShell\Modules\RespClient\RespClient.dll
に配置すれば、PowerShell V3 以降であれば、モジュールとして自動読み込まれるのでいい感じでしょう。
RespClient Module の読み込み
もし、モジュールパスに配置しなかった場合は、Import-Module を使って直接RespClient.dll を読み込んでください。
PowerShell ISE でも、PowerShell.exe でもいいのでお好きな方でどうぞ。
Import-Module RespClient.dll
モジュールパスに配置していた場合は不要です。
これで準備はできました。
RespClient で PowerShell から Redis を叩く
RespClient で公開されている Cmdlet
早速みてみましょう。
Get-Command -Module RespClient
これらのCmdlet が公開されています。
CommandType Name ModuleName ----------- ---- ---------- Cmdlet Begin-RedisPipeline RespClient Cmdlet Connect-RedisServer RespClient Cmdlet Disconnect-RedisServer RespClient Cmdlet Execute-RedisPipeline RespClient Cmdlet Get-RedisCurrentInfo RespClient Cmdlet Send-RedisCommand RespClient
早速使ってみましょう。
Redis ServerへのSocket接続を生成する
この時利用するのは、次のCmdlet です。
Connect-RedisServer
ヘルプを見てみましょう。
help Connect-RedisServer -full
NAME Connect-RedisServer SYNTAX Connect-RedisServer [[-Host] <string>] [[-Port] <int>] [[-IoTimeout] <int>] [<CommonParameters>] PARAMETERS -Host <string> Required? false Position? 0 Accept pipeline input? false Parameter set name (All) Aliases None Dynamic? false -IoTimeout <int> Required? false Position? 2 Accept pipeline input? false Parameter set name (All) Aliases None Dynamic? false -Port <int> Required? false Position? 1 Accept pipeline input? false Parameter set name (All) Aliases None Dynamic? false <CommonParameters> This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, PipelineVariable, and OutVariable. For more information, see about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). INPUTS None OUTPUTS System.Object ALIASES None REMARKS None
対象のRedisサーバーへのSocket接続を作ります。
Redisに親しんでいる方にはご存知の通り、HostアドレスとPortとIoTimeout が設定可能です。
デフォルトでは 127.0.0.1 に 6379 で接続しますが、10.0.0.10 の Port 7000 で接続したい場合は次のようにします。
Connect-RedisServer -Host 10.0.0.10 -Port 7000
Socket接続は、一度接続すれば任意のタイミングできるまで接続しっぱなしなので、コマンド実行ごとに接続を作ったり渡す必要がないのが特徴です。REPLには好ましい動作ですね。
現在のSocket接続を調べる
Socket接続で繋ぎっぱなしな以上、確認はしたくなりますね。
Cmdlet一発で取得できます。
Get-RedisCurrentInfo
結果です。
Host Port IoTimeout ---- ---- --------- 10.0.0.10 6379 -1
Redis Serverへコマンドを送信する
Socket接続を作ったら早速コマンドを送信してみましょう。
これもCmdlet一発です。
Send-RedisCommand
ヘルプです。
NAME Send-RedisCommand SYNTAX Send-RedisCommand [-Command] <string> [<CommonParameters>] PARAMETERS -Command <string> Required? true Position? 0 Accept pipeline input? true (ByValue) Parameter set name Command Aliases None Dynamic? false <CommonParameters> This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, PipelineVariable, and OutVariable. For more information, see about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). INPUTS System.String OUTPUTS System.Object ALIASES None REMARKS None
Redis のコマンドは さすが Linuxで String です。なので、実行したいコマンドを文字列で渡して実行するだけです。簡単。
たとえば、 info cpu コマンドででCPU情報を取得してみるなら、こうです。
Send-RedisCommand -Command "info cpu"
結果がとれますね。
# CPU used_cpu_sys:14346.90 used_cpu_user:1883.09 used_cpu_sys_children:90018.57 used_cpu_user_children:681373.81
もちろん Pipeline 入力にも対応しているのでこう書くこともできます。
"info cpu" | Send-RedisCommand
戻り値はUTF8String で、デコードされています。PowerShell的にも UTF8は望ましいのでいい感じでしょう。
パイプライン実行
Redis といえば パイプライン実行です。
猫も杓子もパイプライン。パイプラインによるアトミック性担保と高速処理すぎょい。
Cmdletでも対応していてくれて、最高です。
こんなかんじですね。
Begin-RedisPipeline Send-RedisCommand "set test fghijk" Send-RedisCommand "incr testb" Send-RedisCommand "incr testc" Send-RedisCommand "get test" Execute-RedisPipeline
結果です。
OK 1 1 fghijk
パイプラインで実行されました。
流れを簡単に説明しましょう。まず、パイプラインの開始は、Begin-RedisPipeline で行います。
Begin-RedisPipeline
その間実行された、Send-RedisComamnd は、すべて即時実行されずパイプラインにキューされます。
Send-RedisCommand "set test fghijk" Send-RedisCommand "incr testb" Send-RedisCommand "incr testc" Send-RedisCommand "get test"
最後にExecute-RedisPipelien でパイプライン実行されます。
Execute-RedisPipeline
なかなか redis-cli でパイプライン実行といわれてもすぐにピンと来なくても PowerShell 経由であれば直観的に操作できることが分かるかと思います。
Redis Serverとの Socket接続を切断する
Socket 接続は、新しい Connect-RedisServer を行うことで前の接続は切断されます。
あるいは任意のタイミングで切断するには、Disconnect-RedisServerを使います。
Disconnect-RedisServer
接続されていない状態で、Send-RedisCommandを行ってもエラーがでるのでわかりやすいでしょう。
Send-RedisCommand "set test fghijk"
Send-RedisCommand : Server is not connecting 発生場所 行:1 文字:1 + Send-RedisCommand "set test fghijk" | clip + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Send-RedisCommand], InvalidOperationException + FullyQualifiedErrorId : System.InvalidOperationException,Redis.PowerShell.Cmdlet.SendCommand
.NET呼び出し
もちろん PowerShell Cmdlet ではなく、.NET呼び出しも可能です。
ふつーにRespClientモジュールをインポートすれば準備は完了です。
Import-Module RespClient
サンプルC# コード
例えば、C# の次のコードをPowerShell で同様に書いてみましょう。
using (var client = new Redis.Protocol.RespClient()) { // string command client.SendCommand("set a 1", Encoding.UTF8.GetString); // binary safe command client.SendCommand("set", new[] { Encoding.UTF8.GetBytes("test"), Encoding.UTF8.GetBytes("abcde") }, Encoding.UTF8.GetString); // use pipeline var results = client.UsePipeline() .QueueCommand("incr a") .QueueCommand("incrby b 10") .QueueCommand("get a", Encoding.UTF8.GetString) .Execute(); } // disconnect on dispose
PowerShell に using はないのでお察しですが。また、単純には binary safeな書き方ができないので、さっくり String Command と use pipelineで見てみましょう。*1
# connection $client = New-Object Redis.Protocol.RespClient -ArgumentList ("10.0.0.10", 6379) # string command $client.SendCommand("set a 1") $client.SendCommand("get a") # use pipeline $result = $client.UsePipeline(). QueueCommand("incr a"). QueueCommand("incrby b 10"). QueueCommand("get a"). Execute() # disconnect and dispose $client.Dispose() $client = $null
後置き記法ができなくてしょぼんですね。
まとめ
RespClient を使えば PowerShell から Redis が自在に操作できます。PowerShell に限らずさくっと C#からという用途でも是非ご活用ください。
*1:[System.Text.Encoding]::UTF8.GetString ではすまないわけですよ。匿名コンストラクタでもほげ