読者です 読者をやめる 読者になる 読者になる

雑多なノート

プログラミング初心者がメモとかを書きます。基礎的なこともメモとして。偏食系のアニオタ。

強制終了の理由とMySQLのキャッシュ

MySQLからデータを持ってきてNeo4jに流し込むPerlスクリプトを走らせてたら強制終了されてた

processing 19 of 215...finish
processing 19 of 215...強制終了
[vayacico@rabbit script]$

何とも不親切なエラーメッセージ……
不親切感的にスクリプト内部でエラーが発生した訳ではなさそう

調べてみたらLinuxから強制終了させられてる可能性があるらしい
メッセージが「強制終了」だけなので調べても見つからないことも覚悟してたけど見つかって良かった……

とりあえず調べた通りにログを確認

[vayacico@rabbit ~]$ sudo tail /var/log/messages   
...
Dec  5 19:55:07 rabbit kernel: Out of memory: Kill process 6287 (mysql_to_neo4j.) score 738 or sacrifice child                                     
Dec  5 19:55:07 rabbit kernel: Killed process 628
7, UID 500, (mysql_to_neo4j.) total-vm:2790640kB, anon-rss:359168kB, file-rss:4kB

Out of memoryとかいうお馴染み感のあるメッセージを確認
メモリ使いすぎで消されたのね
OOM killerとかいう格好良い名前のLinuxカーネルの仕組みによって消されたらしい
このメッセージを標準エラー出力に出してくれればいいのになー


強制終了の理由が分かったところで原因を考えてみる
メモリの使いすぎっていうのは決まっているのだがメモリを大量に使うようなコードは書いた覚えがない
MySQLから持ってくるデータは多いけどカーソル使ってアクセスしている(多分)のでメモリを大量に消費するとは思えないし
変数に結果を全部格納するようなプログラムだと実行した瞬間に落ちそうだし途中で落ちるっていうのも変だ

色々調べてみると「うっかり行をキャッシュしすぎてるんじゃね?」というのが出てきた

Identify a memory problem in Perl/DBI code - Stack Overflow

キャッシュする行が多すぎてメモリを使い果たしてるのではないか,とのこと

my $dbh = DBI->connect($dsn, $user, $pass, { RowCacheSize => 20 }) or die "Cannot connect to $dsn: $DBI::errstr\n";

接続時にオプションを付けることでキャッシュサイズを制限できるらしいのでやってみる
効果あるか分からないけど
ちなみに上のコードはキャッシュする行を20行に制限するものらしい
多分だけど



12/6夜追記
これ実行しても同じところで強制終了
他のところに原因があるのか……?

何となく全データを持ってきてる気がする


ここら辺が役立つかな?
明日やってみよう
YappoLogs: mysql_use_result on DBD::mysql
巨大なテーブルから SELECT する際のメモ | singular point

無かったら作成,有ったら更新(Neo4j)

neo4jにはMERGEとかいう無かったら作成,有ったら更新とかいう便利なものがあるらしいので使ってみる

公式ドキュメントの和訳見てみたら例が載ってた

MERGE (n:Person {name: {value}}) ON CREATE SET n.created=timestamp() ON MATCH SET n.counter= coalesce(n.counter, 0) + 1, n.accessTime = timestamp()

MERGEで作成または検索するパターン設定でON CREATEが作成時のパラメーター設定,ON MATCH SETが更新時のパラメーター設定なんだろう
多分

ちなみにcoalesceは最初に見つけたNULLでない値を返す関数らしい
この場合だと値が未設定の場合0を設定するってことか
便利だな

とりあえずちょっと弄ってぶちこんで確認してみる

MERGE (n:Person {name: "Alice"}) ON CREATE SET n.created=timestamp() ON MATCH SET n.counter= coalesce(n.counter, 0) + 1, n.accessTime = timestamp()


f:id:vayacico:20161130190632j:plain
ノードが作成された
createdに現在の時刻(たぶん)が格納されたっぽい


2回目の実行
f:id:vayacico:20161130190646j:plain
accessTimeに時刻が設定されてカウンターが1になった



一応3回目
f:id:vayacico:20161130190653j:plain
どうやら思った通りに動いてる
これは便利だな

MATCH (a:Person {name: "Karen"}), (b:Person {name: "Alice"}) MERGE (a)-[r:LOVES]->(b) ON CREATE SET r.created=timestamp() ON MATCH SET r.counter= coalesce(r.counter, 0) + 1, r.accessTime = timestamp()

こんな感じでリレーションにも使えるみたい
便利

MySQLの実行結果を捨てる

実際の実行時間だけを知りたかったので実行結果を捨てる方法を調べた
スクリプトから実行する予定のクエリだけど結果を表示させるとコンソールがぐわーってなるし
pagerなるものを使えば良いらしい

