2013年11月18日月曜日

mroongaが割りとクラッシュしやすい件

MySQLの全文検索エンジンにmroongaを使用して数ヶ月サービス運用をしていましたが、

ちょくちょくmroongaがUPDATEロックをやってしまいコネクションが切れずMySQLが落ちる事があります。

復帰させるにはmroongaのロック解除を試しますが、うまく行った事がありません。

仕方ないのでテーブルを丸ごと作りなおすことになります。


その間、DBをクラスタ化してないとサービスが停止します。

原因がはっきりしていれば幾らでも対応できるのですが、ある種のテキストをmroongaがインデックスすると落ちるという程度しかわかっていません。

いつ落ちるか分からないでビクビクしながらサービス運用するのはとても耐えられないので最近はMySQL5.6.4から正式に標準対応したInnoDB FTSを使っています。

PHPでMecabで分かち書きする手間がありますが、特に難しいことでもなく、速度も速いので十分です。

なんといってもMySQL標準で滅多な事がない限りクラッシュしないので安心です。

mroonga(groonga)はプロジェクトポリシーも機能も速度も気に入ってるのですが、個人的にイマイチ実運用をするのは怖いです。


2013年9月6日金曜日

MySQLで遅いRANDを高速に【お手軽版】

MySQLのRAND遅くて困ること多いですよね。

プログラマになりたての頃は常に速いRANDの方法を考えてました。

最近になってやっと常套句が見つかったので紹介します。

SELECT id
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id_)
        AS r2
 WHERE r1.id >= r2.id_
 ORDER BY r1.id ASC
 LIMIT 1

受け売りなんですが、このSQLを見た時は感動しました。
AUTO_INCREMENTを使用しているテーブルならそのまま使えるでしょう。

物にもよりますが、 WHERE r1.id >= r2.id_ の後に評価式を加えて使います。
ブログサイトとかのランダム記事紹介にいいですね。

私の環境では40,000件のレコードからこのクエリでランダムにレコードを抽出すると1msかかりませんでした。
LIMITを変更してももちろん使えます。


2013年9月3日火曜日

AndroidのArrayAdapterでNoSuchMethodError

ArrayAdapterに対してAPIレベル11未満でaddAll()を行った場合発生します。
単純に11未満ではaddAll()が未実装な為です。

適当にArrayAdapterを継承してクラスを作成している場合、addAll系をすべてオーバライドしてループでadd()していくのが無難でしょう。

2013年8月31日土曜日

AndroidのParcelableでwriteToParcel ぬるぽ

簡単な話Parcelableインターフェースを持つクラスのメンバにIntgerは使うなってことです。

ちゃんとキャストするか面倒ならintにしましょう。Null Pointer Exceptionが発生します。

onPauseでBundleにParcelableを保存するときwriteIntを使いますが、Intgerに値を設定しないまま保存しようとするとNullを保存使用をします。

PHPばっかり書いてるとこういう基本的な事を忘れてしまう。

Parcelable実装面倒くさいんだけどなにかいいラッパーライブラリ無いだろうか。

FuelPHPでSessionがCookieに保存できなかった話

FuelPHPをようやく使いこなせてきたところでSessionのset_flashとかを使ってValidationエラーの表示をやろうと思ったらCookieに保存すらされていない現象が起きました。

結果からいうとFuelPHPはなにも悪くなく、リバースプロキシのサーバ時刻がGMTになってたのが原因でした。

同じサーバでバーチャールホストでFuelPHPを複数動かしていたのですが、一方ではSessionが使え、一方ではSessionが使えない不思議な現象で特定まで時間がかかりました。

 

FuelPHPのSessionは賢く、有効期限やらなんやら全部やってくれます。

なぜ同じサーバなのにSessionが動いたり(動いているように見えたり)、動かなかったりしたのかというと、

Sessionが動いてる方ではユーザ認証を使っていたためSessionの有効期限を大幅に伸ばしており、GMT-JSTの時刻差を超えて運用していたのでSession使えていました。

もう一方ではFuelPHP標準のSession有効期限を使っていたため、GMT-JSTの時刻差によって常にSession切れになっていたのです。

 

