atsukanrockのブログ

Microsoft系技術を中心にぼちぼち更新します。旧ブログ (コンテンツ充実) はこちら -> http://d.hatena.ne.jp/atsukanrock/

AWS Dev Day Tokyo 2017で登壇しました

ブログがあまりにも休止状態で自分にドン引きしていますが、先日開催されたAWS Summit Tokyo 2017*1に併設の開発者向けイベントAWS Dev Day Tokyo 2017*2で登壇しました。スライドがこちら

後ほどAWS Summit Tokyo 2016のようにレポートサイトが公開されるそうです。レポートサイトになったらURLが安定しそうですね。

大きな会場で多くの聴衆の前での登壇となり、内心おっかなびっくりだったのですが、ピンマイクを装着させてもらったことでちょっと楽しくなってしまい、壇上をウロチョロしながらオーバーアクションで喋ったら面白いかもしれない、等と思いつつウロチョロしておりました。しかしなかなか思い切ったアクションというのは難しいもので、やはりこういうのは場数だな、等と思いながら楽しい時間を終えました。こういった機会はありがたいものです。

*1:URLが将来変わる気がする

*2:URLが将来変わる気しかしない

『C#エンジニア養成読本』の一部を執筆しました

ありがたいことに機会をいただき、『C#エンジニア要請読本』という書籍の一部を執筆しました。今回が初めての執筆です。

www.amazon.co.jp

gihyo.jp

こちら共著のムック本でして、他の超強力な著者陣に混じってオマエ誰的な立ち位置を満喫させていただいております *1

ターゲット層としては C# 初心者および初級者という感じ。新人から 2-3 年目の方にピッタリでしょうし *2、他の言語である程度経験がある方が「C# ってどんなもんよ?」とパラ見するのにちょうど良さそうです。つい 1 ヶ月ほど前に出たばかりの Visual Studio 2015 や C# 6.0 の話題もしっかりあります *3

という書籍なんですが、私が書いたパートには C# が一切出てきません笑 執筆の話をお受けする際、他の超強力著者陣にビビって「俺ら (同僚の id:kendik も共著&初執筆です) が書けるとしたらこの辺ですかね~」となったからです。ちょっとぐらい C# 書きたかったかも。。と少々後悔しつつも、私の C# 力はごくごく平均的なため、テーマが「C#」ではやっぱり厳しかったかも。。などと思っております。

それにしても Amazon で自分の名前を検索したら出てくるってのは感動モノです。機会を下さった方々に感謝です。

*1:しれっと大トリをいただきましたッ!

*2:勤務先の来年の新人さんも買うって言ってくれてました

*3:執筆した時期にはまだ出てなかったのにすごい!

Amazon SES および SendGrid によるメール送信のスループットを調べるツールを C# で書いた

仕事で使うためにやっつけで書いていたのですが、やってるうちに勢い余って割と作り込むあるあるを踏み抜き、せっかくなので公開することにしました。

github.com

何ができるかっていうと

大したことはできません。片手間でできるものなんてそんなものですね。あえてできることを挙げるとすると:

はい、それだけです。スループットを手軽に確認するために、コマンドライン引数で動作を微調整できます:

  • concurrency: 何本スレッド立ち上げるか
  • mail-count: 何通メール送るか
  • strategy: どうやってメール送るか (例えば 1 なら Amazon SES の SendRawEmail API を叩くし、4 なら SMTP を叩きます)

GUI なんていうお洒落なものはありません。

ソースコードダイジェスト

できるだけ素早くメール送信したいって時にはいろいろと常套手段があるようでして、私も全然専門じゃないもので詳しいことは分からないのですが、ある程度調べて分かったことは詰め込んでおります。

マルチスレッド処理の初速を上げる

Parallel.ForEach(Enumerable.Range(0, 10000), x => { /* 何かする */ });

とか書いても .NET のマルチスレッドは心優しいので *1 いきなり 1 万個スレッドを立ち上げるようなことはしません。CPU コア数 (かその 2 倍) ぐらいだけスレッドプールのスレッドを申し訳なさそうに拝借して処理を始めてみて、どうやらもっとスレッドを増やした方が効率的みたいだぞ?といったことに自動的に気が付いて徐々に使うスレッド数を増やしていきます。ちょっと記憶が定かでないですが、メール送信ぐらいの I/O バウンドな処理で 100 スレッドぐらいまで並列度が増すのに 1 分以上はかかった気がします。その間に送られたメールは数千通的な。

という話があるのでスループット確認には不向きですねってことで次のようにして初速を上げてます。

ThreadPool.SetMinThreads(Math.Max(options.Concurrency, 200), Math.Max(options.Concurrency, 200));

