2014年11月30日日曜日

GDG Devfest Kyoto 2014で発表してきました。

もうすでに、公式のイベントレポートが上がっているのですが、私も参加してきたので書き残しておきたいと思います。

皆さんSlideshareで公開されているようですが、私はGDGのオーガナイザーですから、Google Presentationを使って資料を作っています。その資料は以下のURLから参照して下さい。

https://docs.google.com/presentation/d/1nDTrzQ5etYb_7F2GhumY2pNO3KsRWp9TpTjd00g1Dtc/edit?usp=sharing

今回は依頼を受けた時に、私の前に何人か発表するということがわかっていましたので、初心者向けというわけにもいかないだろうなと思ったので、Golang Cafeで1年間いろんなことをやって来ましたので、自分でも整理するためにGolang Cafeで特に議論することがあった部分について紹介しようと思っていました。

が、12月にリリース予定のGo1.4についての話題が出てきて、すでにrc版になっていましたので、ここは早く1.4の内容について紹介するのがいいだろうと思って、半分はこれまでの内容で、半分を1.4の内容にすることにしました。(実際には思いつかなかった(≒思い出せなかった)ということもあるのですが…)

Go.1.4の内容に関してはBlogに書いていませんが、Golang Cafe #55でやった内容をそのまま資料にしています。やっぱり一番衝撃的だったのは、Androidの正式サポートでしょうか。言語仕様からして合わないだろうと思っていたのですが、しっかり入れてきました。動きも申し分なく動いていますし、良さそうに見えます。
後は、ドキュメントがどれくらいでてくるか。ということと、NDKの仕様が変わらないことを祈っています。
(当日の発表前にオリジナルのデモを作ろうと頑張っていたのですが、ちょっと間に合いませんでした。私のNDKのノウハウの不足と時間不足でした。)

今日のGoConの情報で思い出したけど、何らかの書き込み時にWrite()、Flush()、Close()の順番で呼び出すけど、Close()でエラーのチェックをしないと困る時があるというのは入れておくべきだったと思いました。
実は、実装によっては、パッケージ内部で以前発生したエラーをずっと持っていて、Close()を呼び出したタイミングでエラーを返すという場合があるので、必ずClose()はチェックするようにしましょう。というものです。
そうだったなと思い出すけど、なかなか実践できていないというのが現状かなと思いました。

貴重な経験を頂きましてありがとうございました。また、何かのタイミングでGDG京都のイベントに参加できれば、その時はよろしくお願いします。

2014年11月16日日曜日

Golang Cafe #54を開催しました。

Golang Cafe #54を開催しました。今回は、Go1.4 Release Notesを読み進めました。

今回、読み進めた所は、以下の点です。

  • Changes to the language
    • For-range loops
    • Method calls on **T
  • Changes to the supported operating systems and architectures
    • Android
  • Changes to the compatibility guidelines
  • Changes to the implementations and tools
    • Internal packages
    • Canonical import paths
    • Import paths for the subrepositories
    • The go generate subcommand
    • Change to file name handling
    • Changes to package source layout
  • Performance
  • Changes to the standard library
    • Major changes to the library
      • syscall
    • Minor changes to the library
      • Testing周りを中心に見ました。

個人的に読み進めた部分をおさらいしたような流れになってしまいましたが、再度読み返してみて、わりといろんな所が変更になっていると思います。

For-range loopsの変更はブランク演算子("_")を書かなくても良くなった点が変更になっています。
次に、ポインタのポインタのメソッドを呼ぶ事が1.3以前では呼び出せていたものが、コンパイルエラーになります。

参考コード(Go Playgroundなので、1.4に置き換わるまでは動作します。)
http://play.golang.org/p/JTHWyVJ3V-(こちらは1.4でもビルドが通る)
http://play.golang.org/p/k-GxLYJOPO(こちらは1.4からコンパイルエラー)

以前のGolang Cafeでも話題になったように、ポインタをあまり使わないのであれば特に影響はありません。

Go1.4からのAndroidのサポートが増える件については、Qiitaの記事を見て動作確認をしてみてください。

いろいろ変更になっていますが、1.3以前までの互換性のガイドラインに変更はありません。(実際、1.0系/1.1系を使っているという方は、あまりいないかもしれませんが…アップデートを忘れている事例を除いて…)

他に増えたのが、
内部パッケージ(Internal Package)でパッケージのディレクトリ内に"internal"というディレクトリを作ると、同一パッケージ外から参照する事ができないパッケージを作ることができるようになります。