さらに問題だったのがFuelPHPを動かしているサーバ自体はJSTに設定してあり問題なかったのですが、リバースプロキシとしてVarnishサーバをかませており、そのVarnishサーバの時間がGMTだったことです。

ChromeでCookieを見ていた時、たまたまHTTP Headerを見て気がついたからよかったものの、随分初歩的なミスを犯してしまいました。

普段サーバを立てる時はntpdを一番最初に入れているのにVarnishサーバだけ入ってなかった…

 

mroonga(groonga)+Mecabでtoo long sentence

php5.3 + mysql5.6 + mroongaで数万文字になるテキストにFullTextインデックスを貼って、phpからデータを流しているとMySQLがLost Connectionを吐きデータベースがクラッシュしたように停止することがあります。

mroongaのインデックスが壊れるのでテーブルの再作成が必要になるほどです。

いろいろ原因を考えてmax_allowed_packetを変えたり、timeoutを調整したりしましたが、実際の原因はMecabにありました。

私が作成していたテキストデータは改行コードをPHP上で"\n"としており、問題ないと思っていたのですが、どうもmroongaがMecabで形態素解析するときにそのまま\nという文字として読み込んでいるようでした。

Mecabは改行コードで文章の終わりを見ているようで、数十万文字の文章に改行コードが入っていないとなると文章長すぎ!処理しない!となるようです。

MySQL+mroongaでFullTextを扱わないデータなら\nで問題ないのですが、Mecabはうまく認識してくれないということでPHP_EOLを使用したところちゃんと改行と認識してくれました。

PHP_EOLは環境依存なので使っていなかったのですが、まぁmroongaインデックス用のfieldなのでよしとします。

ハマリにハマって4時間浪費。

レンタルサーバか自社サーバどちらを使うのか

社長にレンタルサーバを使わない理由を聞かれたのでまとめます。

別に嫌いだから使わない訳じゃなくて必要性に合わせて使うことがないだけなのですが。

ここでは個人的なレンタルサーバのメリット、デメリットを書いていきます。

超小規模個人IT屋の極々個人的な意見で、実際に運用するWebサービスによってほとんどケース・バイ・ケースなので悪しからず。

 

レンタルサーバのメリット

レンタルサーバは比較的低負荷なサービスに用いることが多いと思います。

・Wordpress等のブログエンジンを使ったオフィシャルブログ(月間100万PV程度)

・画像、動画等のコンテンツサーバ

・feedクローラプログラム

など、ほとんどサーバスペックを必要としないサービスであれば月額980円程度のVPSレンタルサーバでも十分実用可能です。

2chまとめサイト等最近増えていますが、ああいう用途にも良さそうです。月間1億PVとかになるとスタンドアロンじゃ無理ですが。

 

・初期コストが安い

小規模なシステムなら月額980円程度のVPSで十分です。

サーバを買う初期費用もなく、ネットワーク回線もあり、電気代も月額料金に含まれます。

 

・耐障害性が高い

レンタルサーバではサーバスペックに目が行きがちですが、ネットワーク帯域を別回線として確保できるのがかなり大きです。

自社サーバと合わせて死活監視にも使えますし、自社サーバ障害時はレンタルサーバでホットスタンバイしておけばサービス稼働率を高く保てます。

レンタルサーバプロバイダによってはデータの耐障害性も自社サーバよりよっぽど高いものも多いでしょう。

スタンドアロンでありながらVPSならハードが壊れても問題なくサービスは継続します。

 

・デメリットが減ってきている

最近ではVPSサーバの台頭により、サーバのOSまるごといじれるレンタルサーバサービスが増えています。

以前はPHPのバージョンが古かったりデータベースはMySQLのみでデータベース数が限られているということもありましたが、その心配もなくなり様々な用途に使用できます。

 

レンタルサーバのデメリット

これも運用するサービスによりことなりますが、共通して言えるのがWANだと言うことです。開発時に割りと手間をとることが多くなります。セキュリティについてもLANより強固にしなければなりません。

 

・サーバが手元に無い

サーバが手元にないとなにかと不便で、レンタルサーバ上のOSのを入れかえようと思ったらデータをすべてネットワーク越しにバックアップして、OSのISOをVPSに送ってtelnetでインストールして…と気軽にいじくるには少々時間がかかります。

