WebTekoに行ってきた

神戸で開催されたWeb勉強会、第一回WebTekoに参加させていただきました。



自分は、ExpressionEngineを紹介してきました。

ExpressionEngineの紹介~ありがちサイトを作ってみる~


プレゼンの最後にも追加しておきましたが、参考になりそうなサイトはこちら。

5人くらいのこじんまりした勉強会になるかなぁ、と思っていたら、20人以上集まってびっくりでした。とても楽しかったので、次も是非参加したいです。



PhotoShareサーバ勝手に改善計画

photo by rudolf_schuba

masuidriveの人から、ご意見聞かせて、と連絡が来たので、がんばって書いてみます。

masuidrive on rails – Webでの非同期処理を考えてみる [長い記事だけどコメント求む!]

Life is beautiful: マルチスレッド・プログラミングの落とし穴、その2

要するに、重くなってきたサービスに対して、むやみにサーバを増やさないでどうやってパフォーマンスを改善しましょう?全部の機能を同期的に処理する必要はないんじゃね?という話だと理解しました。

ボク程度の人の意見が必要というよりは、何かしら「あっ!」って気づくきっかけが欲しいのだろうから、遠慮せずにだらだらと。

「その程度のことはわかっとるわいっ!」という部分が多いと思いますが、そこはご容赦ください。

全部を非同期にすると…

中島さんの記事で

アクセス数が上がると、ユーザーがした投稿がデータベースに反映されるまでの時間がかかるようになるが、それが直接的におもてなしの低下に繋がることはない

と書いてあって「え~っ?」とまず思いました。

最近ブログのコメント欄なんかで、(スパムを防ぐために)管理者承認後に反映されます、というブログが増えているのですが、これは明らかに、おもてなしの低下につながっています。

単純な話で、自分が投稿したコメントがどう見えるかすぐに確認できない分、ユーザーさんはできあがりイメージを確認せずにその場を離れないといけないわけで。その場でできあがりを確認してから離れられるのに比べて不便なのは確かでしょう。

masuidriveの人の記事を見ると、「でも全部を非同期にする訳にはいかないし」って言われているので、そんなことは承知の上で、人間以外には非同期でいいんじゃね?という意図なのだとは思いますが。

あれ。でも全部非同期って、意外とありかもしれない。だって現にブログのコメントが非同期に反映されることについては、ユーザーの非難囂々という状態にはなっていなくて、それなりにみんなの同意が得られつつあるように見えます。

それだったら、投稿とか削除についても、「ちょっと時間がたってから反映されます」と一言表示されるだけで意外と許されるのかも。

エラーがあったらどうするか。photoshareの場合、幸い(?)ユーザー登録しないとコメントできないシステムみたいですので、

#iPhone持ってないので、詳細は知りませんw

それだったら、エラーになったらメールする、でもいいんじゃないでしょうか。

あと、よくしらんのですが、iPhone上のサービスって独自の(WEBじゃない)アプリが動いてるんですよね?であればそっちに表示させるとか。

同期と非同期をわける方法

ただ、そうやって非同期にすることが一般化すると何が起きるか。

なんだかんだいったって同期でスムーズに動いた方が嬉しいのは事実なので、そうすると、ユーザー数の少ない小規模サービス(技術者が片手間で作ったみたいなの)と、

リソースに余裕のある超大手サービス(YahooとかGoogleみたいな大手がはじめる新サービス)は同期で動いて、

photoshareのような、お金とサービスのバランスをとらないといけないところだけが非同期で機能を提供することになります。

これは痛い。競合に提供できるサービスを自分たちは提供できません、ということになるんだから、これは厳しい。

そうすると、やっぱり全面非同期化は厳しいんじゃないかな、と。

リアルタイムの情報を必要としないRSSとか、クローラーとかには非同期で返しつつ、ユーザーさんの要求はリアルタイムで返す必要があるんじゃないのかなぁ。

