私が所属する謎社では、Cacheとして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 3.0以降であれば、モジュールとして自動読み込まれるのでいい感じでしょう。

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
戻り値はUTF-8Stringで、デコードされています。PowerShell的にもUTF-8は望ましいのでいい感じでしょう。
パイプライン実行
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]::UTF-8.GetStringではすまないわけですよ。匿名コンストラクタでもほげ