開発時にはFTPかsambaを使えればソース反映はなにかと便利ですが(EclipseかNetBeansを使っているので)、ネットワーク帯域やセキュリティの問題が出てきます。しかしこの辺はgitなりクラウドサービスを使えばある程度はカバーできますね。

 

・開発時に不便

開発はローカルでやってしまえばいいと言えばそれまでですが、実環境で動かしてみないとわからないことも多いわけで、自社サーバと同等の開発環境になるかと言えばそうではないと思います。

レンタルサーバへは常にWAN越しになり、SSH、FTP等で常々つなぐことになります。IDEを使っているとFTPクライアントを入れたり、セキュリティの為ハッシュを生成したりキーを変えたりとLANよりは、遥かに手間が増えます。

一度、レンタルサーバに合わせた開発環境を構築していまえば以後は楽になると思いますが、手間です。

 

・なんといってもサーバスペック

メリットで上げた程度のサービスならCPU2コア、メモリ512MB、ディスク10GBもあれば十分ですが、少し複雑なデータベース構成にしようと思ったら一気にスペックが足りなくなります。

現在、私が運用しているシステムはデータ件数1000万件以上、MySQLバイナリで40GB以上、CPUは8コア3Ghzでメモリ24GBのシステムがあります。ほとんどの時間帯すべてでこれらのリソースを常に使用しています。

これをレンタルサーバで行おうと思ったら初期費用8万円、月額9000円程度になります。上記システムの動かしているサーバは自作で、5万もかかっていません。電気代は月3000~6000円といったところでしょうか。

どうしても高負荷になるサービスをレンタルサーバで行おうと思ったら管理費が高くなるのです。

レンタルサーバにはネットワーク帯域と耐障害性という強みを持っていますが、正しいバックアップ運用とシステムとネットワークの多重化をしていれば運用上問題ない耐障害性は作れます。

 

・結局自社サーバで事足りてしまう。

自社サーバが複数台あればバーチャルホストで低負荷なサービスは量産できますし、運用コストも安く開発もやりやすいです。

課金システムを含むサービスや個人情報を含むサービス等、絶対にデータ紛失を行なっては行けない場合はネットワーク多重化、UPSの導入等考えるとレンタルサーバを複数台借りて運用した方が安上がりになるでしょう。

 

 

以上の事で私がレンタルサーバを使う機会が少いです。(他にもメリットデメリットあった気がするけど思い出せない)

もちろん必要性と開発、運用コストに合わせて今後レンタルサーバなりAmazon EC2なりGoogle App Engineなり使うこともあるとおもいます。

現時点では自社サーバで開発、運用するのが一番楽です。


CentOS6.4+varnishでリバースプロキシ

動的IP一つで複数ドメインで複数サービスといういかにも弱小な運用することになったのでリバースプロキシを導入することにしました。

一般家庭向けのFTTH1GbpsでもプロバイダがSoftBankなら転送制限は今のところなく、案外安定してサービスを続けられています。(月間100GBは上下してると思います)

ネットワーク帯域は十分、そこそこのスペックのあるサーバ一台毎ににWeb、DB両方入れてサービス運用をしています。

落ちてもそこまで問題の無いサービスなので冗長化は行なっていません。

落としちゃいけないサービスは事務所サーバで運用せずクラウドでやります。そういえばGoogle Computer Engineが楽しみ。

 

とは言ってもいずれやることになるのは目に見えてるのでとりあえずLVSで冗長化の試験を行うことに。

少々躓いたけど無事動いたということでリバースプロキシにしようと思ったらLVSじゃドメインベースの振り分けできないことに気づく。

なにを思ったかL4スイッチだから出来るだろうと確認もせずやってました。

 

しかたないのでHTTPのリバースプロキシを改めて導入することに。

ApacheやPoundやnignxなどなどありますが、今回はリバースプロキシでキャッシュしたりヘッダいじったりしないし、

新たにサーバ新調するのも持ったいないので転がってたMini-ITXのAtomで十分動くであろうvarnishを使うことにしました。

初めてvarnish使ってみましたが、これがなかなか使い勝手がいい!

 