じゃあ、同期と非同期をどうやってわけるか。

 コントローラごとに実行するmongrelを振り分けるようなルールをリバースプロキシに書けばある程度回避できますが、どのように振り分けるのか決定するのは困難です。(Feedなら簡単だけどもっと難しいケースもあるよね)



 このように実はアクションごとに優先順位があります。Feedやランキングと言った部分は、反映が遅くてもほとんど問題になりませんが、自分の写真リストや写真そのものはすぐにアクセスできるようにしたいのです。

 現在のRailsはコントローラごとに優先順位を付けるような処理は苦手なので、これを行うには、なんらかの仕組みが必要になると思います。

問題は二パターンあって。

1.create,update,delete系の要求以外を別サーバに振り分けたら問題が解決する場合

2.それでは負荷対策として不十分で、create,update,delete系であっても一部は非同期にする必要がある場合

1.だったら問題は簡単で、railsで動作する同期動作サーバと、rsyncか何かで同期サーバの情報をミラーして提供する非同期サーバを用意して、リバースプロキシ部分の振り分けをがんばればいい話です。

sv_idea1.jpg

#十分難しいのですけどw まあお二人ならきっとできるでしょう。

問題は2.の時で。アーキテクチャはこんな感じかなぁ。非同期でいい機能はWEBサービスとして切り出して、フロントサーバはバックエンドサーバに投げちゃう。

sv_idea2.jpg

#当たり前ですけど、本当にサーバを4台以上用意せよ、という話ではなくて。物理的に同じサーバ上でフロントとバックエンドの機能が動いていたってかまわないです。負荷が耐えられるんだったら、ですけど。

バックエンドサーバに要求される機能はこんな感じ。

・要求を受け付けて、キューに入れる

・応答は、静的に生成してあるHTMLかなにかをそのまま返しちゃう

・適宜キューにある処理を実施して、静的HTMLをアップデートする

railsで実現するとすると、

・要求を受け付けたら、それをDBに入れて、生成済みのHTMLを返す。ここはrailsで普通に作れるはず。

・キューにある処理を実施する部分は…

キューの処理は、rakeタスクをcronとかで叩くようなぬるい処理で間に合うんだったらこんな苦労していないから、やっぱりぶんぶん回るサーバプロセスが必要になりますね。

ここでrailsいらないじゃん、という話になるわけか。

いかん。masuidriveの人と同じ結論になってしまった^^;

でも、ここまでをふまえると、やっぱり独自で作るのがいい、という話になると思います。要求とは無関係にぶんぶん回っている時点でもはやWEBサーバじゃないですから、それに適したアーキテクチャのものを書く必要があるんじゃないかなぁ。

なんだかまとまらん話ですが、思うがままに書いてみました。何かしらヒントになるような部分があれば幸いです。

不要なところは削除してやりたい放題できる『編集』

百式さんで「不要なところは削除して好きなところだけ印刷できる『Print What You Like』 」というのを紹介されていました。

不要なところは削除して好きなところだけ印刷できる『Print What You Like』 | 100SHIKI.COM


でも、それだったらもっと便利な方法を知っています。



editable.JPG
ボクのブラウザ、「編集」というのがお気に入りに入っています。百式を表示した状態でこれを選ぶと…

edit2.JPG
広告を消して….

edit3.JPG
右側が余るので、ぐいっと広げて…

もちろんこのまま印刷することができます。

ついでにこんないたずらも。

trick.JPG
百式で褒めていただきました!





やり方をご存じない方は続きをどうぞ。



なにをやったかというと、ブックマークレットという手法で、ページの内容を書き換え可能にしています。



編集


このリンクを右クリックして「お気に入りに追加」します。

alert.JPG
こういう警告が出ます。警告の内容は書いてある通りなので、mogya.comが信用できる方だけ「はい」を押してください。



先ほどのように、編集したいページに行ったら、そこでお気に入りから「編集」を選びます。