それから、Canonical Import Paths(標準的なインポートパス)ということで、package文の末尾にコメントを記入することで、ローカルのディレクトリ構成が正しい(≒go getしたものが正式である)時でないとコンパイルエラーにすることができるようになりました。
リポジトリもいろんなものがあるので、リポジトリを移設することも考えられるかもしれません。そういう時に古いリポジトリを参照しているといつまでも最新バージョンに置き換えられないことになるので、強制的にアップデートさせるのにいいかもしれません。
ただし、go get -uとかして、最新のコードが取得されていないとダメですが…。

Goの公式パッケージのリポジトリがGoogle Codeからgolang.orgに変更されます。
来年の6月1日から正式移行のようです。

go generateコマンド(実際には、コメントに書かれたコマンドを起動するだけのもの)が追加されました。最初は「ライブラリ作者には便利」とだけ認識していましたが、ビルド時に実行したいコマンドを書いておくことで、任意のコマンドを実行する事ができます。(大体はソースコードの自動生成で利用されることと思いますが…)

以前は、windows.goとか、amd64.goというファイル名でwindows専用だったり、64bit専用のソースコードとしてコンパイルされていましたが、これからはそれができなくなります。

あとは、テストコードを書く時に、これまでだと、全てのテストにsetupの処理と、teardownの処理を書かなくてはいけませんでしたが、Go1.4でTestMain()が追加になったので、全てのテストに共通した準備と後処理を書く事が可能になりました。Go本体だと、テスト後にメモリリークが発生しているかどうかのチェックを行うという使い方がされていました。

次回(これからですが)は、Goで大量データを処理するコードを書いて実行する。
ということをテーマに進めて行く予定です。

2014年11月9日日曜日

Golang Cafe #53を開催しました。

Golang Cafe #53を開催しました。

今回は前回に引き続き、isucon4の予選問題に挑戦しました。Golang Cafeということで、GoのWebアプリケーションを置き換えたりしながら速度アップを図っていきました。

最初の状態のスコアは以下のようになりました。

$ ./benchmarker b
18:12:29 type:info message:!!! DEBUG MODE !!! DEBUGE MODE !!!
18:12:29 type:info message:launch benchmarker
18:12:29 type:warning message:Result not sent to server because API key is not set
18:12:29 type:info message:init environment
18:12:34 type:info message:run benchmark workload: 1
18:13:34 type:info message:finish benchmark workload: 1
18:13:39 type:info message:check banned ips and locked users report
18:14:04 type:report count:banned ips value:4
18:14:04 type:report count:locked users value:2568
18:14:04 type:info message:Result not sent to server because API key is not set
18:14:04 type:score success:6620 fail:0 score:1430

successがリクエストをして正しい結果が返ってきた回数で、failが間違った結果が返ってきた回数です。実際には最後のScoreの値で競っていくようです。

このisuconのアプリケーションはmartiniが使われていたので、gorillaに書き換えてみました。

$ ./benchmarker b
22:40:23 type:info message:!!! DEBUG MODE !!! DEBUGE MODE !!!
22:40:23 type:info message:launch benchmarker
22:40:23 type:warning message:Result not sent to server because API key is not set
22:40:23 type:info message:init environment
22:40:29 type:info message:run benchmark workload: 1
22:41:29 type:info message:finish benchmark workload: 1
22:41:34 type:info message:check banned ips and locked users report
22:41:59 type:report count:banned ips value:4
22:41:59 type:report count:locked users value:2569
22:41:59 type:info message:Result not sent to server because API key is not set
22:41:59 type:score success:6760 fail:0 score:1461

Golang Cafeの最中では、エラーが取れなかったのですが、その後すぐに原因が分かったのでエラーを修正した結果です。Scoreが31上がりました。やっぱりreflectionを使うとスピードがどうしても遅くなるようです。

次に、Golang Cafe #50の時に教えてもらった、gojiに書き換えてみました。

$ ./benchmarker b
23:18:46 type:info message:!!! DEBUG MODE !!! DEBUGE MODE !!!
23:18:46 type:info message:launch benchmarker
23:18:46 type:warning message:Result not sent to server because API key is not set
23:18:46 type:info message:init environment
23:18:53 type:info message:run benchmark workload: 1
23:19:53 type:info message:finish benchmark workload: 1
23:19:58 type:info message:check banned ips and locked users report
23:20:23 type:report count:banned ips value:6
23:20:23 type:report count:locked users value:2567
23:20:23 type:info message:Result not sent to server because API key is not set
23:20:23 type:score success:6920 fail:0 score:1495