WAN

NVR500(L3)

varnish(L4 or L7)

Web01(hogehoge1.com)  , Web02(hogehoge2.com), othres...

といったネットワーク構成です。サービスが増えたらvarnishもLVSで複数にする予定です。

現在はWebサーバとDBサーバは物理的に同じですが、それもいずれ分離してクラスタする予定。

 

・CentOS6.4にvarnish3.0.1をインストール

 

デフォルトのリポジトリには含まれていないのでrpmを用意

適当に最新版を持ってきます。

$ rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el5/noarch/varnish-release-3.0-1.noarch.rpm

$ yum install varnish

デフォルトポートが6081あたりになってるのでhttpdに合わせて変更

$ vi /etc/sysconfig/varnish

#VARNISH_LISTEN_PORT=6081

VARNISH_LISTEN_PORT=80

 

・設定

 

varnishの一番好きなところです。

VCLというドメイン固有言語があり、かなり細かく設定ができます。

でも今回は必要ないので単純にドメインで振り分けする設定です。

 

$ vi /etc/varnish/default.vcl

backend default {

  .host = "127.0.0.1";

  .port = "80";

}

 

backend hogehoge1{

  .host = "192.168.1.10";

  .port = "80";

}

 

backend hogehoge2{

  .host = "192.168.1.11";

  .port = "80";

}

 

sub vcl_recv {

 

  if (req.http.X-Forwarded-For) {

    set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;

  } else {

    set req.http.X-Forwarded-For = client.ip;

  }

 

  if (req.http.host == "hogehoge1") {

    set req.http.host = "hogehoge1";

    set req.backend = hogehoge1;

  }elseif (req.http.host == "hogehoge2") {

    set req.http.host = "hogehoge2";

    set req.backend = hogehoge2;

  } else {

    error 404 "Unknown virtual host";

  }

}

見たまんまシンプルな設定です。

VCLではこのようにC++ライクに設定がかけます。

FreeNAS8.3.1x64+ZFS(raidz)で自作NAS

WIndowsの開発機のシングルHDDにsambaで繋いで運用環境のバックアップを手動でとる。という不安で仕方ない環境で、
先月HDDが3台が立て続けに逝ったので重い腰を上げNASを導入することにしました。

NASは既成品でBuffaloのLS-WXL05Dを持っていましたが、速度が遅く細かい事ができない、容量の大きいものは結構高い。ということで自作NASにすることに。
ちなみにこの際にLS-WXL05DはHDDを換装してテレビ録画したりメディアサーバにしたりと、個人用途では十分使えます。

おおまかに導入メモ
1、機器の購入

・マザー、CPU、メモリ、システムディスク
サーバ群にMini-ITXのASUS E45M1-I DELUXEがすでにあり、中途半端に非力でデバッグ機として使ってたのでNASとして再利用。
DDR3 4GBx2、Crucial M4 64GB CT064M4SSD2(システム用)、マザーボードにBluetoothやら無線LANやらUSB3.0やらHDMIから乗ってるのでNASとしてはなかなか使い勝手がいいです。(全部使ってませんが)
raidzで組む予定だったのでCPUの弱さが少々心配でしたが、現在そこそこ速度も出てるようなのでヨシとします。電源も転用でATXの400W
ということで0円

・ケース
自作大容量NASといえば「Node 304 FD-CA-NODE-304-BL」
MiniITX準順のくせに3.5インチが6台も入ります。ケースファンが3台ついてて硬性も高いです。HDDのアクセスはしにくいですが、ホットスワップすることもないだろうということで目をつぶりました。
見た目もなかなかカッコいいです。割とでかい。一見ウーファーの様。ちなみにリセットスイッチはついてません。
TSUKUMOで9,980円

・HDD
1TBプラッタのWD30EZRX/Kにすることにしました。3TBで10,980円を4台購入。
ケース限界の6台欲しかったけどマザーにSATAが5ポートしかなく、インターフェースカード買うのも金かかるし、3TBが4台あれば数年は持つ予定。
Faithで44,000円