で、適当なところを選んで

select.JPG
DELETEキーを押すと、削除することができます。

grip.JPG
幅を変えたい時は、こうやってドラッグするとサイズが変わります。





もちろん、InternetExplorerだけでなく、FireFoxでも動きます。

おためしあれ☆


[ruby]gcalapiを使ってAuthSubログイン

photo by Martin LaBar

 昨日はすっごいがんばって自前でGoogleAuthSub認証を通すコードを書いたのですが。

今日、続きでカレンダーを扱おうとしたら、gcalapiに同じ内容のコードがあるのを発見してしまいました。

しかもこっちの方が明らかにきれいです。だったら最初からこっちでよかったんじゃん。

再発明しちゃった車輪をもてあそびつつ、gcalapiでAuthSub認証を使う方法を記述しておきます。

Googleの認証ページ用のURLを生成する

require ‘gcalapi’

require ‘googlecalendar/auth_sub_util’

@uri = GoogleCalendar::AuthSubUtil.build_request_url(

‘http://www.example.com/responce’,

‘http://www.google.com/calendar/feeds/’,

false, #use_secure

true #use_session

)

Googleから戻ってきたトークンをつかってセッショントークンをもらう

authsub_token = ”

one_time_token = params[:token]

session_token = GoogleCalendar::AuthSubUtil.exchange_session_token(one_time_token)

戻ってきたページのURLからワンタイムトークンを取り出すためにget_one_time_tokenというメソッドも用意されているのですが、railsであればparams[:token]でとる方がずっと早いですね。

セッショントークンをつかってカレンダーに予定を書き込む

require ‘gcalapi’

require ‘googlecalendar/auth_sub_util’

require ‘googlecalendar/service_auth_sub’

server = GoogleCalendar::ServiceAuthSub.new(session_token)

calendar = GoogleCalendar::Calendar.new(server, ‘http://www.google.com/calendar/feeds/default/private/full’)

event = calendar.create_event

event.st = Time.parse(“2008-09-19 20:00:01”)

event.en = Time.parse(“2008-09-19 22:00:01”)

event.title = “実験!”

event.desc = “こんにちはこんにちは! ”

event.save!

あとは基本的に、GoogleCalendar::Service の代わりにGoogleCalendar::ServiceAuthSubを使えばいいらしい。calendar_listが動かないのはしょうがないのかなぁ。

[ruby]GoogleAuthSubを使う

GoogleカレンダーやGoogleDocの情報は、ユーザーの同意の下に他のアプリケーションからも読み書きができるようにAPIが定義されています。

で、そういう時に、「ここにユーザー名とパスワードを入れてね」という危険なやり方じゃなくて、ちゃんとユーザーの同意をとりつつ、アプリケーションにはパスワードを渡さなくていいようにするための認証APIが、GoogleAuthSubです。

実際に使っている例としては、携帯電話でGoogleカレンダーを読み書きできるGoogle Calendar Mobile Gatewayが有名です。

で、そのGoogleAuthSubをRails(というかRuby)で実現するためのgoogle_auth_sub.rbというのを作ってみました。

手元では動いていますが、いろいろ自信がないところがあるので、動いたとか動かなかったとか、このコードはまずいだろ、とか、いろいろフィードバックいただけると嬉しいです。

google_auth_sub.rb

使い方

 GoogleAuthSubについての情報は、この辺にまとまっています。



流れを見るのであれば最後のサイトを見るのがわかりやすいと思います。

ここでは、google_auth_sub.rbを使うことを前提に説明してみます。

まず、Googleの認証ページ用のURLを生成して、ユーザーさんに踏んでいただきます。

google_auth_sub.rbでは、こんな感じで生成します。

@uri = GoogleAuthSub.getURLForAuthSubRequest(

“https://www.google.com/calendar/feeds/”,

“http://www.example.com/responce”

)

最初の引数はscope、Googleのどのサービスにアクセスしたいかを示すURLです。

二つ目は、next、ユーザーさんがGoogleのサイトでアクセスを許可した後戻ってくるページのURLです。三番目以下を使いたい人は、Googleのドキュメント見てください:-)