更に、スコアが34上がりました。gojiは軽量フレームワークなので処理スピードが早いようです。

ここまでのソースコードはgithubにpushしてありますので興味があればどうぞ。
ソースコードをそれぞれで修正したかったので、branchを分けています。
masterは何もしていない状態なので修正後のものが見たい時は、branchを切り替えて下さい。

Goのフレームワークを変えるだけでもかなり差が出ることがわかりましたが、Sessionの保存にgorilla/sessionを使っているので、データがCookieに全て保存されて通信されてしまっているのでその辺りも修正すればもう少しスピードアップが見込めそうな気がしています。(ローカルでのテストなので通信コストは低いけど…)

次回は、リリース間近のGo1.4のRelease Noteを読み進める予定です。

2014年11月2日日曜日

Golang Cafe #52を開催しました。

Golang Cafe #52を開催しました。

今回は、isuconという「与えられたサーバとそこで動作するWebアプリケーションを高速化してアクセス数を競うイベント」の予選問題でGolangが使われたという情報を聞いたので、実際に挑戦してみようという主旨で開催しました。

本来はAMIというAWSで動作するイメージを使ってAWSにデプロイして競うようなのですが、「課金前提」ということで、GCEに…というのもやめまして、ローカルにデプロイしようと頑張ってみました。

最初、「Dockerを使おう」ということで、

$ docker pull mysql

としたのですが、これが大失敗。関連する全てのコンテナをダウンロードし始めて、1時間待ってもダウンロードが終了しなかったので(Wimax回線の調子が悪かった…?)ローカルのhomebrewを使ったインストールに切り替えました。

$ brew update
$ brew install mysql

これで、mysqlがインストールできたので、早速ログインしてバージョンを確認します。

$ mysql.server start

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.20    |
+-----------+
1 row in set (0.03 sec)

インストールが完了したので、次にinit.shを動かしました。
すると、"MySQL server has gone away"というメモリ不足で発生するエラーに悩まされました。
drupalのblogに設定の記載例があったのでそれを元に、my.cnfを修正しました。
ただし、table_cacheという設定はないようで、そのままコピペしても改善しませんでした。実際に編集する時はtable_cacheの行は書かないようにしましょう。

[mysqld]

# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M

# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin

# These are commonly set, remove the # and set as required.
# basedir = .....
# datadir = .....
# port = .....
# server_id = .....
# socket = .....
skip-external-locking
key_buffer = 384M
max_allowed_packet = 64M
sort_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 64M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size = 32M
max_allowed_packet = 32M
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M 

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 

これでinit.shを実行した所、今度は、

ということになったので、いろいろ試行錯誤した結果、+0900という記載がダメなようなので
$ sed -e s/\+0900//g dummy_log2.sql

として、+0900の記述を消してから登録しました。homebrewでインストールした時のtimezoneがJSTになっていたので、これをUTCに変えてやればそんなことをしなくても良さそうな気がしてきました。が、本来の主旨と違う気がしたのでそこまで検証していません。

次に、Webサーバの起動ですが、Goの場合は、アプリケーションにhttpサーバの機能があるので、go buildして、起動するだけです。
$ cd webapp/go
$ ./build.sh
$ ./golang-webapp

これで、http://localhost:8080に接続すると「いすこん銀行」が表示されるはずです。

次に、ベンチマーク用コマンドもGoで書かれていますので、go buildすればいいのですが、makefileが用意されているので、それに従ってコンパイルします。
中身を見ると、標準でAWSにリクエストを飛ばすようになっているので、
$ cd benchmarker
$ make debug

として、コンパイルします。すると、localhostに対するリクエストになります。
ですが、そのままだと、http://localhostへのリクエストになり、goのwebappにリクエストが送信されないので、main.goの81行目付近を書き換えます。

    cli.StringFlag{
     Name:   "host",
     Value:  "localhost:8080",
     Usage:  "Bench Endpoint host",
     EnvVar: "ISUCON4_BENCH_HOST",
    },

これでビルドしなおせばローカルホストに対するリクエストが送信されるようになり、スコアも表示されるようになります。

ということで、今回はGoに関する内容ができなかったので、次回(今日、これから)に持ち越しとなります。