2、OSのインストール
MySQLのバックアップもしようかなと思ってSolarisかCentOSあたりにしようかなと思ってましたが、NAS用のFreeNASが簡単そうでWebUIまで標準で入ってるとのことで、zfs入れたりrpmしたり面倒だったのでFreeNASにしました。
AFP、NFS、CIFS、FTP、SSH、その他もろもろ入ってるのでNASとしては十分です。WANからアクセスする予定もないし、セキュリティは深く考えていません。
FreeNASのインストールはhttp://aramacin-blog.blogspot.jp/2013/01/freenas830.htmlを参考にさせて頂きました。
GUIを画像付きで解説してくれててとてもわかりやすい。

3、raidz設定
購入したHDD4台すべてつなげてraidzを組みます。GUIで楽々
raidzの組み方は多々ありますが、主にバイナリと個人情報を含まないデータベースの定期バックアップなので簡素に。
適当にユーザとパーミッション作って完了。

4、メール設定
FreeNASは標準でレポートをメール送信してくれます。
Gmailでできるのでそれもありがたい。ネットワークのDNSの問題でGmailのメールサーバの名前解決ができず、your test email could not be sent: [Errno 8] hostname nor servname provided, or not knownというエラーが出たので直接IP入れました。
GoogleのメールサーバのIPそうそう変わることがないと思いますが、毎日レポートメールが来るのでメールが来なけりゃ設定直そうという甘い考えです。

5、完成
完成しました。楽々でした。
開発機からマウントして速度を測ってみました。



もう少し速度が出せそうな気がしますが、NASとしては必要十分な速度なのでOK。
4KランダムReadがなんでこんなに速いのか不思議です。SSDキャッシュを勝手にやってくれてるのかもしれないから後々調べます。

初めて自作NAS組んでraidz使ってみましたが、特につまる所もなく、簡単にできました。
面倒なのはバックアップのcron書く方ですね。
NASは信頼性が最も重要だと思うのでできれば既成品が良かったのですが。
今後はリカバリのテストやrsyncなど始めていく予定です。

2013年3月5日火曜日

Eclipse Google Plugin デプロイエラーcom.google.appengine.tools.admin.JspCompilationException: Failed to compile jsp files.

ハマった。

Windows7 x64でslim3にてGAE開発を行なっているのですが、slim3のbuild.xmlが動かないこともありEclipse4.2 x86(32bit)版をIDEとして使っていました。

開発自体に何ら問題なく順調に行なっていたのですが、ローカルのDataStoreにJava上ではUTF8の日本語文字列を入れたところDataStoreViewerで文字化けしていたので、実際にGAEにデプロイして確かめようよしたところタイトルのエラーが発生。

関連するエラーでUnable to update app: Cannot get the System Java Compiler. Please use a JDK, not a JRE.ある。

JREはx64版でEclipseはx86でのみ発生するのかはわかりませんが、以下解決策。

 

「x86(32bit)」版の「JDK」をインストール。今回のバージョンは1.7.0_15。バージョンは1.6以上ならなんでもいいと思います。

JDKがC:\Program Files (x86)\Java\jdk1.7.0_15あたりに配置されると思います。

 

EclipseにてWIndow→Preference→Java→Installed JREsにAddで上記パスを追加

Eclipseを一旦閉じる。

 

Eclipse.exeと同ディレクトリにあるeclipse.iniのopenFileディレクティブ直下に

 

-vm

C:\Program Files (x86)\Java\jdk1.7.0_15\bin

 

を追加。

Eclipseを再起動。

 

なぜx86版JDKかというと単純にx64版では動かなかったからです。

こういう所でハマると時間がかかるから困る。

2013年1月8日火曜日

VirtualBox仮想環境AndroidをEclipseからデバッグしてみた

Androidアプリ開発に本格的に着手することになるので開発環境を整えます。

AndroidアプリのIDEであるEclipseはGoogleがプラグインとSDKとエミュレータをセットにしたパッケージを配布してるのでそれを実行するだけでできてしまいます。

http://developer.android.com/sdk/index.html

Windowsはこれだけで直ぐにAndroid開発ができちゃうから便利ですね。

 

ただ、エミュレータがどうしても重たい。このバンドルされているエミュレータはARM命令をx86CPUでエミュレートすることによって動いているのですが、