ともあれ、こうやって生成したURLをWEBサイトに表示して、ユーザーさんに踏んでいただきます。

そうするとユーザーさんはGoogleの認証ページに飛んで、

サイト xxxx は次のサービスで使用するため Google アカウントへのアクセスをリクエストしています。
というようなメッセージで、アプリケーションがGoogleカレンダーにアクセスすることへの確認を求められます。

ユーザーさんが「アクセスを許可」を押すと、ユーザーさんは先ほどnextで指定したURLに帰ってきます。この際、URIにToken=XXXX という形でトークンがついてきます。

これは一時トークンといって、一回しか使えませんが、Googleにお願いすると、当分使えるセッショントークンと交換してもらうことができます。

single_use_token = params[:token]

gas = GoogleAuthSub.new()

token = gas.getSessionToken(single_use_token)



セッショントークンがとれたら、あとはGoogleの各種APIにアクセスすることで、情報を取り出すことができます。このさい、セッショントークンをヘッダに入れてアクセスしないといけませんが

gas = GoogleAuthSub.new()

res = gas.googleHttpGet(‘https://www.google.com/calendar/feeds/default/private/full’,token)

とすることで、その辺をラップして情報をとってくることができるようになります。

とってきた情報はGCal namespace element referenceというフォーマットで格納されていますが、ここから先はSubAuthじゃなくて各アプリケーションの処理なので、google_auth_sub.rbが面倒見るのはここまでです。

そのほか

GoogleAuthSub.new()の最初の引数で、CA 証明書ファイルのパスを指定します。nilで省略した場合には、HTTPSのサーバ証明書をチェックしなくなるので、セキュリティ上まずいような気がしますが、ライブラリとしては一応動作します。

CA 証明書ファイルを渡すと、VERIFY_PEERモードで証明書を検証します。でも、これで安全なのかどうなのかあまり分かっていないので、このあたりつっこみいただけるととても嬉しいです。

GoogleAuthSub.new()の二番目の引数にloggerを渡すと、Googleとのやりとりを見ることができます。

getAuthSubTokenInfo()をつかうと、トークンが有効かどうかを確認することができます。セッショントークンであっても、ユーザーが有効性を取り消すことができるので、時々チェックした方がいいのかも。

ちなみに一時トークンをこの関数に渡して有効性をチェックすることもできますが、チェックしたことでトークンを使い終わってしまうので、あんまり役にも立ちません:-)

[ruby]Net::HTTPで無限に302 Movedを繰り返すトラブルにあった

まとめ

 res= http.get( url.path )

って書いていると、30x系のリダイレクトでパラメータ付きのURLを指示された時にはまります。url.request_uriを使いましょう。


内容

Google Calendar APIなんかを使ってWEBサービスからデータをとってくる時、net/httpを使うことはよくあるかと思います。

とってきたデータが30x系のリダイレクトであった場合まで考慮に入れたとすると、こんなコードになりますよね?

 max_retry_count = 5

 max_retry_count.times {|retry_count|

  http = Net::HTTP.new(url.host, url.port)

  http.use_ssl = true if (443==url.port)

  http.ca_file = ‘/var/hogehoge/www.google.com.cer’

  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  http.verify_depth = 5

  res= http.get( url.path )

  

  case res

  when Net::HTTPSuccess

   break

  when Net::HTTPRedirection

   url = URI.parse(res[‘Location’])

   next

  else

   break

  end

 }

 resを使ってあれこれ。

 ところが、これでGoogleカレンダーのデータをとってこようとしたらひどい目に遭います。とりあえずとってくると…

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=m6Kxxxx