同時コネクション数を増やす

.NET で作る普通のデスクトップアプリケーションの場合、同一サーバーエンドポイントに対する同時コネクション数が 2 に限定されています。例えばスレッドを 10 個起動し、それぞれの上で SMTP コネクションを張ってドバドバっとメールを送るなんてことができません。2 本までは張れますが、残りはコネクションを張ることができず待たされます。Web ブラウザーなんかの HTTP コネクションと同じ感じですね。

これだとスループット確認のために十分な負荷をかけられないので、こいつを増やします。具体的には App.config の中で以下のように書いてます。

<system.net>
  <connectionManagement>
    <!-- See http://weblogs.asp.net/johnbilliris/don-t-forget-to-tune-your-application -->
    <add address="https://email.es-east-1.amazonaws.com/" maxconnection="1000" />
    <add address="email-smtp.us-east-1.amazonaws.com:587" maxconnection="1000" />
    <add address="https://api.sendgrid.com/" maxconnection="1000" />
    <add address="smtp.sendgrid.net:587" maxconnection="1000" />
  </connectionManagement>
</system.net>

なお、同僚に教えてもらいましたが ServicePointManager.DefaultConnectionLimit なんていうプロパティもあるそうで、これでも同じようなことができるようです。こいつの場合はエンドポイント別の指定ができませんが、ほとんどの場合こいつで十分そうですよね。

SMTP セッションを使い回す

こんな話は SMTP でメールいっぱい送るプログラムを書いたことがないと *2 知る由もないのですが、SMTP というプロトコルはセッションの open / close が非常に重いです。重いっていうか無駄。1 通のメールを送るのにサーバーと 7 回とかやり取りしないといけないそうで。そのうち実際のメールを送ってるやり取りの回数は 3 回とかだそうで、半分以上はセッションの open / close というのですから驚きを禁じ得ません。例えば 10 通メールを送るとして、1 通毎にセッションを開いたり閉じたりしたら 7 * 10 = 70 やり取りです。1 本のセッションで 10 通まとめて送れば 7 + 3 * 9 = 34 やり取り!エコ!!

実際には open / close のための通信量が微少なのに対しメール本体はドカンと行きますから、やり取り回数削減のインパクトほどにはスループット改善しないことの方が多いでしょうけれど *3、それでも無駄は減らすに限りますね。日本人ですから。

というわけで .NET でどうすんだ?というと簡単です。標準で付いてくる SmtpClient クラスのインスタンスを使い回します。

using (var client = new SmtpClient())
{
    foreach (var message in messages)
    {
        client.Send(message);
    }
}

みたいにするだけです。詳しくは MSDN ライブラリ に力の入った解説がありますからそちらをどうぞ。私のコードではいろいろ抽象化してる関係上よく分からんことになってますが、

https://github.com/atsukanrock/EmailThroughputChecker/blob/master/EmailThroughputChecker/Program.cs#L37

この辺で using を開始してその後でループをぶん回してますね。

まとめ

たかがメール送信、されどメール送信ですね。

*1:「スレッドプールを用いるもの」に限る話で、new Thread しちゃえば心優しくない使い方もできる

*2:もしくは telnetSMTP!!

*3:サーバーがどれだけ遠いか = レイテンシも変数に入ってきますね

今だから学びたい!DDD (Domain-Driven Design) - Sansan .NET勉強会 #10 に登壇しました

勤務先で開催された今だから学びたい!DDD (Domain-Driven Design) - Sansan .NET勉強会 #10 という勉強会に登壇しました。私が好きな設計手法である DDD についての発表ということで、けっこう気合いが入っていました。時間の都合上、内容が浅くなってしまったのが心残りです。でも次回以降も同じテーマで機会をいただけるなら、気合いを入れて勉強して発表したいです。

発表資料

(第八回) 「ネクストスケープ×Sansan 」 .NET勉強会で発表しました!!

2月27日の金曜日、(第八回) 「ネクストスケープ×Sansan 」 .NET勉強会に登壇しました。その際の発表資料を公開します。

自分はそもそも生粋の開発者気質でして、ID連携というテーマ自体にはそれほど興味を持てなかったというのが正直あります。きっと自分だけじゃないと思って今回のテーマを選びました。なんで興味が持てないか。いろいろな原因があると思うのですが、自分の場合は以下のような感じでした。

  • 「所詮ログイン、簡単なことでしょ?」という感覚
  • そのくせ調べ出したら情報が大量に出てきて「決定版」が何なのか分からない
  • サービス・アプリケーションが主に解決したい問題・課題 (Domain) とは関係がない

