考える×つくる×動かす

主に技術系のことを書いていきます。

mroongaで「ERROR 1005 (HY000): already used name was assigned:」の対処

MroongaでTokenizerをMecabからTokenBigramSplitSymbolAlphaDigitに変更する際に
インデックスのDropでエラーが出てしまい強制的に中止した。

これがまずかったのか、
その全文検索のインデックスが存在していないにもかかわらず、
再度インデックスを貼り直そうとした際に、

ERROR 1005 (HY000): already used name was assigned:

というエラーが発生するようになってしまった。

groonga /var/lib/mysql/database.mrn
>table_list

でMroongaのtable_list情報を確認した所しっかりと残っていた。

http://groonga.org/ja/docs/reference/commands/table_remove.html
の情報を参考に

>table_remove index_name 

でMroongaのtable_list情報を削除したら無事インデックスを貼り直すことができました。


以下バージョン情報です。

mysql Ver 14.14 Distrib 5.6.11
groonga(mroonga) 3.0.3

人生で大事なことは大体自転車から学んだ。

・一歩ずつ前へ前へペダルを漕ぐだけで大概の場所に自分の力で行ける
・長くてきつい上り坂は永遠には続かない
・楽な下り坂も永遠には続かない
・頂上から見る景色は物凄い綺麗だ
・下り坂に入ったときにブレーキを掛けながら下りないと転んで怪我することもある
・距離は短いけど急な坂もあれば距離が長くゆるやかな道もある
・毎日のメンテナンスが安全やパンクを防いでくれる
・自転車本体の良し悪しはあるけど結局は自分の体力次第
・長距離の自転車に乗る場合はペース配分を考えないと途中でバテてしまう
・食べ物や水はある程度ストックしておかないと大変なことになる
・いくら遠回りしたって足を止めないで漕ぎ続ければ目的地には到着できる

社内のISUCONに参加しました。

昨日のことですが社内のISUCONに参加しました。

ISUCON2に関しては以下のブログに書いてあります
http://blog.livedoor.jp/techblog/archives/67728751.html
http://github.com/tagomoris/isucon2

今回はPHPを選択しました。
だって一番慣れてるしー
ホントだったらRubyでやりたいんだけどねー

実を言うと自分は業務がちょっと忙しくて
ソースを完全に見たのが当日の昼という状況でした。

まず基本的な設計指針

PHP不要モジュールの削除
→ほぼ必須モジュールのみだったので手を加えず

Apache不要モジュールの削除
→Auth系とかProxy系はOFF

・不要なサーバーのサービスのKill
→chkconfigで確認してPostfixとかOFF

CSS,JS,画像ファイルの最小化
→JSはGoogleから引っ張ってきて画像は圧縮してBASE64エンコで内部に埋め込み

・Memcacheの導入
→別途記載(1)

・DBテーブルカラムの最適化
→別途記載(2)

Apache等各種ログファイル出力のOFF
httpd.confですべてOFF

・Keep Aliveの設定
→一回のリクエスト数が少ないので重くなりOFFにした


まず初期状態でのベンチスコアは110チケット前後
WebよりもDBのLoadAverageがいっぱいな感じ。

Memcacheの導入(1)

スロークエリーが出ていた場所は

SELECT stock.seat_id, variation.name AS v_name, ticket.name AS t_name, artist.name AS a_name
FROM stock
JOIN variation ON stock.variation_id = variation.id
JOIN ticket ON variation.ticket_id = ticket.id
JOIN artist ON ticket.artist_id = artist.id
WHERE order_id IS NOT NULL
ORDER BY order_id DESC LIMIT 10

最近購入されたチケットの10件を取得して表示する場所。

これは様々なページで呼ばれていたのでMemcacheに入れた。
チケットが売れた時に10件を超えていた場合はarray_popし古いのを1件削除して
array_unshiftで直近で売れたチケット情報を加えることにした。

Memcacheの導入(2)

他の部分でスロークエリーが出ていた場所は

SELECT COUNT(*) FROM variation
INNER JOIN stock ON stock.variation_id = variation.id
WHERE variation.ticket_id = :ticket_id AND stock.order_id IS NULL

残りのチケットの枚数を取得する場所。

はじめの枚数をMemcacheに入れて、
チケットが売れた時にそのvariationの枚数を-1する処理に変更。

ここで400前後のスコアまで改善した。

APCの導入+サーバーのチューンナップ

APCを入れたらスコアが一気に700前後まで改善した。
KeepAliveはスコアが落ちたのでOFFにした。

DBテーブルカラムの最適化

アーティストとチケットと開催場所をDBではなくソースに直接配列として記述した。
これらの値は基本固定だったので配列として処理した。

以下やらなかったこと