想定の範囲内の302 Moved Temporarilyなので、プログラムはいわれたとおりにリトライして、データをとってきます。

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=1rJxxxx

え?と思いつつ、プログラムはいわれたとおりにリトライして、データをとってきます。

Moved Temporarily

The document has moved https://www.google.com/xxxx?gsessionid=Cmvxxxx

….たらい回し状態です。いっこうに目的のデータに行き着きません。

やり方が間違っているのかなぁ、それともドキュメントに読み落としがあるかなぁ、とさんざん悩んだ末、やっと原因に気がつきました。

rubyのURIライブラリは、URIを渡すと部品に分解してくれます。host/port/path/query….

そこで、http.get( url.path )を使うと? queryとして指示されている「?gsessionid=Cmvxxxx」が吹っ飛んじゃいますよね。

Googleさんから見ると、

・”xxxx”にクライアントが来たので、”xxxx?gsessionid=….”にリダイレクトを指示しました。

・なぜかクライアントはgsessionidを外して、再び”xxxx”にアクセスしてきました

・仕方がない(というか、別クライアントに見えるので)、”xxxx?gsessionid=….”にリダイレクトを指示しました。

・なぜかクライアントはgsessionidを外して”xxxx”にアクセスしてきたので….

ということになっていたわけです。

….だって みんな“http.get( url.path )” って書くじゃーん!

 res= http.get( url.request_uri )

って書くのがいいみたいです。

puttyの設定をiniファイルに変換する

 Windowsからlinuxサーバにアクセスする日本人の標準ツールPuTTY ごった煮版は、設定をレジストリじゃなくてiniファイルに保存することができます。

 今まで設定をレジストリに保存していた人は、ゑBLOG: PuTTYごった煮版 レジストリINIファイルコンバータを使うと設定を変換することができます。



 ところがこれが、どうもうまく動かない。スクリプトは動作するのだけれど、出力されたputty.iniには

[Generic]

UseIniFile=1

しか書かれていない、ということになって困りました。



コチョコチョしてみたら原因が分かったので、困った人向けのメモ。



原因:

 WindowsXPのregeditは、utf16(16ビット単位で文字を扱うコード)でファイルに書き出すみたいです。

reg2ini.pl(というか、ActivePerlとかその辺の処理系)はutf8を前提としているので、これだと正規表現がまったくマッチしなくなります。



ということで、出力された.regファイルを一度秀丸エディタか何かで開いて、utf8に変換してからreg2ini.plを使うとうまく動作します。



追記

regeditでエクスポートするときに「Win9x/NT4 登録ファイル」を選ぶという手もあるらしいです。

regedit.JPG

AmazonEC2&S3を使ってみた

 Amazonが運営するサーバ仮想化技術であるAmazonEC2&S3を使ってみました。



やり方とかは増井さんがとっくに説明されていますので、

はじめてのAmazon EC2&S3 ~これからの新サービスの公開の形~

ここでは使ってみた感想とかを。

意外といける

 聞き慣れない単語が多かったので、これはどうも今までの技術とは別系統っぽいなぁ、

はやらなかったときが悲惨だからもう少し様子見、とか思って先送りしてきたのですが^^;

やってみた結果、そんなに変な技術ではなくて、自分の知っている技術の延長線上にあるシステムだと分かりました。

 vmwareを使ってWindowsの上でlinuxを走らせたことのある方は分かると思うのですが、vmwareが動いてしまえば、

その下のホストOSは、Windowsだろうとlinuxだろうと、あまり関係がなくなってしまいます。

Windowsで作った仮想マシンイメージをlinuxで動いているvmwareに持って行ってもそのまま動作しますよね。

この考え方を延長すると、ホストは正体不明のOSであってもかまわないわけで。

正体不明のOSの上に何台でも仮想マシンを走らせることができるようにしたのが、AmazonEC2です。