きっと同じように感じている開発者が一定数いるはずと信じ、その人たちが自分と同じところで悩むことが少しでも減るように。という思いで作ったスライドです。細かいことは端折ってます。

Visual Studioでお手軽にメモリリーク調査♪

Visual Studio 2013 (VS) の "Performance and Diagnostics Hub" が超いいです。とうわけでこの記事は自分向けのリンク集です。

.NETアプリのメモリリーク調査には従来からWinDbgという方法がありましたが、WinDbgはとても手軽とは言えません。Performance and Diagnostics Hubなら、VSでデバッグ実行しながら好きな時にメモリ状態のスナップショットを取れます。スナップショットを取る前には好きな時にGCを実行できます。スナップショットには、メモリ使用量はもちろん、オブジェクト型毎のインスタンス数が記録されます。これらの値はスナップショット間での比較が可能なので、リークしている (≒インスタンス数が増え続ける) オブジェクトを特定できます。この記事の方がイメージが分かるスクリーンショットが多いですね。

なおVSのエディションがUltimateなら、Production環境 (ソースがない) でも解析が可能みたいですね。ProdDumpを使って取得したdumpファイルをVSで読み込んで、マネージドメモリーの調査ができるようです。良さそうですね。自分はUltimateエディションを使えないので試せませんが。

メモリリーク調査の基本的な考え方を知るには、"実戦的WPF・Silverlightメモリーリーク解消方法" (パワポ直リン注意) というパワポが良いと思いました。

めとべや東京 #5で発表してきました

タイトルは「マルチスレッドデザインパターン再考」です。我ながら仰々しいタイトルですが、結局Producer-Consumerパターン最高!みたいな内容になりました*1。でも実際Producer-Consumerパターンはバッチリハマる局面ではなかなか強力です。後述のデモアプリでは半ば無理やり*2使いまくってます。今っぽいProducer-Consumerパターンの書き方についてはTwitterを #めとべや でググるLINQ星人の人*3がいろいろ呟いているかもしれません。

スライド自体は勢いで書き切りましたが、個人的に今回はデモアプリ(サンプルコード)の実装に全てを懸けてました。GitHubで全て公開してますので、興味のある方はご覧ください。後述の背景からゴミがたんまり残ってます。

https://github.com/atsukanrock/MultithreadDesignPattern

デモアプリは最終的に以下の形になりました。

  1. WPFの管理者用アプリがWebフロントエンドからのユーザー入力をSignalRで受け取る。
  2. 収集開始ボタンのクリックでBing Search APIを叩いてBing画像検索をし、検索結果の画像をローカルのテンポラリーフォルダーに収集する。
  3. 処理開始ボタンのクリックでテンポラリーフォルダー内の画像に画像処理をかけ、画面にどんどん表示していく。

当初(本当)は以下の形を目指していたんですが、Worker Roleのプログラミングに不慣れだったせいでマルチスレッドプログラミングがまともにできず撃沈。近いうちに勉強して修正したいです。

  1. 2種類のAzure Worker Roleを起動しておく。画像処理をシングルスレッドでするものとマルチスレッドでするもの。それらへの処理リクエストはAzure Queue Storageで行う。
  2. WPFの管理者用アプリがWebフロントエンドからのユーザー入力をSignalRで受け取る。
  3. 収集開始ボタンのクリックでBing Search APIを叩いてBing画像検索をし、検索結果の画像をAzure Blob Storageに保存する。
  4. 処理開始ボタンのクリックで、上記2種類の画像処理Worker Roleへの処理要求メッセージをQueue Storageに保存する。
  5. Worker RoleはBlob Storageからオリジナル画像を取得して画像処理をし、Blob Storageに処理結果の画像を保存する。1枚終了する度にASP.NET Web APIでWeb Roleに報告する。
  6. 報告を受けたWeb RoleはSignalRでWPFの管理者用アプリに伝える。
  7. WPFの管理者用アプリが処理結果の画像をどんどん表示する。

発表中のデモでは画像処理が重すぎて*4途中で見るのを止めてしまいましたが、発表後に確認したらちゃんとマルチスレッド版が2~3倍早くなっていました。

シングルスレッドだと513秒程度かかった*5:

f:id:atsukanrock:20140803113828p:plain

マルチスレッドだと234秒になった!:

f:id:atsukanrock:20140803114145p:plain

*1:細かな内容を考える前にタイトルを申請しなければならないのです

*2:サンプルですしおすし

*3:@neuecc さん

*4:というかデモに使ったAzure VMのスペックが悪かったのかも

*5:非常に見にくいですが画像が並んでいるすぐ上に表示されてます