Shogo's Blog

Sep 24, 2013 - 1 minute read - perl yapcasia

YAPCへ行ってきた(二日目)

前回のポストにつづいてYAPC二日目。 聞いたトークの内容を簡単にメモ。 Perl で書く結合テスト 前半はSWET(Software Engineer in Test), TE(Test Engineer)といった業種の話。 後半はテスト手法の分類(誰がする?テストの対象は?方法は?目的は?)について。 スライドはこちら→[Perlで書く結合テスト(]http://ikasama.hateblo.jp/entry/2013/09/22/234521) これからのPerlプロダクトのかたち 世界一高速な処理系を目指して開発中のgperlと、 その過程でできたツールの紹介。 PerlをLLVMにコンパイルすることがで、高速動作するらしい。 恐ろしい・・・。 Perlは文脈によってトークンの意味が変わってしまうから、トークナイザーを作るのに苦労したとのこと。 (例えば、hoge * fuga とあったときに、*が掛け算なのかブロブなのかわからない) コンパイルの高速化のために文法を工夫しているKuinを見習って欲しいですね。 Emacs実践入門 Perl編 typester先生によるEmacs入門。 PerlCompletion とか helm とか便利そう。 あんまりEmacsカスタマイズできていないので、今度いろいろ入れて遊んでみよう。 Perlでレコメンデーション 登壇者はJubatusのPerlモジュールを書いたりしているらしい。 Jubatus に触ってみようと考え始めてからどれだけの月日が経っただろう・・・ そのうち触ってみます。そのうち。 中規模チャットサービスの運用事例 handlename先生のLobi運用のお話。 今日もcronのメールが迷惑メールフィルタによって闇に葬りさられる悲しいことがあったので、 cronの結果をIRCに飛ばすのとか参考にして何とかしたい。 PhantomJSによる多岐にわたる広告枠の確実な表示テスト 最近の広告はJavascriptを使った遅延読み込みをするので、 ちゃんと表示されるかを静的に判断することができない。 そこで PhantomJS を使ってテストするお話。 フルテストも50msで終わらせたい 〜 FreakOutの取り組み 〜 さすがにフルテストは50msで終わりません。 Ukigumoを使って複数台のサーバでテストを分散実行する取り組みを紹介。 スライド→http://yapcasia.org/2013/talk/show/767463b0-d8fd-11e2-971a-72936aeab6a4 LT 前日にアイデアだけLTで紹介したHTTP::Body::Builderが、別の人の手によって実現されていたのには驚いた。 YAPC恐ろしいところだ・・・。 HUB 懇親会参加しない組だったので、 @sasaplus1 さん, @kazuph さん, @aokcub とHUBで飲み会。 なぜ学内にHUBがあるんだ・・・? NDS勢やNiigata.pm勢、あと何故かスタッフになっていた @jewel_x12 とも会えて楽しかったです!

Sep 20, 2013 - 1 minute read - perl yapcasia

YAPCへ行ってきた(一日目)

YAPCの一日目に行ってきたよ。 いまどきのカジュアルなデータベース関連開発 Songmu先生のセッション。 DBIx::Schema::DSL とか GitDDL::Migrator とかの説明や、 DBのスキーマ設計、Redisの紹介なんかがありました。 自分もMySQLやRedisを触る機会が増えて、DB周りでつらい思いをしたことが何度かあるので (外部キー制約でデッドロック起こしたり、無駄なインデックスを必死に削除したり・・・) 大いに参考に参考にさせていただきます。 スライドはこちらから→いまどきのカジュアルなデータベース関連開発 学術分野におけるPerlの活用例 Perlを使ったアンケートの結果と、PerCUDAの紹介。 GPGPUをPerlのコードで実現しようとのお話。 大規模Perl初心者研修を支える技術 :DeNAさんが行った研修の紹介です。 顔覚えられない、 研修生の状況把握が大変、 信頼関係を作るのが大変 といった問題をどうやって解決したかについてのお話がありました。 トークの中で紹介された本何冊か持っているけど、全然読んでない・・・。 というか研修生みんなこれ読んだんですか。 スライドはこちらから→大規模Perl初心者研修を支える技術 mod_perlの展望とApacheの超絶技巧 最近僕の周辺ではあまり Apache の話題を聞かなくなってしまいましたね。 しかし、その知名度の高さからか、他のオープンソースのプロダクトはダメでも、 Apache はOKという案件があるらしい。 「Apache使いました!」っていうために、mod_perl で代替品を作ろう、というお話。 おそろしい・・・。 スライドはこちらから→mod_perlの展望とApacheの超絶技巧 0から学んだポストモダンPerl ルーティングとかORMはWAFにはいらない。 blessで十分!これぞ、ポスト・モダンPerl!とのことでした。 僕もフルスタックのフレームワークより、 各機能が別になっているほうが好きですね。 (でもblessよりはクラスを扱うためのライブラリ使ったほうがよいと思う) まあ、あんまり大規模なWebアプリ作ったこと無いので、 実際に作ってみると意見が変わるかもしれませんが。 スライドはこちらから→0から学んだポストモダンPerl Dist::Zilla 英語のトークに紛れ込んでしまい、正直良くわからなかった。 英語能力全く向上していない。 モジュールを作成、テスト、アップロード等の管理をするためのプログラムらしい。 Redis::Namespace でつらい思いをしたので、 次モジュールを作りたくなったら試してみよう。 perl な web application のためのテスト情報 スライドの順番が正しいか、今使っているのは本当にマイクなのかのテストが必要ですね! 335さん自らテストの必要性を教えてくれました。 「なぜテストが必要か」言葉では語らず行動で示す335さんかっこいい。 Test::Deep は Redis::Namespace のテストでも一部使っていますが、これ便利ですね。 Test::More の is_deeply はちょっと不便だと思っていたので、今後も使っていこうと思います。

Sep 14, 2013 - 1 minute read - perl redis

Redis::NamespaceのPerl版書いた

Redis のキーにプリフィックスつけるの面倒だなー自動的につけてくれないかなーと思い、 調べてみると Ruby に Redis-Namespace というものがあるらしい。 だけども、Perl では探しても見つからなかったので書いてみた。 レポジトリはこちら→Redis::Namespace 使い方 インターフェースは Perl Redis と一緒。 コマンドのキー名に当たる部分に、自動的にプレフィックスをつけてくれる。 use Redis; use Redis::Namespace; my $redis = Redis->new; my $ns = Redis::Namespace(redis => $redis, namespace => 'fugu'); $ns->set('foo', 'bar'); # $redis->set('fugu:foo', 'bar'); my $foo = $ns->get('foo'); # my $foo = $redis->get('fugu:foo'); 大体のコマンドには対応したつもり。 別のプレフィックスがついたキーには基本的にアクセスできなくなるので、 キー名の管理が少し楽になると思います。 でも、flushdb とか flushall すると全部消えるので気をつけてね!

Aug 24, 2013 - 2 minute read - perl redis

Perl の Redis ライブラリを調べた

最近Redis を使ったコードを書くようになったのですが、 キー名を毎回指定するのがだるいです。 Ruby には redis-objects というのがあって、 Redisのキーをオブジェクトとして扱うことができるようです。 きっと、Perl にも似たようなのあるだろ、って思って調べてみました。 ほしいもの 低レベルなRedisのライブラリはたいていメソッドとRedisのコマンドが一対一対応していて、 次のようなコードになると思います。 $redis->set('key-name', 'piyopiyo'); $redis->get('key_name'); でも、Redisに何か操作をしたいわけじゃなくて、 Redisのキーに対して操作をしたいので、 次のように書けるべきだと思うんです。 my $key = key($redis, 'key-name'); $key->set('piyopiyo'); $key->get(); Redis::Hash, Redis::List Redis::Hashと Redis::Listは Perlのハッシュや配列と同じ操作で Redis にアクセスできるようにするライブラリ。 use utf8; use warnings; use strict; use 5.014; use Redis::Hash; tie my %my_hash, 'Redis::Hash', 'hash_prefix', (server => 'localhost:6379'); # set hash_prefix:hogehoge piyopiyo # set hash_prefix:fugafuga fugufugu $my_hash{hogehoge} = 'piyopiyo'; $my_hash{fugafuga} = 'fugufugu'; # get hash_prefix:hogehoge piyopiyo say $my_hash{hogehoge}; # piyopiyo # keys hash_prefix:* say join ',', keys %my_hash; #fugafuga,hogehoge # keys hash_prefix:* # get hash_prefix:fugafuga # get hash_prefix:hogehoge say join ',', values %my_hash; #fugufugu,piyopiyo # del hash_prefix:hogehoge delete $my_hash{hogehoge}; tie とかよくわかない。 Perl の黒魔術を見た気がしました。

Jul 13, 2013 - 3 minute read - perl

ランダム抽出アルゴリズムについて考える

数日前に社内IRCで「スマートな非復元抽出の方法はないか」と話題になったので、 ランダムサンプリングのアルゴリズムについて調べたり考えたりしてみた。 復元抽出 非復元抽出の手法って調べてもなかなか出てこない・・・。 ひとまず、復元抽出についてまとめてみましょう。 線形検索 一番簡単な実装方法。 どの区間に入るかを線形検索して求める。 選択肢の個数nとすると計算量はO(n)。 use strict; use warnings; use List::Util qw(sum); sub linear_search_method { my $weights = shift; my $num = shift; my $sum = sum @$weights; my $length = @$weights; my @a; for (1..$num) { my $r = rand($sum); for my $i(0..$length-1) { $r -= $weights->[$i]; if($r < 0) { push @a, $i; last; } } } return \@a; } print join ', ', @{linear_search_method [1,2,3], 100}; バイナリサーチ あらかじめ累積分布表を作っておき、どの区間に入るかをバイナリサーチ。 準備にO(n)、選択に O(log n)かかる。

May 15, 2013 - 2 minute read - chrome perl

Google Cloud Messaging for Chrome を試してみた

少し前にGoogle Cloud Messaging for Chrome が発表されました。 Android向けに提供されていた Push 通信の仕組みである GCM の Chrome 版です。 ちょうど GCM for Android に触っていたところだったので、 for Chrome のほうも試してみることにしました。 拡張機能の登録 公式ページの説明にしたがって、 APIを使えるようにします。 GCMはOAuth2.0で認証を行うので、 クライアントIDを作る Refresh Token を作る という2ステップが必要。 クライアントIDを作る まず、新しい OAuth2.0 のアプリを作成。 拡張機能をアップロードする予定のGoogleアカウントで以下の作業して Client IDを作ります。 Google APIs Console にログインする ** Create… ** メニューから新しいプロジェクトを作成 “Services” を開いて ** Google Cloud Messaging for Chrome API ** を有効化 “API Access” を開いて ** Create an OAuth 2.0 cliend ID… ** というボタンをクリック branding information を適当に入力 “Application Type” という項目の “Web application” を選択 “Create client ID”!! Client ID と Client Secret が表示されるのでメモしておきましょう。

May 12, 2013 - 1 minute read - RaspberryPi

RaspberryPiからメールを送る

RaspberryPi に cron を仕込んで定期実行をやってみようと考えました。 cron の設定自体は crontab -e コマンドを実行すれば簡単にできます。 ただ、これだけだとちゃんと動いているか少し心配なので、 エラーが起きた時に何か通知して欲しい。 普通なら設定ファイルに MAILTO=hogehoge@example.com と書いておくと メールが送られるはずなのですが、 メールサーバが動いてないのでうまくいかない・・・。 そういうわけで、RaspberryPiからメールを送るための設定をしたのでメモ。 MTAをインストールする Raspberry Pi には標準でMTA(Message Transfer Agent)が入ってないようなのでインストール。 今回はPostfixを採用 sudo apt-get install postfix 最初、Sendmailも試してみたんだけど、送信者マスカレードがなぜかうまく行かなったので断念。 後述するように、この設定がないとスパムフィルタに引っかかってしまうのです。 プロバイダのSMTPにリレーしてもらう 実際にメールを送りには以下の条件を満たす必要があるようです。 送信元のドメインを引ける 固定IPからのアクセス 固定IPなんて自前で持ってないし、 cron からのメールは送信元が pi@raspberrypi になってしまいドメインを引けません。 そのためそのままではスパムメールとして扱われてしまい、メールが届きません。 そこで、プロバイダが提供しているSMTPサーバにメールをリレーしてもらいます。 /etc/postfix/main.cfに以下の行を追加します。 sender_canonical_maps = regexp:/etc/postfix/canonical relayhost = [smtp.example.com]:587 smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/relay_password smtp_sasl_security_options = noanonymous プロバイダにリレーしてもらうには SMTP-Auth で認証する必要があるので、 ユーザ名とパスワードを設定しておきます。 smtp.example.com hogehoge:your-password postmapコマンドを使って、Postfixから扱える形式に変換します。 $ postmap hash:/etc/postfix/relay_password さらに、エンベロープのFromがプロバイダから提供されたメールアドレスでないと メールをリレーしてくれないので、 すべてのメールのFromをすべて書き換えるよう設定します。

May 12, 2013 - 1 minute read - RaspberryPi Python

RaspberryPiでhttps通信が失敗するのを何とかする

RaspberryPiをネットつないでみたので、PythonからいろんなURLを叩いて遊んでいたんだけど、 一部のhttps通信が Connection Timed Out で失敗しちゃう。 プログラムの問題かと思ったけど、curlで叩いてもやっぱりタイムアウト。 Macで全く同じ事をするとうまくいく・・・。 いろいろ調べて、何とかしてみたお話。 原因 接続先がTLSv1にしか対応していないのにSSLv3でアクセスしようとしていたことが問題だったらしい。 明示的にTLSv1を使うように指定して curl を叩いてみるとうまくいった。 $ curl --tlsv3 https://hogehoge なぜRaspberryPiではダメで Macでは成功するのか、という根本的な原因はよくわからなかった。 SSLv3に対応していないなら自動的にフォールバックしてくれてもよさそうなものだけど、 なぜうまく行かないんだろう・・・? Pythonでの対処 PythonでもTLSv3を使えばうまくいくはずなんだけど、 暗号化方式を指定するオプションは見当たらない(2.7での話)。 どうやら標準ライブラリのファイルを直接書き換えるか、 実行時に中身を入れ替えるかしないとできないみたいだ。 この問題普通のUbuntuでも起こるらしく、 そのフォーラムで置き換えコードを見つけた。 import httplib from httplib import HTTPConnection, HTTPS_PORT import ssl class HTTPSConnection(HTTPConnection): "This class allows communication via SSL." default_port = HTTPS_PORT def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None): HTTPConnection.__init__(self, host, port, strict, timeout, source_address) self.key_file = key_file self.cert_file = cert_file def connect(self): "Connect to a host on a given (SSL) port.

May 9, 2013 - 1 minute read - Python Twitter

tweepyでApplication-only authenticationしてみた

Twitter の API リファレンスを久しぶりに見たら、 Application-only authenticationとかいうのを発見。 特定のユーザと関連付けられない代わりに、普通に認証するより制限が緩いみたい。 3月に追加されてたらしい。 知らなかった・・・。 最近API叩いてなかったからな・・・。 便利そうなので、Python用のTwitterライブラリであるTweepyから使ってみた。 AuthHandler Tweepy用のAuthHandler。 認証部分は TwitterのApplication-only authenticationを試してみた のページからほぼコピペ。 import tweepy import urllib import urllib2 import base64 import json class AppAuthHandler(tweepy.auth.AuthHandler): TOKEN_URL = 'https://api.twitter.com/oauth2/token' def __init__(self, consumer_key, consumer_secret): token_credential = urllib.quote(consumer_key) + ':' + urllib.quote(consumer_secret) credential = base64.b64encode(token_credential) value = {'grant_type': 'client_credentials'} data = urllib.urlencode(value) req = urllib2.Request(self.TOKEN_URL) req.add_header('Authorization', 'Basic ' + credential) req.add_header('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8') response = urllib2.urlopen(req, data) json_response = json.loads(response.read()) self.

Apr 13, 2013 - 1 minute read -

社内ISUCONに参加した

先日、社内 ISUCON(良い感じにスピードアップコンテスト) に参加してきました。 Livedoorで開催されたISUCONのミニ版で、 Webアプリをひたすら高速化するコンテストです。 高速化の対象はNoPaste。 テキストを共有するWebアプリです。 テキストの投稿・投稿の閲覧・投稿にスターをつける の3つの動作ができる簡単なアプリです。 新卒 vs 先輩ということで、それぞれ4チームが参戦。 チームは二人一組で僕は @Maco_Tasu くんと一緒でした。 @Maco_Tasuくんのブログも参照。 Recent Posts 生成クエリの高速化 高速化前のアプリのベンチマークの結果、スコアは77(≒1分あたりの捌いたリクエスト数)。 何も考えずにデータベースの全行を舐めるクエリを書いていたので、まあ、妥当なスコアですね。 重いのはサイドバーに表示される Recent Posts。 Recent Posts は表示回数が多く、 複数の行、複数のテーブルへのアクセスが発生するため、 きっとここがボトルネックになるだろうと予測してました。 そこで最初にこの部分を解決することにしました。 とりあえずインデックスを張る クエリを修正してアクセスする行を最小化 スターのカウントした結果をテーブルに格納 オリジナルのデータベース構成では、スターした回数だけ行が増えてました 必要なのは投稿ごとのスター数なので、独立したテーブルに この時点で早くも重大なバグを組み込んでしまったことに、この時はまだ気がついていなかった・・・ nginxによる静的ファイル配信 僕がクエリをいじっている間、@Maco_Tasuくんには サーバの設定をお願いしました。 ログの様子を眺めてみると、cssとかjsとかの静的ファイルが結構な量ありました。 最初のスクリプトでは静的ファイルの配信もアプリでやってたので、 これをnginxを使って配信するように変更。 その他のリクエストはリバースプロキシを設定してアプリに投げます。 Starlet と Server::Starter リバースプロキシを設定する際にアプリの起動スクリプトを編集する必要があったので、 ついでに起動時の設定を色々変更。 PSGI実行のStarletというのが速いと聞いてこれを採用。 Starlet使い方調べてたら、Server::Starterを使った例が出てきたので一緒にインストール。 ワーカーの数の数は適当に10個にしました。 ここで2回目のベンチマークを実行。 スコア1300程度で、その時点のトップ! SSIを使ったサイドバーの埋め込み お昼を挟んで、さらなる高速化を目指します。 topコマンドを眺めているとPerlで作ったアプリの負荷が大きい。 ほとんどテンプレートエンジンを呼び出しているだけの単純なコードなので、 ここを高速化するのは面倒くさい。 そこで、前段のnginxでキャッシュする作戦を採用することにしました。 もっともキャッシュが有効なのはサイドバーだろうと予想。 クエリの最適化をしたとは言え、サイドバーには100件程度の投稿が表示されるので、 クエリ実行にもレンダリングにも時間がかかるはず。 さらにすべてのページでサイドバーは共有できるので、大幅な高速化が期待できるはずです。 過去のISUCONの記事にSSI(Server Side Include)を使った例があったのを思い出し、 これを使ってサイドバーのみキャッシュ、nginx内でサイドバーを埋め込むように。 僕が SSIのタグ埋め込み、 @Maco_Tasu くんにnginxのキャッシュ設定を行ってもらうという役割分担で作業を再開しました。