Ymsrの壮大な送別会
ブログ書くまでがなんとやらで。遅くなりますた。
さてYmsrの送別会に逝ってきた。いろんな人が色々書いているので詳細は書かないけど、花火もあがり、MBAで包丁もしたし、ベルギービールではれてMBAも破壊して、これでみんな前向けるんじゃないかなと。というかそのための会だったと思いたい。太一、よしおり、Mesoたん、他幹事みなさん本当にお疲れさまでした。とても良い会だった。
山城と僕は実はそんなに親しい関係というわけじゃない。ただちょっとアレがアレな感じでwww、お互い意識せざるを得ない関係であった事は間違いないw 一時期は確実に一歩ひかれていた。「おー、山城元気」(山城一歩あとずさりする)、みたいな。しかし、このネタ、当の本人がこの世を去ったあたでもまだ引っ張るのかと思いつつ、まあそれはそれで関係があってうれしい気もする。まさかお別れの会でもこのゲスいネタをやるとは思いもしなんだよ。。。
正直ここ数年の彼はちょっと心配だった。FBやTwitterの書き込みをみても、なんだか前を向いているのかがよくわかんなかったのが正直な感想だ。でも人それぞれな部分あるし、いつか会って話を聞いてみるまでは勝手な判断はやめようと思ってた。で、そこでConmameが開催まで持ってきてくれたAWS Casual Talksに山城がきて、本当に久しぶりの再会だった。これがおそらく亡くなる一ヶ月前くらいだったように思う。
そのときの彼は前を向いてた。色々あったみたいだったけど、会社やるかもとか将来にすっごい前向きだった気がする。しかもなかなか楽しそうで、純粋になんかそれがうれしかった。だから噂レベルで亡くなったという話が聞こえてきたときは本当に残念だった。他の人のように泣きまくったり、何も手つかずとかそういう感じではないのだけど、少なくともしばらく毎日の足取りが重くなり、考えてもどうしようもできない類いのもので、聞くにも聞けずといった感じだった。特に太一とよしおりには。なかなか言葉で言い表すのは難しい。
今回の送別会は本当に太一らしいなと思った。あいつらしく、カオスでグダグダな部分もあって、キチガイじみてて、だけど皆相当笑ってたし、泣いてたな。ジコマン結構じゃん。スライドもなしにいろんな人がしゃべりはじめたときは、なんかわからんが感動した。話は結構がゲスい気もしたけど、なぜか感動した。そして太一がMacを買ったことに宗教上の観点から驚きを禁じ得ない。
最後に勝手な自己満をたれる。山城は少なくとも僕が会った最後の感じはとても前向きだった。だから、前を向こうと思うし、前を向いてほしいなと思う(そこのあなたですよ)。自分が他の人と同じようなつらさなのかはよくわかんない。多分違うんじゃないかなと思う。でもあえて言うと、前を向いてほしい。あと、山城がくっそー参加できなくて、くやしい!おまえら!!!と思うくらいどうしようもない感じの何かをjava-jaで続けてほしいと思う。java-jaってそこでしょ。子持ちになって色々なものに参加が難しい昨今だけど、なるべく時間の許すかぎり参加したいと思う。そして、たまにはばか騒ぎしたい。
P.S.子供のノロ疑惑で先に帰ってすまんかった。。。
そしてスライドはパブリックにはあげれねえw
山城、んじゃね。
shot6
AWS Advent Calendar 12/13 -Go言語でのAWS、特にDynamoDBの利用-
AWSのアドベントカレンダーの12月13日として、私が興味あるGo言語からAWSをどうやって利用するかを述べようかなと思います。
ここ最近Goは暇な時間を見つけては好きに書いているだけなので、大して書けるわけではないです。そこんとこご了承ください。
Goって?
Googleが開発しているオープンソースのプログラミング言語で、非常にシンプルなのにも関わらず必要十分な機能があります。
詳しくは http://golang.org/ まで。はい、おしまい。
シンプルなコードで簡単なWebアプリ書くならこんな感じになります。これはGo言語のチュートリアルかなんかに従って作ったWebアプリです。
package main import ( "fmt" "io/ioutil" "net/http" "html/template" "regexp" "errors" "log" "os" ) /* * Struct prestenting wiki page */ type Page struct { Title string Body []byte } /* * Template caching for some templates which heavily used. */ var templates = template.Must(template.ParseFiles("edit.html", "view.html")) /* * valid path regex * - m1: edit, view, save * - m2: [a-zA-Z0-9]+ */ var validPath = regexp.MustCompile("^/(edit|view|save)/([a-zA-Z0-9]+)$") /* * Simple logger from golang logging feature. */ var logger = log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds|log.Lshortfile) /* * Make http.HandlerFunc for editing, viewing, saving by title given by URL */ func MakeHandler(fn func(w http.ResponseWriter, r *http.Request, title string)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { m := validPath.FindStringSubmatch(r.URL.Path) if m == nil { http.NotFound(w, r) return } else { fn(w, r, m[2]) } } } /* * View handler */ func ViewHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := LoadPage(title) if err != nil { http.Redirect(w, r, "/edit/" + title, http.StatusFound) return } else { RenderTemplate(w, "view", p) } } /* * Edit Handler */ func EditHandler_ugly(w http.ResponseWriter, r *http.Request, title string) { p, err := LoadPage(title) if err != nil { p = &Page{Title:title} } fmt.Println("ugly", p.Body) } /* * Edit Handler */ func EditHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := LoadPage(title) if err != nil { p = &Page{Title:title} } RenderTemplate(w, "edit", p) } /* * Save Handler */ func SaveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") page := &Page{Title:title, Body:[]byte(body)} err := page.Save() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { http.Redirect(w, r, "/view/" + title, http.StatusFound) } } /* * save page */ func (p *Page) Save() error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600) } /* * load page as Page struct */ func LoadPage(title string) (*Page, error) { filename := title + ".txt" body, error := ioutil.ReadFile(filename) if error != nil { return nil, error } return &Page{Title:title, Body:body}, nil } /* * Render using template loaded from name. */ func RenderTemplate(w http.ResponseWriter, tmpl string, p *Page) { err := templates.ExecuteTemplate(w, tmpl + ".html", p) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } /* * bootstrap */ func main() { logger.Println("start web server...") logger.Println("register http.HandlerFunc.") http.HandleFunc("/view/", MakeHandler(ViewHandler)) http.HandleFunc("/edit/", MakeHandler(EditHandler)) http.HandleFunc("/save/", MakeHandler(SaveHandler)) logger.Println("bootstrap web server...") http.ListenAndServe(":8080", nil) }
GoからのAWS利用方法
現状残念ながらAWSからの正式SDKは出ていませんが、比較的アクティブに動いているプロジェクトは幾つかあります。
例えばGoamz(https://launchpad.net/goamz)とかですね。その中で特にDynamoDBを利用するには、今回紹介するGodynamoがなんかよさげにみえます。
Godynamoの前に
今回のre:InventでAWSのヘビーユーザであるSmugmugはMySQLからDynamoDBへ移行した話をしてくれました。
Smugmugは大きく分けて3つ今回新しいオープンソースを出しています。
- Godynamo : DynamoDBをGoから使うライブラリ
- bbpd : DynamoDBをHTTPプロキシしてくれるライブラリというかサーバ?
- goawsroles : GoからIAM Roleをシームレスに使うためのライブラリ。
時間が出来ればbbpdは試してみたいですねー!bbpdがあると
curl -X POST -d '{"TableName":"mytable","Key":{"Date":{"N":"20131001"},"UserID":{"N":"1"}}}' "http://localhost:12333/GetItem?indent=1&compact=1"
こんな感じでDynamoのデータを参照できます。便利!
Godynamo
GodynamoはAWSのヘビーユーザであるSmugmugが実際に使っているGo言語用のDynamoDBライブラリになります。
実際にMySQLからの移行から使われているので実績は既にあるものになります。
Godynamoを使うには3つのことをする必要があります。
- Goのインストール
- 必要なライブラリのインストール
- クレデンシャル情報の設定
クレデンシャル情報の設定はjsonファイルにて行います。
大きく分けて、アクセスキーとシークレットキーを使う方法と、IAM Roleを使う方法があります。
設定ファイル自体は~/.aws-config.jsonとしておきます。
設定ファイルはこんな感じ。
{ "extends":[], "services": { "default_settings":{ "params":{ "access_key_id":"your_access_key", "secret_access_key":"your_secret_key", "use_sys_log":true } }, "dynamo_db": { "host":"dynamodb.ap-northeast-1.amazonaws.com", "zone":"ap-northeast-1", "iam": { "use_iam":false, "role_provider":"file", "access_key":"role_access_key", "secret_key":"role_secret_key", "token":"role_token", "base_dir":"/dir/where/you/update/role_files", "watch":true } } } }
本来はIAM Roleを使うべきですが、今回は割愛します。本番ではIAM Roleを使いましょう!
コードは非常にシンプルに作ることが出来ます。私が気に入ってるのは、
- 直感的でわかりやすい
- レスポンスが生のJSONで帰ってくるので、どう扱うかは利用者側にゆだねられている
- 早い
のあたりです。特に生のJSONファイルなのでとりまわしは正直楽で、かつパースは後からやればいいので高速です。このあたりのシンプルさが好きですね。
例えばQueryのコードはこんな感じになります。ハッシュキーを指定してレンジキーを1万件取得している感じです。
package main import ( "fmt" "encoding/json" ep "github.com/smugmug/godynamo/endpoint" query "github.com/smugmug/godynamo/endpoints/query" "github.com/smugmug/godynamo/conf" "github.com/smugmug/godynamo/conf_file" ) func main() { conf_file.Read() if conf.Vals.Initialized == false { panic("the conf.Vals global conf struct has not been initialized") } tn := "revaluate" q := query.NewQuery() { q.TableName = tn q.Select = ep.SELECT_ALL } k_v1 := "209963" var kc query.KeyCondition { kc.AttributeValueList = make([]ep.AttributeValue,1) kc.AttributeValueList[0] = ep.AttributeValue{N:k_v1} kc.ComparisonOperator = query.OP_EQ } q.Limit = 10000 q.KeyConditions["id"] = kc json,_ := json.MarshalIndent(q, "", "") fmt.Printf("JSON:%s\n",string(json)) body,code,err := q.EndpointReq() fmt.Printf("%v\n%v\n%v\n",body,code,err) }
レスポンスはJSONで帰ってくるので必要な部分だけをパースすればよいと思います。
2013/12/13 17:03:38 read conf from: /Users/shot6/.aws-config.json JSON:{ "AttributesToGet": null, "ConsistentRead": false, "ExclusiveStartKey": null, "IndexName": null, "KeyConditions": { "id": { "AttributeValueList": [ { "N": "209963" } ], "ComparisonOperator": "EQ" } }, "Limit": 10000, "ReturnConsumedCapacity": "NONE", "ScanIndexForward": true, "TableName": "revaluate", "Select": "ALL_ATTRIBUTES" } {"Count":17, "Items":[{"id":{"N":"209963"},"date":{"N":"1366807742203"},"user":{"S":"209963:231131"}},......]} 200 <nil>
まとめ
いかがでしたでしょうか?非常に簡単に使える感覚がわかってもらえたら嬉しいです。
私自身も試し始めたばかりですが、そこそこ使えているので、ぜひ試しにやってみてください。
また、DynamoDB自身もいよいよ待望のグローバルセカンダリインデックスが対応されましたので、こちらも試してみてください!
http://aws.typepad.com/aws/2013/12/now-available-global-secondary-indexes-for-amazon-dynamodb.html
re:Inventおすすめセッション3日目
最終日、早いものです。
では超個人的なお奨めを。
STG306:CloudStorage for App Developers
Dropboxの人の講演。これは楽しみですね。最近増えてきましたが、なかなか語られる事のないので期待値高めです。
9時からです。おそらくかなり開発者よりではないかと思われます。
BDT204 GraphLab: Large Scale Machine Learning on Graphs
こちらは機械学習のセッションですね。GraphLabsは名前は知っていたのですが中身はまだ詳しくないのでしっかり学習しようかなと。
MBL303:Gaming-Ops: Running High-Performance Ops for Mobile Gaming
ゲームの運用についての話。こちらはGree Internationalの方の講演です。
11時30分から。生々しい話が聞けるといいなあー
Unmeltable Infrastructure at Scale:Using Kafka, Storm, and ElasticSearch on AWS
Logglyのセッション。ログ収集のIngestion側の話ですね。第2世代のログ収集システムということで、色々具体的な話が聞けそうです。
DAT304:Mastering NoSQL:Advanced DynamoDB Design Patterns for ultra-high performance apps
DynamoDBを使ってスケールを出すためのパターンの話。DynamoDBをうまく使いたい人にはかなり好さそう!
re:Inventおすすめセッション
初日すっかり忘れてましたが、2日目から。なんだか聞かれることが多かったので。
CPN401:A Day in the Life of a Billion Packets
11時からで、もう始まってしまいますが、間に合う人がいればぜひ。
今ここにいます。
SPOT401:Leading the NoSQL Revolution
DynamoDBが何故できたか、どう違うのかなどの詳細が知りたい人はこちらを強くお勧めします。
ウチのメンバーとはスプリットしてこれをみています。
11時からです、
SPOT201 Managing the Pace of the Innovation:Behind the Scences of AWS
これは13時30から。AWSがどうやってイノベーションのペースを落とさずにやっているかをテクノロジーのトップがしゃべる、おそらくかなりレアな機会だと思います。
私はここに参加。
STG302-R Maximizing EC2 and EBS Disk Performance(repeat)
EBSのPIOPSおよびhi1/hs1のSSDを使うならば、このセッションは確実に見ておいた方が良いと思います。
初日に見たのですが相当おすすめです。13時30分から。
DAT306 How Amazon.com Is Leveraging Amazon Redshift
Redshiftに興味ある方はこちらは見てみると良いかと思います。相当面白いはず
3時からですね。
SPOT205 Why Scale Matters and How the Cloud is Really Different
おなじみのJames Hamilton先生のセッション。当然これは出ます。
4時15分から。
ARC301 Controlling the Flood:Massive Message Processing with SQS/DynamoDB
こちらはどうやって大量のメッセージ処理をさばくかですね。SQSとDynamoDBのアドバンスドな使い方が見れそうです。
5時30分からですね。
AWS CLIとjqを使った簡易管理ツール
AWSの新しいユニファイドCLIは最新バージョンである0.5.1でかなりサポートされたサービスが増えています。RDS, ELB, EMRなどの主力サービスはだいたいサポートされてきています。ところがどっこい、unified cliは基本的に返すレスポンスが基本JSONで返ってきます。なかなか人間様には見にくいので少々こねくりまわす必要があります。そこでJSONを簡単にパースしてくれるjqコマンドでうまいこと見たいものだけをとるのが望ましいです。
というわけで温泉ハッカソンで簡単なコンソール表示をEC2, ELB, RDSでやってみました。
EC2インスタンスのタイプ、状態、URLを見る
初級編。
aws ec2 describe-instances| jq '.reservationSet.instancesSet| .instanceType + " / " + .instanceState.name, .dnsName, "---------------------------------------------------------"'
結果はこんな感じ。
"m2.xlarge / stopped" "" "---------------------------------------------------------" "m1.medium / stopped" "" "---------------------------------------------------------" "m1.medium / stopped" "" "---------------------------------------------------------" "t1.micro / running" "ec2-54-249-133-52.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "m1.medium / running" "ec2-54-228-151-12.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "m1.medium / running" "ec2-54-228-155-116.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "t1.micro / running" "ec2-54-228-38-217.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "t1.micro / running" "ec2-54-229-153-38.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "t1.micro / running" "ec2-173-34-19-211.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "t1.micro / running" "ec2-46-54-220-111.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "t1.micro / running" "ec2-54-223-50-57.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------" "m1.small / running" "ec2-54-223-11-57.ap-northeast-1.compute.amazonaws.com" "---------------------------------------------------------"
ELBのざっくりとした概要を知る
少し慣れてきたのでELBではもうちょい細かく知りたい感じだったので、ぶら下がってるインスタンスと、ポートのフォワードとヘルスチェックも。
もうちょいやるなら、インスタンスの詳細も欲しいな。
aws elb describe-load-balancers| jq '.LoadBalancerDescriptions| .DNSName, "Instance", " " + .Instances.InstanceId, "AZ", " " + .AvailabilityZones, "Listen port config", " " + .ListenerDescriptions.Listener.Protocol + ":" + (.ListenerDescriptions.Listener.LoadBalancerPort|tostring) + "->" + .ListenerDescriptions.Listener.InstanceProtocol + ":" + (.ListenerDescriptions[].Listener.InstancePort|tostring), "Healthcheck", " " + .HealthCheck.Target, "====================================================================="'
さっくり力技。
"myfrontend-1709110016.ap-northeast-1.elb.amazonaws.com" "Instance" " i-0948680a" " i-0d48680e" " i-0f48680c" " i-6d4a6a6e" " i-c14868c2" " i-c74868c4" "AZ" " ap-northeast-1a" " ap-northeast-1b" " ap-northeast-1c" "Listen port config" " HTTP:80->HTTP:80" "Healthcheck" " HTTP:80/index.html" "=====================================================================" "yourapp442.ap-northeast-1.elb.amazonaws.com" "Instance" "AZ" " ap-northeast-1a" "Listen port config" " HTTP:80->HTTP:80" "Healthcheck" " HTTP:80/index.html" "====================================================================="
RDSでもざっくり概況を知る
RDSでは、エンジンやバージョン、ストレージだけでなく、マルチAZかどうか、リードレプリカなども。
aws rds describe-db-instances| jq '.DBInstances[]| .DBInstanceIdentifier + "(" + .Engine + " " + .EngineVersion + ", " + (.AllocatedStorage|tostring) + "GB)" + "[" + .DBInstanceStatus + "]", .AvailabilityZone, .Endpoint.Address + ":" + (.Endpoint.Port|tostring), if .MultiAZ == true then "MAZ" else "Single" end, if .ReadReplicaSourceDBInstanceIdentifier then "RR : " + .ReadReplicaSourceDBInstanceIdentifier else "" end, "======================================================================" '
結果はこんなん。
"hoge(mysql 5.5.8, 5GB)[available]" "ap-northeast-1c" "hoge.cb1tkvzxk6ev.ap-northeast-1.rds.amazonaws.com:3306" "MAZ" "" "======================================================================" "mydb(mysql 5.5.27, 5GB)[available]" "ap-northeast-1b" "mydb.cb1tkvzxk6ev.ap-northeast-1.rds.amazonaws.com:3306" "Single" "" "======================================================================" "mydb-rr(mysql 5.5.27, 5GB)[available]" "ap-northeast-1b" "mydb-rr.cb1tkvzxk6ev.ap-northeast-1.rds.amazonaws.com:3306" "Single" "RR : mydb" "======================================================================"
まあほとんどjqの練習になってしまいましたが、まあいいでしょう。
Asgardの更によいとこ
Asgard君、驚くべきことにきちんとデフォルトでAPIをサポートしています。
東京リージョンでのリソース一覧
東京リージョンのインスタンス一覧
curl http://asgardhost:8080/ap-northeast-1/instance/list.json
作成したアプリケーション"simpleaa"のクラスタリソース一覧
curl http://asgardhost:8080/ap-northeast-1/cluster/show/simpleapp.json
東京リージョンでのアプリケーション一覧
curl http://asgardhost:8080/ap-northeast-1/application/list.json
セキュリティグループなどの設定一覧
curl http://asgardhost:8080/ap-northeast-1/security/list.json
今回突っ込んではやらなかったですが、POSTを使ってリソースのコントロールをAsgard経由でプログラマブルにも可能です。
詳細は下記のURLです。
https://github.com/Netflix/asgard/wiki/REST-API
えっと、言葉がないですが、これでよくないですかw?