SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|

2008-02-09(Sat) パルスを数えまくる

  長らくチマチマと作業を進めてきた、家庭用電源の50Hzで時計を作るプロジェクトであるが、とりあえず50Hzをカウントして時刻を表示する、というところまできた。ずっと疑問に思っていた電源の50Hzの精度であるが、脇に腕時計を置き、秒単位のズレを目視で確認した限りでは、1時間で0.5秒程度のズレが生じるようだ。

  画像の説明

  予想よりもかなり正確だという印象だが、もしかしたら完璧な精度を持っているかもしれない、とも思っていたので、その意味では予想を裏切られた。

  しかし、1時間で0.5秒ということは、24時間で12秒、5日で1分、1ヶ月で6分……うーむ、100円で売っている腕時計でも、平均月差は30秒程度だろうから、ちょっとイマドキの時計としては使い物にならない感じだ。でも、敢えてコレで行ってみようかな、と思う。日や季節によっても多少は違ってくるかもしれず、それを体感してみたいという気持ちもあり……

  画像の説明

  ……こっちの「コレ」で容易に時刻修正ができるようにしてあるなら、それはそれで修正作業自体がちょっと楽しめるんじゃないか、と思ってのことだ。

  その「コレ」とは、ロータリーエンコーダ。ふたつのパルスを読み取ることで、回転方向と速度を検出するセンサだ。かなり前にアルカノイドのパドルコントローラを作ろうと思って実験用に購入しつつ、放置してあったパーツだ。

  扱いは難しいんじゃないか? 秋月ではそれだけのキットも出ているくらいだし……と、ちょっと腰が引けていたのだが、実はムチャクチャ簡単である。実は、以下の十数行のコードでハンドリングできるのだ。

RotaryDecode
	SWAP	(GPIO)>A
	AND	A, 0000_0011b
	LD	(BUF), A
 
	RR	(BUF)>A			; 観測値を正規化
	AND	A, 0000_0001b
	XOR	(BUF), A>A
	SUB	(LAST), A		; 前回 - 今回
 
	BIT	0, (LAST)
	JP	Z, RotaryDecode1	; 不動 or 無効
 
	SKIPRES	1, (LAST)
	INC	(VAL)			; 正転
	SKIPSET	1, (LAST)
	DEC	(VAL)			; 逆転
RotaryDecode1
	LD	(LAST), A

  珍しく電車の中で組んだコードがそのまま動いた。先日完成した7セグモジュールに値を出力させてみる。クリクリクリ。おぉー、気持ちいい。

  ロータリーエンコーダは、ボタン等のスイッチに比べると、非常に人間のフィーリングにマッチするインタフェイスだ。これから積極的に使っていこう。

  さて、ハードウェア工作とは何の関係もないが、最近、ウチのサーバがよく落ちる。

  messagesをみると、OOM-Killerが動いているので、何かのプロセスのリークか何かだろうと判断し、たいして気にもせず強制再起動で回避してきたが、最近、落ちる頻度が増してきて、リセットボタンを押すのがうっとおしくなってきた。特に設定をイジっていないのに頻度が増すということは、内部要因ではない可能性が高いということだ。どうにかせねばなるまい。

  それ以前に、お客のLinuxサーバをどうにかすることで飯を食っているのに、自分のサーバをボコボコと落としているというのは、カッコ悪い。まさに医者の不養生なので、どうにかするコトにする。まずは、ロギングツールを稼動……した途端、都合よく、すぐ再現した。どれどれ。

  なんと、バカみたいにhttp要求を連続(秒間20とか)で投げ続けるアホがいた。rubyのcgiプロセスが溢れかえっていて、落ちる寸前にはロードアベレージは数百に達している。tdiaryはかなり重く、メモリも食うので、秒間1アクセス程度にしてもらわないと困るんだがなぁ。どうしようかなぁ。いくつか案を考える。

  1. アホのIPをハジく
  2. Apacheに負荷制御モジュールを入れる
  3. ユーザの同時プロセス起動数を制限する
  4. iptablesに連続アクセス防御ルールを書く

  1はアホが複数現れるとイチイチ面倒。2はモジュールを入れるのが面倒。4は画像が多いウチのサイトには適応しづらい。というわけで、3がいい。連続でCGIにアクセスされた場合、CGIの起動を故意に失敗させ、Apacheには内部エラーとして処理させる。結果としては負荷制御になるワケだ。

  ユーザの同時プロセス起動数といえばulimit -uのmax user processesなのだが、これは環境変数みたいなものなので、CGIが起動してから設定しても遅い。そもそも、CGIの起動を抑制するという目的に合わない。Apacheの起動時に指定してしまう手もあるが、Apache自身に制限が加わるのは困る。

  とりあえず、現在の設定値を確認しよう。CGIの中に以下の1行を追加する。

print `/bin/bash -c 'ulimit -a'`.gsub(/\n/, "<BR>\n")

  CGIをリロード……うむ。max user processesは数千だ。これじゃ、負荷制御にはならない。

  ただ、これをApacheから変更させるのは難しそうだ。ほかの方法を探すか……あったぞ、RLimitNPROC。Apacheの設定パラメータだ。これをhttpd.confに書けばいいのか……

RLimitNPROC 20

  ……っと。Apacheを再起動。これで設定は有効になったはず……なのだが、確かめようがないな。ん? もしかして? と、思って、さっきのCGIをリロードしてみる……

max user processes (-u) 20

  ……なんと。RLimitNPROCって、内部的にはulimitを設定しているだけじゃないの。

  実際の効果のほどは、まだわからないが、これでしばらく落ちなければ効果あり、としよう。では。