・nginxの導入
→時間が足りなかった
Mysqlのエンジン変更
Mysqlサーバはボトルネックになってなかったから
フレームワークの変更
→時間が足りなかった
Mysqlのテーブルカラムの構造変更
(stockのseat_idをvarchar255から2個にカラム分割してintに変換しindexを貼り直す)
Mysqlサーバはボトルネックになってなかったから

以下反省点

・事前に時間を作ってちゃんとソースとサーバーを見ておくべきだった
・テストのソースをしっかりと確認してどこをテストしてるのかを確認すべきだった
・Webサーバっていう大まかな負荷を見るだけじゃなくて、
どの画面がボトルネックになっているのかっていうのをしっかりと把握すべきだった
・実際の業務じゃないので新しい技術に積極的にチャレンジしてもよかった

最後に

チームメンバーのお陰でなんと優勝することができました。
最小の処理でなかなかのパフォーマンスを引き出すことができ良かったかなと思います。
運営の皆様お疲れ様でした。次回ありましたら是非また参加したいです。

賞金5000円分の商品券もらったんで飲みにでも行きましょう(笑)

CakePHPでBlogを作る

某社の課題でBlogを作る。

基本設計編

まず基本となる言語環境選択

PHP(一番得意)
Perl(はてななら)
RubyRails使うなら)

今回は単純に一番得意なPHPにて開発することにした。

次にデータベースの選択

Mysql(ローカルにインストール済)
PostgreSQL(ローカルに未インストール)
Sqlite(環境が変わってもファイルなんで手軽)

ローカル環境なので何も考えずにMysqlで作ることにした。

次にフレームワークの選択

・ZendFramework(ちょっと規模が小さい)
CakePHP(お手軽)
Ethna(昔使ってた)

ZendFrameworkだと1時間かからずに作成できるけど、
自分フレームワークも含んでいるためかなり規模が大きくなって、
Zend内部と自分フレームワークと2重の説明をしないといけなくて煩雑になりそう。
お気軽っていう意味でCakePHPを選択した。
ただCakePHPは1.3系までしか使ったことがないのと、
最後に使ったのが数年前なのでちょっとブランクあり。


ローカル環境編

ホストの設定

hostsファイルにローカルアクセスできるように以下を記述する。

sudo vi /etc/hosts 
127.0.0.1       blog.localhost
Apacheの設定

バーチャルホストの設定する。

sudo vi /opt/local/apache2/conf/extra/httpd-vhosts.conf
<VirtualHost *:80>
    DocumentRoot "/Users/kazuya/home/blog/app/webroot/"
    ServerName blog.localhost
</VirtualHost>
サーバー再起動
sudo apachectl restart
データベース作成

本当ならユーザーも作成すべきだけどローカル環境なのでrootで全てやっちゃう。

mysql -u root -p   
# (パスワード入力)
mysql > CREATE DATABASE  `blog` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
CakePHPのインストール

http://cakephp.jp/ より最新版をゲットして/Users/kazuya/home/blogに設置する。

CakePHPの設定

セキュリティーの値を変更

app/Config/core.php以下の値を変更する。

'Security.cipherSeed'
'Security.salt'
データベースアクセスの設定

app/Config/databese.phpを作成する。
ファイル内容はこんな感じ。(パスワードとユーザー名は適宜変えてね)
またMacportsでインストールしたMysqlだとソケットを指定しないと動かないので注意する。

	public $default = array(
		'datasource' => 'Database/Mysql',
		'persistent' => false,
		'host' => 'localhost',
		'login' => 'root',
		'password' => 'XXXXXXXXX',
		'database' => 'blog',
		'prefix' => '',
		'encoding' => 'utf8',
	    'unix_socket' => '/opt/local/var/run/mysql5/mysqld.sock'
	);
書き込みの権限を付与

キャッシュとかセッションを保存する一時フォルダーに書き込み権限をつける。

chmod -Rf 0777 app/tmp


http://blog.localhost/ にアクセスして問題なく動作していることを確認。
f:id:kazupyong:20121104231442j:plain


アプリケーション設計

データベース設計

データベースはERMasterで作った。
Blogで最低限記事とタグ付けが出来ればいいとの課題なので、
記事とタグと関連付けテーブル。あと認証を使いたいのでユーザーテーブルを作成する。

ER図はこんな感じ。
f:id:kazupyong:20121104232233p:plain

ERMasterでSQLをエクスポートしてコマンドラインからテーブルを作成する。

> mysql -u root -p blog < blog.sql 
Bakeでモデル、コントローラー、ビューを作成する

CakePHPにはBakeっていうインタラクティブなコマンドラインツールがあるんだけど、
2.2で久しぶりに使ってみたらかなり使えるツールになってた。

php -f ./app/Console/cake.php bake
---------------------------------------------------------------
Interactive Bake Shell
---------------------------------------------------------------
[D]atabase Configuration
[M]odel
[V]iew
[C]ontroller
[P]roject
[F]ixture
[T]est case
[Q]uit
What would you like to Bake? (D/M/V/C/P/F/T/Q) 