なので、AmazonEC2の上でゲストOSが動いてしまえば、あとは普通のlinuxと同じように使うことができます。

マシンイメージが便利

 vmwareでは、新品の仮想PCをくみ上げてそこに自分でOSを入れるのが基本でしたが、AmazonEC2では、すでにあるマシンイメージ(AMI)を使うのが基本です。

RedhatやCentOS,Ubuntuなどの各種linuxイメージが公開されているので、このコピーを使っていきなりマシンを起動させることができます。

amis.JPG


で、このマシンイメージがなにげに便利です。

いままで、CentOSをインストールしたら、その後Rubyを入れて、RubyGemも入れなくちゃ、RubyGemはyumにないから自分でrpm作らないとね、そのためにはrpmbuild入れて…

というような作業が必要だったのですが。rightScaleさんが公開しているCentOSのイメージでは、RubyはもちろんGemもsqliteもsubvesionも、全部すでにインストールされていました。

これは楽ちん。



もちろんこれは、自分の希望と異なるものが入っていたら「余計なことすなっ!」ですが、AmazonEC2を借りてその上でWebサービスを作ろうという人にはおおむね妥当なソフトがインストールされていて、これは便利、と思いました。

自動拡張してくれるわけじゃない

 「AmazonEC2は負荷に応じた拡張が容易」といわれていたので、負荷が高くなったら勝手にCPUの性能が上がったり、ディスクサイズが自動的に拡大されたりするサービスなのかな、と思っていたのです。

そんな怪しいマシンだから、きっと普通のOSは動かないんだろうな、と思って警戒していたのですが。

 べつにそんな怖いサービスではありません。仮想マシンを動かすことができますが、それだけです。ただ、サーバの増設が必要だ!となったときに、新しいマシンを買ってきたり、そこにOSを入れたりしなくても、AMIから同じ構成のマシンを何台でも立ち上げることができるので、拡張が便利、とそういうことです。

 なので、スケーラビリティを考えないサービスを適当に作っても何とかしてくれるわけじゃなくて、ちゃんとスケーラブルになるようにサービスを設計しておく必要があります。

はじめてのAmazon EC2&S3 ~これからの新サービスの公開の形~:第4回 自分用のイメージファイル(AMI)を作ろう|gihyo.jp … 技術評論社




 なんにも考えずにサーバが勝手に何とかしてくれないかな?とかずぼらなことを考える人は、グリッドホスティングみたいなサービスがオススメです。



#まあこれはこれでいろいろ難しいのですけどね。


Re:やっぱり京都にITって無理なのか

無理なわけがない。

ITの発展で場所とかに縛られずに色んなことが出来るようになって、地方が活性化するというようなイメージがむかし有ったんだけど、現状どうみても東京とそれ以外の地方での温度差というか格差というかいろんなモノが違う感じですね。こんなことでは僕が沖縄で赤瓦の家でだらだらネットで仕事してソーキそば食べてちょっと昼寝してだらだらネットで仕事してソーキそば食べる生活はいつの日になるんでしょうか。

やっぱり京都にITって無理なのか – 妖精ホルモン



 できるに決まってます。だって現に今ボクがやってますし、GANCHIKU.comの大野さん(ならべて.com作った人)もやってます。大野さんにいたっては、国内でうけた仕事を海外放浪しながら開発しています。

お客さんが不安にさえならなかったら、WEBサイトなんて別にどこで作ったって一緒です。仕事さえとれたら、あとはどこにいても大丈夫。



もっとも、自分の今のメイン営業ルートは東京にいた頃の知り合いですし、大野さんだって、日本のエージェントさんに仕事とってきていただいているみたいですけど。

でもってどっちもそんな生活はここ一年くらいしかやっていないので、持続可能である保証はないのですけどw



でもきっと大丈夫。うまく説明できないけれど、きっと大丈夫。右足が沈む前に左足を踏み出せば、きっと大丈夫なはずです。