mysql> pager cat >/dev/null

本来は出力結果を外部コマンドで見やすくするのに使うんだとか
これで件数と時間だけが表示される

mysql> select userid from tweet group by userid having count(*) > 5;
236595 rows in set (1 min 36.63 sec)

元に戻すときは

mysql > nopager

で戻るらしい


本当はEXPLAINとか使ってスマートに色々知れるんだろうけどよくわからなかったので

mysqldの自動起動

MySQLに接続しようとしたらエラー

ERROR 2002 (HY000): Can't connect to local MySQL 
server through socket '/var/lib/mysql/mysql.sock'
 (2)

なんで落ちてんだって思ったら自動起動設定忘れてた
この前neo4jのために再起動したからそのせいか
滅多に再起動しないから気づかなかった

$ sudo chkconfig mysqld on

とりあえずこれでOKなはず


CRONでTwitterからデータ持ってきてデータベースに入れるスクリプト走らせてたけどエラーなってた
当たり前だけど
むー


標準エラー出力をメールするように設定するかねー

REST::Neo4pを使ってみる

とりあえず適当に使ってみた
クエリを投げただけだけど
色々便利そうな関数用意されてるけど直接クエリ投げた方が個人的には分かりやすい気がする

use REST::Neo4p;

REST::Neo4p->connect('http://127.0.0.1:7474','USER_NAME','PASSWORD');

my $query = REST::Neo4p::Query->new('CREATE (Person{name:"アリス",from:"イギリス"})');
$query->execute;

何も考えずに日本語使えたのは驚き
PerlMySQLの組み合わせだと散々苦しめられたから覚悟してたんだけどな
Webの管理画面で見ても文字化けせずに見れるし大丈夫っぽい


関数一覧眺めてたら思ったより使いやすいかも
気が向いたら使ってみよう

REST::Neo4pのインストール

あんまりメジャーじゃないみたいだけどPerlからNeo4jを使いたかったのでモジュールをインストールした
探したら複数見つかったけど公式で紹介されてるREST::Neo4pを入れることにした
イマイチ使い方分からないけど
REST::Neo4p - A Perl "OGM" - Neo4j Graph Database

普通にcpanを使ってインストール

cpan[1]> install REST::Neo4p

途中でユーザーネームとパスワード聞かれたので入力したらテストが失敗した

Server for live tests: [http://127.0.0.1:7474 ]  
http://127.0.0.1:7474                            
Username: [ ] testuser                                              
Pass: [ ]testpass
Result: FAIL                                     
Failed 1/36 test programs. 1/1327 subtests failed
.                                                
  MAJENSEN/REST-Neo4p-0.3012.tar.gz              
  ./Build test -- NOT OK                         
//hint// to see the cpan-testers results for inst
alling this module, try:                         
  reports MAJENSEN/REST-Neo4p-0.3012.tar.gz      
Running Build install                            
  make test had returned bad status, won't instal
l without force                                  
Failed during this command:                      
 MAJENSEN/REST-Neo4p-0.3012.tar.gz            : m
ake_test NO

納得いかないけどここは何も入れずにエンターでいいみたい

Username: [ ]                                    
                      
Pass: [ ]
./Build install  -- OK


ただ単にテストをスキップしてるだけな気もするけどテストスクリプトを実行したら動いたので大丈夫かな

Neo4j起動時のWARNING

インストール直後から発生してるワーニング

[vayacico@lavie bin]$ ./neo4j start
Starting Neo4j.
WARNING: Max 1024 open files allowed, minimum of 40000 recommended. See the Neo4j manual.Started neo4j (pid 1358). By default, it is available at http://localhost:7474/
There may be a short delay until the server is ready.
See /opt/neo4j-community-3.0.7/logs/neo4j.log for current status.

よく分からないけど開けるファイルの数が制限されてるからどうにかしろってことらしい
そんなにファイル開くのかコイツ
ワーニング出てても動くけど忘れたころに謎のエラーとして現れても嫌なので治す

ググってみたら設定ファイルに追記すればいいらしい


/etc/security/limits.conf

vayacico        hard        nofile        100000
vayacico        soft        nofile        40000
root            hard        nofile        100000
root            soft        nofile        40000

/etc/pam.d/su

session    required   pam_limits.so

Qiitaの記事だとユーザー名のところがneo4jになってたのでそこがユーザー名だということに気づくのに時間がかかった
よく考えればrootと同じところに書かれてるのでユーザー名なのは当たり前だった

あと再起動しないと適用されなかった
CRONで動かしてるスクリプトがあったから極力再起動したくなかったけど他の方法見つからなかったので仕方ない

とりあえずこれでワーニングは解消