と表示されるのでMを選択してModelを作成する。

Use Database Config: (default/test) 
[default] > 
Possible Models based on your current database:
1. ArticleTag
2. Article
3. Tag
4. User

と4テーブル分のモデルをチュートリアルに従って作成する。
バリデーターとかも事細かにそれぞれのフィールドごとに指定できる。

ここで大切なのは
ArticleとTagはArticleTagにhasAndBelongsToManyであり、
ArticleTagはArticleとTagにbelongsToしていると関連付けしておく。

ControllerとViewも同様にして作成する。


アプリケーション実装

ルーティング処理

articlesのindexがblog.localhostにアクセスした際にデフォルトの表示になるように
app/Config/routes.phpに以下を記述する。

	Router::connect('/', array('controller' => 'articles', 'action' => 'index'));

またコントローラーのadmin_の関数を有効化する為に
app/Config/core.phpに以下を記述

	Configure::write('Routing.prefixes', array('admin'));
ページング処理

ArticlesControllerにページング処理の設定。
記事の公開日時順に並び替えたいのとデフォルトで5件表示に変更。

クラス変数に以下を追記

public $paginate = array(
        'Article' => array(
        'maxLimit' => 5,
        'order' => array('published' => 'desc'),
));

あとはタグIDが指定されている場合にそのタグの記事だけが表示されるように、
ArticlesControllerのページング処理に絞込みの条件を指定。

function index ()内に以下を追記した。

	if(isset($this->params['named']['tag'])){
	    $cond = "ArticleTag.tag_id = {$this->params['named']['tag']} and ";
	    $this->paginate['Article']['joins'] = array(array('type' => 'LEFT', 'alias' => 'ArticleTag', 'table' => 'article_tags','conditions' => 'Article.id = ArticleTag.article_id'));
	}
ログイン処理

LoginControllerとAppControllerにadminのログイン処理を記述。
今回はAuthコンポーネントを使って処理する。

AppControllerにコンポーネントの有効化を記述することにより、
基本すべてのコントローラーがAppControllerを継承しているので全てに反映される。

クラス変数に以下を追記

    public $components = array(
            'Session',
            'Auth' => array(
                    'loginRedirect' => Array('controller'  => 'admin', 'action' => 'articles'),
                    'logoutRedirect' => Array('controller' => 'login', 'action' => 'index'),
                    'loginAction' => Array('controller' => 'login', 'action' => 'index')),
            );

ただ、Blogのトップと記事詳細はログインしてなくてもアクセスできるように、
AppControllerのbeforeFilterに以下を記述。

    function beforeFilter() {
        $this->Auth->authError = __('Login Error');
        $this->Auth->allow('article','index');
        $this->Auth->allow('article','view');
    }
日本語化対応

デフォルトでエラーメッセージやデータベースのカラムとかは全て英語表示。
一応日本語化しておく。
コマンドで全ファイル内の文字出力関数__()内の翻訳ファイルを作る。

php -f ./app/Console/cake.php i18n 

これでapp/Locale/以下にdefault.potファイルが出来る。

mkdir -R app/Locale/jpn/LC_MESSAGES/
cp app/Locale/default.pot app/Locale/jpn/LC_MESSAGES/default.po

日本語の翻訳メッセージを入力しておく。
デフォルトで英語環境で使っているので日本語のFirefoxをインストールして確認した。



こんな感じで最低限ひと通りの機能は完成。


ソースコードは以下で。
https://github.com/kazupyong/Blog

MyWi4.0+B-Mobileの組み合わせ最強説

以前の記事の続き。

MyWiがアップデートしてiOS4に対応しました。
3GをiOS4にすると電池のもちが悪くなったり、もっさりしたので、3.1.3に戻しました。

以下新しいフィーチャーの日本語訳。
http://www.rockyourphone.com/index.php/mywi-4.0.html
・より早く起動
・より消費バッテリーを少なく
・公式のテザリングバーとステータスバーに表示を選べる
・ステータスバー表示にすれば10-15%のバッテリーの持ちが良くなる
Wifiの電波強度を30-100%の間で調整できる
・USBブリッジモードを搭載


個人的にはWifiの電波強度を調節できるのがいい。
基本的にすぐ近くに置いて使うので強度は殆どいらなく、
バッテリーの持ちと発熱を抑えられるのがいい。
あと起動がかなり早くなって使わないときはすぐOFFにできる。


5日くらい使いましたが、
たまに繋がらなくなったり不安定なことはあるものの、
基本的にiPhone4の3Gデータ通信の電波はOffのままで十分運用可能。
ドコモの広範囲+安定したネットワークで3Gにつながるのはすごい便利だ。
またMacbookProでUSB給電しながらのテザリングだと充電しがらテザリングできる。