命令セットのエミュレータというのはかなり高コストになります。現在のどんなにハイスペックのPCでもヌルヌル動かすのは難しいでしょう。

 

なんとかならないものかと探していたらx86で動くAndroidビルドがあるそうです。

ということはVirtual Box等の仮想化ソフトで動かせるということ。

x86なので命令セットのエミュレートも必要ありません。

そして何台でも仮想Androidを作成できます。

 

試しにやってみたところ実に簡単に動かす事ができました。

ヌルヌルとまでは行きませんが、少ないリソースでAndroidエミュレータよりかなり高速に動かすことができます。

ただ、APIレベルがあってなくてEclipseからリモートデバッグができないこともあったのでいずれやり方をまとめようと思います。

 

それにしてもEclipse + ADTは画面ゴチャゴチャで見辛い...

フルHDでも狭いから4k2kが欲しくなってきた。

2013年1月7日月曜日

Webサーバチューニング(MySQL+PHP)とりあえず版

チューニングメモ。

パラメータの細かい説明はいろんなサイトにまとめてあるので省略します。

環境としてはOSは問わずPHPでSQLゴリゴリでリクエストあたりレスポンス秒が少ないWebサービスで、

他にクローラツール等のDBサーバも請け負っています。

 

まず、見落としがちですが、

CLOSE_WAITのセッションを早く消します。

主にクローラツールが原因なのですが、TCPコネクションが無駄にkeepaliveされるので許されるギリギリの値まで削ります。

http://network.station.ez-net.jp/server/linux/network/time_wait.asp

が参考になります。

# vi /etc/sysctl.conf

に下記を追加。

net.ipv4.tcp_keepalive_time = 5

net.ipv4.tcp_keepalive_probes = 2

net.ipv4.tcp_keepalive_intvl = 2

net.ipv4.tcp_fin_timeout = 15

 

次にApacheチューニングですが、奥が深すぎるのでおおよその計算を設定して運用後、徐々に調整していきます。

私の環境では以下の様に。結構稼働範囲ギリギリです。

# vi /etc/httpd/conf/httpd.conf

Timeout 15

KeepAlive Off

HostnameLookups Off

TraceEnable Off

<IfModule prefork.c>

ServerLimit 300

StartServers      10

MinSpareServers   50

MaxSpareServers  100

MaxClients      300

MaxRequestsPerChild  4000

MaxMemFree 4096

</IfModule>

server-statusを見ながら細かい調整を重ねます。

 

そしてMySQLの設定。

どのようなリレーションでサブクエリを多用するのかしないのか。同時にいくつアクセスがあるのかなど考えて調整していきます。

私の環境では細かい接続がバンバンくるので下記の様な設定です。

# vi /etc/my.cnf

 

max_connections = 1500

 

#tuning

query_cache_limit       = 32M

query_cache_size        = 256M

 

key_buffer              = 2048M

max_allowed_packet      = 4M

thread_stack            = 192K

 

sort_buffer_size = 4M

read_buffer_size = 4M

read_rnd_buffer_size = 16M

join_buffer_size = 262144

 

wait_timeout = 120

interactive_timeout = 120

 

thread_concurrency = 300

thread_cache_size = 3000

table_cache = 10000

 

 

PHPで真っ白画面

 

また下らないことで少しハマった。

Webサーバの引越時にPHPファイルを移行してMySQLに接続するコードーがありました。

ほぼ同じ構成のサーバの引越しなので特に問題なく進むはずと思ってたのですが、php.iniの設定でエラー表示するようにしてるのに画面が真っ白です。

エラーログファイルにも何も書かれていません。

 

一時間くらいうろうろしてたところふとMySQLへ接続するDAOラッパをコピペで動かしてるのを思い出しました。

見てみると「@」アットマーク。エラー制御演算子がmysql_connectについてました。

エラーが出ないのも納得。エラー制御演算子をつけているのにも納得。

こういうことがあるからコピペする時は最大限の注意を。

 

 

2013年1月2日水曜日

何度目かのブログ開設

GAEのmiclogが死んだので今度はBloggerでブログ開設。

もう何度ブログ作りなおしたかわからないけど懲りずにやります。

IT系忘却ブログです