素のfluent-plugin-elasticsearch使ってkibanaで描画するだけではちょっと使うの難しい
"実践"としてかっちょいい監視ツールを利用したい
かっちょいい監視ツールにあこがれて fluentd - elasticsearch - kibana を使ってみたので実際に使えるようになるまでのポイントを幾つか。
そんなtype想定してない
fluent-plugin-elasticsearchだと読み込んだログを基本的に全部文字列として構造化してしまうので、各所最適化されたmappingができない。type:integerで入って欲しいが、文字列なのでtype:stringでmappingされたりする。そこでplugin自体をカスタマイズして数値型としてmappingすると、今度はtype:longでmappingされてしまう。type:ipとかを利用したくても同様の結果になる。
勝手にexpireして欲しい
ログ監視なので一定期間過ぎたindexは自動で消えてくれるといいんだけど、なかなかそういう設定ができない。なのでelasticsearchのTTL機能などを使おうとする。しかしfluent-plugin-elasticsearchはmappingが自動的にされるので各documentやindexに対してTTLを設定することができない。また、設定してもdocumentにTTLに設定してもindexのmappingを_ttl:{enabled:true}にしなければTTLは動かない。
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-ttl-field.html
加えて、このelasticsearchのTTL機能についてはパフォーマンスが落ちるので好ましくないとのことが公式で以下に載っている。なのでcronで定期的にindexを削除するといいよ、という話。結局cron頼みになるのかな?
http://www.elasticsearch.org/tutorials/using-elasticsearch-for-logs/
検索パフォーマンス
analyzerちゃんと設定しないといけませんよね?
documentを構成するデータに合わせたanalyzerを設定できてる?
elasticsaerch自体のパフォーマンス
デフォルト設定ではそもそも性能に限界がある。
その辺りのパフォーマンスチューニングはデータストアとして切っても切れないので、
利用用途と現状に合わせたチューニングが必要。
template機能
fluentdでデータを投げる前にちゃんとデータ構造を定義して明示的に最適化されたmappingでelasticsaerchにdocumentを保持するべき。analyzerも設定しなければならない。そのためにtemplate機能。これを設定すると指定の条件のindexに対して設定したtemplateをベースにdocumentを生成保存してくれる。結局全く何も考慮せずにデータを突っ込むといのは危険ということ。
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-templates.html
まとめ
素のプラグインでlogを収集して素で突っ込むだけでは結局使えない。
要は実践で使うにはやはり色々考慮しないといけない。まる。
特にmappingはきっちりやること。そのためのtemplate。
analysisとかtokenizerととelasticsaerch自体のパフォーマンスチューニングはまた今度。
apacheでwordpressとpassenger/railsを共存させる
railsをルートとしてwordpressを入れ込む形での共存はよく見かけたけども逆のパターン(wordpressの下部にrailsを入れ込む)がなかなか見つからなかったのでメモっとく。
1.
railsのプロジェクトをapacheのユーザー権限が届く位置に設置する
たとえばapacheユーザがuser_1だった場合、/home/user_2/*に置いても参照されない
なので/home/user_1/*とかに置く
2.
DocumentRoot(ここでは/home/user_1/localhost)配下にrailsプロジェクト(publicディレクトリ)のシンボリックリンクを貼る
ln -s /home/user_1/rails/public /home/user_1/localhost/utils
3.
あとはapacheのconfig設定。
ここではvconf.d/hoge.confのような例を示す
# railsの基本設定 RackEnv production RackBaseURI /utils # wordpress <VirtualHost *:8081> ServerName localhost ServerAdmin root@localhost DocumentRoot /home/user_1/hogehoge.public_html ErrorLog /var/log/httpd/localhost/error_log CustomLog /var/log/httpd/localhost/access_log combined ErrorDocument 404 /404.html DirectoryIndex index.php # wordpress内はpassengerを動かさない PassengerEnabled off PassengerResolveSymlinksInDocumentRoot On </VirtualHost> # wordpressのディレクトリディレクティブ <Directory "/home/user_1/localhost"> Options FollowSymLinks MultiViews ExecCGI AllowOverride All Order allow,deny Allow from all </Directory> # railsのディレクトリディレクティブ <Directory "/home/user_1/localhost/utils"> PassengerEnabled on Options FollowSymLinks -MultiViews AllowOverride All Order allow,deny Allow from all # URI書き換えによってrailsディレクトリ以下はrailsのルーティングに入るようにする RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !utils RewriteRule . /index.php [L] </Directory>
Arrayを__proto__で機能拡張したときのfor inの注意点
昔書いてたメモ。
たとえばArrayオブジェクトを以下のように拡張する。
すると普通にArrayオブジェクトからemptyメソッドが使えるようになる。
Array.prototype.__proto__ ={ empty : function(){return "emptyが呼ばれたよ!";} } var ary = []; alert(ary.empty()); //"emptyが呼ばれたよ!"
そしてfor inをしたときには以下のようになる。
Array.prototype.__proto__ ={ empty : function(){return "emptyが呼ばれたよ!";} } var ary = ["1","2","3"]; var str = ""; alert(ary.length); // "3"←3つの値を配列として保持させたのでlengthは勿論3となる for(var i in ary){ str += i; } alert(str); // "012empty"←lengthが3なので"012"となることを期待したが…
このようにlengthは初期化した時の3のままなのに、
何故か4つめが存在していてしかもその4つめが拡張したemptyとなっている。
これはjavascriptの以下の性質の為と思われる。
var obj ={ test0 : "", test1 : function(){}, test2 : function(){} } var str=""; for(var i in obj){ str+=i; } alert(str); // "test0test1test2"←オブジェクトも連想配列として認識する為にobj配下にあるプロパティを呼んでいる。
このようにjavascriptのfor in文はオブジェクト配下のプロパティすべてを走査するため、
__proto__による拡張したメソッドまでループの中で呼び出されてしまう。
まあfor..inは連想配列に対して行うということですね。
GCMまでの流れ〜GoogleDevelopersConsoleの設定編〜
この記事は2014年1月27日時点の設定です。
GCM(Google Cloud Messaging)を利用するにあたりGCM側の設定をしなければなりません。
で、C2DMからGCMに変わり、API ConsoleからGoogle Dev Consoleになったので、
設定周りが多少変わっており、整理のために個人的なメモとして残しておきます。
プロジェクトの作成
GoogleDevelopersConsoleにアクセス
トップのCreateProjectをクリックし任意のプロジェクトを作成する
Projectsに作成したプロジェクトが追加される。
APIの有効化
作成したプロジェクトをクリックしプロジェクト詳細に遷移。
ここのoverviewに表示されるproject numberがAndroidアプリでregistration idを発行するときに必要な値。
APIs & authのAPIsから「Google Cloud Messaging for Android」を見つけ有効化(ON)にする
API keyの作成
CredentialsからPublic API accessのcreate new keyをクリック。
Server keyと進みserver側のAPI Keyを作成する。
使用するサーバー側のIPを制限したい場合はここでIP指定をする。
同じようにcreate new keyから今度はAndroid keyと進みclient側のAPI Keyを作成する。
こちらはAndroid applicationsの指定をする。アプリに使ったキーの「SHA1;パッケージ名」を組み合わせる。
キーのSHA1値は以下のコマンドで表示される。
keytool -list -v -keystore {キーストアのパス}
RSR2011タイムテーブルライブ壁紙公開
RSR2011タイムテーブルライブ壁紙を公開しました。
https://market.android.com/details?id=boringdays.jp&feature=search_result
Rising Sun Rock Festival 2011 in Ezoで
Android携帯で簡単にタイムテーブルの確認ができたらいいのになぁ、
と思ったので簡単に作ってみました。
タイムテーブルの上下スクロールや日程の簡単切り替えができます。
つまり大した機能とかは全然無いです。
本番までに拡張するかもしれないけれどw
ご了承ください。
なお、なかったので作ってみた非公式勝手アプリですのでご注意を。
石狩でライジングサン見れたらいいナ!
WeakHashMap なるものがあるのね
SoftReferenceといふもの
久々にAndroid記事を書いてみるw
画像のメモリーに対する圧迫はAndroidアプリ開発のよくつっかかるポイントだと思うけれど、
そこで活躍するのは往往にしてSoftReferenceっつうクラスだと思う。
メモリーリークしそうになるとGC側が優先してSoftReferenceが持つオブジェクトを開放して、
メモリーの節約をさせるという形。
なのでたとえば、画像を相当数リスト表示する場合、オンメモリーにある画像を参照する場合、
このSoftReferenceを介することで、画面上に表示されない画像はGC側が優先的に破棄し、
相当数の画像リスト表示にも耐えられる実装となる。
結果メモリー管理も楽になれるという形。
//実装 SoftReference ref = new SoftReference<Bitmap>(bitmap); //取得 Bitmap image = ref.get(); //解放 ref.clear();
http://developer.android.com/reference/java/lang/ref/SoftReference.html
SoftReferenceでの問題点
じゃあ、それで解決じゃんって話なんだけども、
これはSoftRefenrenceインスタンスの内部に持つObjectが解放される仕組みであって、
SoftReferenceインスタンス自体は解放されない。
なので、上記の画像のリスト表示なども、画面上に表示される画像オブジェクトは破棄されるのだが、
その画像を持っていたSoftReferenceインスタンスはメモリー上に残ったままなのである。
実際、残ってしまう空のSoftReferenceはメモリ圧迫には殆ど影響を及ぼさない量なのだけれど、
たとえば画像リスト表示を1000件以上だとかする場合、
1000個の空のSoftReferenceインスタンスがメモリー上に残ってしまう可能性がある。
こうなってくるとちょっと無視できなくなる。
そこでSoftReferenceインスタンスのリストが増えるたびに空のSoftReferenceインスタンスがないかチェックして、
あればそれを削除する、といった自前の実装が必要になってしまう。
しかしこれはメンドイ。
HashMap<string, SoftReference<Bitmap>> cache = new HashMap<string, SoftReference<Bitmap>>(); //空のインスタンスならリストから削除する private void cleanCache(){ for(string key : cache.keySet()) { if(cache.get(key).get()==null){cache.remove(key);} } }
WeakHashMap
そこでWeakHashMapの出番!
これはWeakReferenceというクラスに基づいて作られている拡張HashMapみたいなもの。
メモリーに対して一定の負荷がかかった時に内部で参照されてないオブジェクトがあった場合、
それをアイテムごと破棄してくれるというちょっと便利なモノ。
GCの判断で破棄されるのではなく、一定の負荷係数に応じて呼び出されるっぽい動き。
なので、空のインスタンスがメモリーに残ることはなく、
キャッシュの際などに大量のリスト状データが必要な場合はWeakHashMapの方が実装上楽に管理することが出来るでしょう。
//宣言するだけで後の処理は全部WeakHashMapにお任せ! WeakHashMap<string, Bitmap> cache = new WeakHashMap<string, Bitmap>();
http://developer.android.com/reference/java/util/WeakHashMap.html
…というわけで、
WeakHashMapはふつーに昔からある代物だそうです。。。
でもSoftReferenceを使ったWeakHashMapなんてものはないみたい。
知らなかったー。
IntentService
先日のGoogleDeveloperDays2010JapanでAndroidの高速化の際に出てきてたクラス。
気になってググったらやっぱり日本語の説明があんまりないのでメモ的に簡単に説明。
ServiceをオーバーライドしたIntentService
任意の特定の処理をメインスレッドとは別のスレッドで非同期で行うためのクラス。
このサービスは通常メインスレッドでハンドリングしないような処理を行うためのものらしい。
呼び出し方はサービス的だけれども同一プロセス内で別スレッドを立ち上げて処理する。
実際に実装するには、IntentServieを拡張しonHandleIntent内に特定の処理を記述する。
IntentService拡張
サービスとしてのクラスなのでインナークラスでの記述は不可能
public class CustomIntentService extends IntentService{ private static final String name="TEST"; public CustomIntentService() { super(name); } @Override protected void onHandleIntent(Intent intent) { //ここに時間のかかる重い処理を記述 } }
Activity側での呼び出し
@Override public void onResume(){ super.onResume(); Intent intent = new Intent(Intent.ACTION_SYNC,null,this,CustomIntentService.class); this.startService(intent); //ここからスタート! }
ちゃんとAndroidManifest.xmlにも記述
<application android:icon="@drawable/icon" android:label="@string/app_name"> ・ ・ ・ <service android:name="CustomIntentService"></service> //先ほどの拡張クラスを明記! </application>
そんなIntentServiceの中身
中身はHandlerThreadを1つ作ってそのループにキューを投げるというだけっぽいので、
たとえば同時に複数回startServiceメソッドを呼び出したとしてもここで要求される全てのリクエストは、
サービスを開始した順に同一プロセス内でシングルスレットで一つずつ処理される。
すべてのキューが終了したら通常のスレッドと同じように破棄される、という流れなのかな。
とはいえ、AsyncTaskと違うのはIntentServiceはService自身をスタートさせたActivityに依存せずに処理が続く。
AsyncTaskのように元Activityの生き死にで処理の中断などはされない。