phpmdでコード解析+チェックルールのカスタマイズしてみる
前回のphpcsに続きコーディングの品質向上のためphpmdを使うようにしてみました。
phpmdは潜在的にバグになりそうなコードや改善の余地があるコードなどを検出してくれるツールです
phpmdインストール
公式通り、composer.json
に下記を追記してcomposer installします
{ "require-dev": { "phpmd/phpmd" : "*" } }
使い方
コマンドラインで実行する際は下記のように実行できます。
phpmd /path/to/file xml codesize,naming,cleancode
xml以後のオプションで検出ルールを指定します。
ルールが設定してあるxmlはvendor/phpmd/phpmd/src/main/resources/rulesets/
以下にあります。
デフォルトでは下記があります。
またそれぞれのルールの実装はvendor/phpmd/phpmd/src/main/php/PHPMD/Rule/
にあります。
なので、ルールのカスタマイズするには、新規にruleを定義したxmlを作成して、それに対するチェックの実装を行っていく感じになります。
カスタマイズルールを作ってみる
今回はtypoチェックを実装してみました。
まずカスタマイズルール用にxmlを作ります。
vi vendor/phpmd/phpmd/src/main/resources/rulesets/myStandard.xml <?xml version="1.0"?> <ruleset name="My Standard Rules"> <description> This ruleset contains a my standard rules. </description> <rule name="CheckTypo" since="0.2" message = "Maybe typo. {0} : {1} -> {2}" class="PHPMD\Rule\MyStandard\CheckTypo" externalInfoUrl="#"> <description> <![CDATA[ Maybe typo. ]]> </description> <priority>1</priority> <properties /> <example> <![CDATA[ protocal->protocol recompence->recompense ]]> </example> </rule> </ruleset>
上記のように定義して、PHPMD\Rule\MyStandard\CheckTypo
にチェックルールの実装を行っていきます。
typo例はこちらのものを参考としました。
Wikipedia:Lists of common misspellings/For machines - Wikipedia, the free encyclopedia
既存の実装を元に下記のように実装してみました。
./resources/typoList.csv
にtypo単語リストを置いています
vendor/phpmd/phpmd/src/main/php/PHPMD/Rule/MyStandard/CheckTypo.php namespace PHPMD\Rule\MyStandard; use PHPMD\AbstractNode; use PHPMD\AbstractRule; use PHPMD\Rule\FunctionAware; use PHPMD\Rule\MethodAware; /** * This rule CheckTypo. * typo check * */ class CheckTypo extends AbstractRule implements MethodAware, FunctionAware { private static $typoList = []; /** * This method checks typo * * @param \PHPMD\AbstractNode $node * @return void */ public function apply(AbstractNode $node) { $typoList = $this->getTypoList(); foreach ($node->findChildrenOfType('Variable') as $variable) { $image = $variable->getImage(); foreach ($typoList as $key => $value) { if (preg_match("/$key/", $image)) { $this->addViolation($variable, array($image, $key, $value)); break; } } } } /** * get typoList * @return void */ public function getTypoList() { if (self::$typoList) { return self::$typoList; } $typoList = []; $fp = fopen(dirname(__FILE__) . "/resources/typoList.csv", "r"); while (!feof($fp)) { $tmpArr = fgetcsv($fp); $typoList[$tmpArr[0]] = $tmpArr[1]; } self::$typoList = $typoList; fclose($fp); return self::$typoList; } }
実行はこんな感じで、
phpmd /path/to/file xml myStandard
既存の実装を元になんとなくやってみましたが、変数名のtypo検出ができました!
こんな感じでカスタマイズルールを実装することでプロジェクト共通で品質向上やレビューの負荷軽減等していけたらと思いますん。
phpcsでカスタマイズしたコーディング規約をチェックする
正直なところ、今まであまり厳格に規約に沿ってコーディングしてきませんでした。
- ある程度守っていればいいだろ
- 統一させたいなら整形ツール的なやつで自動化すればいいじゃん
など思っていたんですが、OSSなど作っていきたいと考えた時、ちゃんと標準的なコードを書きたいと思い、コーディング規約をしっかり守りたいと考えるようになりました。
また何が標準かというのを理解するために整形ツールなどではなく、phpcsを使ってコーディング規約をチェックするようにしました。
phpcsインストール
PHP_CodeSnifferをインストールすることでphpcs,phpcbfなどがまるっと使えるようになります。
composer global require "squizlabs/php_codesniffer=*"
ドキュメント通り、composerでさくっとinstall
使い方、規約のルール指定
Usage · squizlabs/PHP_CodeSniffer Wiki · GitHub
phpcs --standard=PSR2 /path/to/file
などで指定したコーディング規約でチェックをすることができます。
規約ルールのカスタマイズ
現在のプロジェクトのコーディング規約はフレームワーク側の兼ね合いもありPSR2をベースにして、一部フレームワーク側の合わせたものになっています。
なので、そのままPSR2を適用すると意図しない規約のチェックが行われるので、PSR2をベースに一部をカスタマイズしたものを作成しました。
vendor/squizlabs/php_codesniffer/CodeSniffer/Standards
以下に各種規約ルールがあります。
ここにカスタマイズした規約ルールを作成し、その規約を指定してphpcsを実行するイメージです。
//MyPSR2という規約ルールを作成する mkdir vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/MyPSR2 vi vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/MyPSR2/ruleset.xml
今回はPSR2をベースにインデントを4タブ、いくつかのルールを除外したものを作成しました。
exclude nameはphpcs -s
などで実行して除外したいルールを追加していく感じです
ruleset.xml <?xml version="1.0"?> <ruleset name="MyPSR2"> <description>The MyPSR2 coding standard builds on the PSR2 coding standard.</description> <arg name="tab-width" value="4"/> <!-- タブ --> <exclude-pattern>*/Tests/*</exclude-pattern> <!-- Include the whole PSR2 standard except FunctionComment, which we override --> <rule ref="PSR2"> <rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/> <rule ref="Generic.WhiteSpace.ScopeIndent"> <properties> <property name="indent" value="4"/> <property name="tabIndent" value="true"/> </properties> </rule> <exclude name="PSR1.Files.SideEffects.FoundWithSymbols"/> <!-- --> <exclude name="PSR2.Methods.FunctionCallSignature.Indent"/> <!-- --> <exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"/> <!-- --> <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/> <!-- --> <exclude name="Generic.WhiteSpace.DisallowTabIndent.TabsUsed"/> <!-- --> <exclude name="Generic.WhiteSpace.DisallowTabIndent.NonIndentTabsUsed"/> <!-- --> <exclude name="Generic.WhiteSpace.ScopeIndent.Incorrect"/> <!-- --> <exclude name="Squiz.Classes.ValidClassName.NotCamelCaps"/> <!-- --> </rule> </ruleset>
ルール作成後に、
phpcs --standard=MyPSR2 /path/to/file
のように実行すればカスタマイズされたルールで規約のチェックをすることができます。
これでしっかりコーディング規約にそったコードを書いていけますね! 次はいちいちコマンドラインから実行するのもアレなので、エディタからコーディングチェックできるようにしていこうと思います。
New Relic ハンズオン・ワークショップ in Tokyoに行ってきた
行ってきてみました。
new relic使っているものの、transactionからどの処理が遅いか的な使い方しかしてなかったので。
スピーカーはNew Relic の Joe LoCascio さん。前編英語かと思いきやしっかり通訳の方がいらっしゃって一安心。
アジェンダ
ざっくりメモ
new relicの大枠の機能
-
- サーバー側のプロファイリング
BROWSER
- フロントエンド側のプロファイリング
SYNTHETICS
- サーバーの死活監視。ブラウザテスト的なこともできるらしい
MOBILE
- ネイティブアプリのプロファイリング
SERVERS
- サーバーのリソース監視
PLUGIN
INSIGHTS
- new relicで収集したデータをSQL的な感じ抽出してデータ分析できる
apdex
レスポンスタイムからユーザ満足度を図った数値
基準レスポンスタイムを設定し、そこから割合判定
apdex計算式
apdex = (satisfied + (tolerating / 2)) / total requests
satisfied -> 満足。レスポンスタイムが基準値以下
tolerating -> まあまあ。基準値の4倍以下
flustrated -> 不満足。基準値の4倍以上
key transaction
特定のtransactionをkey transactionに設定することでより詳細な情報を取得できるようになる
x-ray sessionで関数レベルで分析できる
error analytics
- クラスごと、トランザクションごとグルーピングできる
- error traceもできる
- newrelicのモジュールを追加すれば、newrelic専用エラー出力もできる
newrelicのAPIでデプロイメントマーカーを設定できる。
- リリース前後での変化を可視化
custom dashboard
- 監視したい情報を自分用にピックアップできる
using alerts
アラートポリシー設定可能
アラート条件、通知チャンネル柔軟に設定可能
所感
やろうと思えばもろもろ監視系すべてイケるっぽい
- でもすでにmuninとかもあったり、他の監視ツールとの住み分けなり統合なり考えないといけなそう
色々できそうだけどnewrelicのオーバーヘッドはないのだろうか・・・
過去にnew relicからマスターDBへ定期的にデータ取得してたりとかあった
野良のプラグインとか要調査が必要そう
どうやらもろもろphp対応は後回しの模様・・・
- 最近風当たりの強さを感じる
頂いたnew relic Tシャツが意外とアグレッシブ
でした!
crontabのエラー、(CRON) bad minuteはただの改行の場合でも出る
タイトルでもうほぼ終了なのですが、 crontabを更新した後に、cronのエラーログ/var/log/cronを確認すると下記のエラー
Feb 23 13:29:01 localhost crond[4436]: (xxxxxx) RELOAD (/var/spool/cron/xxxxxx) Feb 23 13:29:01 localhost crond[4436]: (CRON) bad minute (/var/spool/cron/xxxxxx) Feb 23 13:29:01 localhost crond[4436]: (CRON) bad minute (/var/spool/cron/xxxxxx)
書式間違っちゃったかなと思い、確認するも明らかに正しいはず・・・ 試しに全てコメントアウトしても上記のエラーが出る始末
よくよく見るとエラーの数と改行の数が一緒 crontabを改行なしにしてみると、エラーは出なくなりました
もうちょっとそれっぽいエラーにして欲しかった感。。。
golangでcrontabからドキュメントを作成するコマンドラインツール crondocを作った
javadoc,phpdoc的にcrontabからドキュメントを生成するツール
crondocをgolangでつくってみました
きっかけ
いくつかのサーバーの設定、ミドルウェア変更することになり、
影響範囲を確認していたのですが、サーバーごとにcronの運用が統一されていなかったのでcronまわり影響範囲を確認するのに時間がかかってしまいました
そこでcronの運用フローを統一する過程でcronの簡単なドキュメントを作成したくなりました
その際、javadoc,phpdocのcron版みたいのがないか探してみたのですが、ないようなのでせっかくなので自作してみました
crondocの機能
ざっくり下記のような機能で作ってみました
- 標準入力、ファイル指定でcrontabからドキュメントを出力
- 改行までをひとグループとしてドキュメント出力
- ドキュメントを出力はmarkdowm形式
- @authorなどのタグ付ができる
出力例
現状下記のようなcrontabの場合はこんな感じです
- crontab
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # @title monday.sh # @author hoge # @param env[dev|stg|prod] # start every monday 0 10 * * 1 sh /home/hoge/happy_monday.sh prod
↓↓↓
使い方
ソースはこちら
github.com
バイナリを落としてきて、下記のようにすればドキュメントが出力されるはずです
$ crodoc /etc/crontab $ crontab -l | crodoc -s
続 サービス稼働中に不要なDBのテーブルを安全に削除する方法
前回の続編です。
前回まで
前回はdropするテーブルのデータファイルにハードリンクを貼ることでdrop時にファイル削除されることを回避することができました。
しかしioniceで優先度を下げても、巨大なテーブルのデータファイルなどを削除する際はCPU使用率など見る限り負荷がかかっていました。 ioniceは緩やかに削除というより実行の順番の優先度を下げるという挙動のようです。
なので、次に負荷をかけずに巨大なファイルを削除するということで下記を参考にさせてもらいました。 www.nari64.com
truncateコマンドで徐々にファイルサイズを削り、小さくした後に削除するというやり方です。
安全にテーブルdropする手順
まとめて下記のような流れで処理しました
- 削除前に念のため、dump取る
mysqldump DB_NAME hoge_table > dump_hoge_table.sql
- 対象テーブルのデータファイルにハードリンクを貼る
ln /usr/local/mysql/data/DB_NAME/hoge_table.ibd /root/hoge_table.ibd ln /usr/local/mysql/data/DB_NAME/hoge_table.frm /root/hoge_table.frm
- drop tableを実行
mysql DB_NAME -e "DROP TABLE hoge_table"
- ハードリンクを貼ったファイルをtruncateコマンドで徐々にサイズを削った後に、rmを実行
//ファイルサイズ取得 $file_size = 0; $cmd = "du -m {$file_path} | awk '{print $1}'"; exec($cmd, $output, $ret); if($ret == 0) $file_size = $output[0]; //truncateで徐々に切り詰める if($file_size){ $i = 1; while ($i <= $file_size) { $tmp_size = $file_size - $i; $cmd = "truncate -s {$tmp_size}M {$file_path}"; exec($cmd, $output, $ret); //0.1sec sleep usleep(100000); $i++; } //ファイル削除 $cmd = "rm {$file_path}"; $res = exec($cmd, $output, $ret);
的な感じで、稼働中の本番DBで百数テーブル、260GB程度削除しましたが、負荷なく実行できました。 そこそこ時間はかかりますが、、、truncateの部分はもっと攻めて良さそうですがそれはまた次の機会に・・・
これでどんどん不要なテーブル消せますね!
感謝致します。
サービス稼働中に不要なDBのテーブルを安全に削除する方法
担当サービスのDBサーバーのディスク容量の空きが少なくなり、不要なテーブルを削除することになりました。
対象のテーブルのデータ量が多く、平常時でもそこそこ負荷のあるサーバーなのですが、
テーブル削除だけのためにメンテナンスをするのもアレなので、
深夜帯にしれっとdropしたい気持ちを抑えつつ、負荷のかからないdrop tableの手順を試してみました。
サービス稼働中にテーブルdropする時の問題点
metadata lock
drop対象のテーブルに書き込みやトランザクションが貼ってあるとmeta data lockがかかってしまいます
今回は参照等がないテーブルなので、問題なし
巨大なファイルを削除するとI/O待ちが発生する
巨大なテーブルのデータファイルを削除すると他のプロセスがI/O待ちになる可能性があります
安全にテーブルdropする方法やってみた
完全にこちらを参考をさせて頂きました。
dropする前にデータファイルにハードリンクを貼り、
drop時はファイル削除を行わず、後に優先度を下げて実ファイルを削除するという流れです。
さっそく本番でもやってみました。
# データファイルにハードリンクを張る ln /usr/local/mysql/data/hoge_db/bk_hoge_tbl.ibd /home/hoge/bk_hoge_tbl.ibd time mysql -e "DROP TABLE bk_hoge_tbl" real 0m0.047s user 0m0.002s sys 0m0.002s time ionice -c 3 rm -f /home/hoge/bk_hoge_tbl.ibd real 0m14.505s user 0m0.001s sys 0m0.065s
確かに意図通り、dropはデータ量に限らず一瞬で終わり、
データ削除はデータ量によって実行時間に違いがありました。
が、、、drop中は問題ありませんでしたが、データ削除中に若干レスポンスの悪化が見られました。
巨大なファイルを低負荷で削除する方法
結局、巨大なファイルを削除する時のI/O待ちが問題なら
drop前にパーティション切ってデータ細切れにするのはどうかな?でもめんどいなーって思っていたら下記の記事を見つけました。
巨大なファイルを削除する方法
このケースが一番悩まされました。しかし、最近 truncate コマンド使えばいいのでは〜ということに気がつきました。
truncate コマンドを用いて少しずつファイルサイズを減らす
sleep をはさむ
徐々にファイルサイズを小さくして、削除すればI/O負荷軽減できそうです。
次回はこちらの手順で削除してみようかと思います♪
感謝致します。