portsnap, freebsd-updateにuser:password@proxy形式のHTTP_PROXYを読ませるには。(phttpgetを改造)


http://d.hatena.ne.jp/flageo/20060501/p1
でも書いたけど、phttpget、つまりはportsnap, freebsd-updateはhttp://user:password@proxy.server.com:8080形式の環境変数HTTP_PROXYを読んでくれない。
そこでportsnap, freebsd-updateを実行するときにはHTTP_PROXY, HTTP_PROXY_AUTHに付け替える必要があるわけだが、これが面倒くさい。
というわけで、phttpget自体を改造する。

ネタはhttp://www.freebsd.org/cgi/query-pr.cgi?pr=129431

$ uname -r
8.2-RELEASE-p3
$ grep FBSDID ./phttpget.c
__FBSDID("$FreeBSD: src/usr.sbin/portsnap/phttpget/phttpget.c,v 1.14.2.1.6.1 2010/12/21 17:09:25 kensmith Exp $");


以上の/usr/src/usr.sbin/portsnap/phttpget/phttpget.cに対して以下のような修正を。

$ diff -u phttpget.c.orig phttpget.c
--- phttpget.c.orig     2012-04-05 10:58:52.000000000 +0900
+++ phttpget.c  2012-04-05 11:04:25.000000000 +0900
@@ -44,7 +44,7 @@
 #include <sysexits.h>
 #include <unistd.h>

-static const char *    env_HTTP_PROXY;
+static char *          env_HTTP_PROXY;
 static char *          env_HTTP_PROXY_AUTH;
 static const char *    env_HTTP_USER_AGENT;
 static char *          env_HTTP_TIMEOUT;
@@ -136,6 +136,11 @@
                p = strchr(env_HTTP_PROXY, '/');
                if (p != NULL)
                        *p = 0;
+               if (strchr(env_HTTP_PROXY, '@')) {
+                       proxy_auth_user = strsep(&env_HTTP_PROXY, ":");
+                       proxy_auth_pass = strsep(&env_HTTP_PROXY, "@");
+                       p = strchr(env_HTTP_PROXY, '@');
+               }
                p = strchr(env_HTTP_PROXY, ':');
                if (p != NULL) {
                        *p = 0;

あとは/usr/src/usr.sbin/portsnap/phttpget/でmakeして、できたphttpgetを/usr/libexec配下にコピーすればOK。
当然ながらOSの更新(freebsd-updateやmake buildworld install)すると元に戻るので注意。

宅鯖FreeBSDを節電しよう

はいはいはいドーモそういうわけでですね、自宅鯖の節電をやっていきたいわけですけれども。
9.0-RELEASEのIntelで実施しましたので共有。
AMDでも9.xならなんとかできそう。
しかし8.xかつAMD CPUの方は解散で。

ただ、MLなどをつらつら見ていると、以下の設定を行っても効果がでないケースもあるようなので各自調整のこと。(例: C2よりC3の方がなぜかCPU温度が上がるとか)


やること。

やることをさっさと書く。


CPU throttlingを無効に。
/boot/loader.confで指定。
具体的にはp4tccを無効に。sysctlで調べて複数あればすべてつぶすこと。

以下の例では二つ。

$ sysctl -a|grep "p4tcc"
dev.p4tcc.0.%desc: CPU Frequency Thermal Control
dev.p4tcc.0.%driver: p4tcc
dev.p4tcc.0.%parent: cpu0
dev.p4tcc.0.freq_settings: 10000/-1 8750/-1 7500/-1 6250/-1 5000/-1 3750/-1 2500/-1 1250/-1
dev.p4tcc.1.%desc: CPU Frequency Thermal Control
dev.p4tcc.1.%driver: p4tcc
dev.p4tcc.1.%parent: cpu1
dev.p4tcc.1.freq_settings: 10000/-1 8750/-1 7500/-1 6250/-1 5000/-1 3750/-1 2500/-1 1250/-1


以下のように。

/boot/loader.conf:
hint.p4tcc.0.disabled=1
hint.acpi_throttle.0.disabled=1
hint.p4tcc.1.disabled=1
hint.acpi_throttle.1.disabled=1


C-states設定


/etc/rc.confに設定を加え、C3まで落ちるようにする。
RELEASE、CPUに応じて/boot/loader.confに追加の設定を加える。


9.x, intelの場合

/etc/rc.conf:
performance_cx_lowest="C3"
economy_cx_lowest="C3"


8.x, intelの場合

/etc/rc.conf:
performance_cx_lowest="C3"
economy_cx_lowest="C3"

/boot/loader.conf:
hint.apic.0.clock=0
kern.hz=100
hint.atrtc.0.clock=0


9.x、AMDの場合

/etc/rc.conf:
performance_cx_lowest="C3"
economy_cx_lowest="C3"

/boot/loader.conf:
hint.apic.0.clock=0

再起動。
sysctlで確認

p4tccが表示されない。

$ sysctl -a|grep p4tcc
$


C3が有効になっていて、再起動直後ということもあるけど、システムがほとんどC3ステートにいることが分かる。

$ sysctl -a|grep cx
hw.acpi.cpu.cx_lowest: C3
dev.cpu.0.cx_supported: C1/1 C2/1 C3/57
dev.cpu.0.cx_lowest: C3
dev.cpu.0.cx_usage: 0.00% 0.06% 99.93% last 432us
dev.cpu.1.cx_supported: C1/1 C2/1 C3/57
dev.cpu.1.cx_lowest: C3
dev.cpu.1.cx_usage: 0.00% 0.10% 99.89% last 907us


上記設定の意味

ではその意味などを。


1: CPU throttlingの停止について
powerdはCPUの周波数変更(CPU throttling)とEISTの組み合わせ。
周波数変更は単純に周波数だけ変更する。
EISTは周波数と電圧を変更する。
前者の周波数変更は、どうも周波数を実際に「落とす」わけではなく、周波数はそのままに「動作をするのはクロック8回に1度な」というように単に動作タイミングを間引いているだけらしい。
したがって、発熱を抑える効果はあっても(CPU Frequency Thermal Control)、電力消費を抑える効果は薄い。
効果のない選択肢があっても無駄なだけなのでバッサリ切る。


2: C-statesの設定
C-statesは以下の通り。
下に行けば行くほど節電できる。システムは低負荷時にあらかじめ設定されたC-states(C状態)まで動作を落とす。
デフォルトはC1。C2, C3まで落とすようにするには/etc/rc.confで指定する。

C1: CPUコアの一部のクロックを停止する。
C2: CPUコアのクロックを停止する。
C3: CPUの内部クロック停止、電圧を下げ、システムバスから切り離す。

2-1: AMDの制限
AMDの場合、詳細なC StatesはOSに対して隠蔽される。代わりにC1Eというstateがある。
OSからはマシンがC2にいようが、C3にいようが、C1Eとしてしか分からない。
後述するようにC3ではタイマーに関しての考慮が必要になるのだが、OSから見えないのではどうにもできない。したがってAMDとRELEASEの組み合わせにより、具体的には8.xとAMD CPUではC1Eへの移行が抑止される。


2-2: OS, RELEASEの組み合わせごとのC3の設定
節電の観点ではC3が一番良いが、この状態だとAPICタイマーも機能しなくなる。
APICタイマーが止まるとスケジューリングが出来ず、復帰もできなくなる。
したがって、APIC以外のタイマーを使う必要がある。
RELEASE、CPUにより回避策に違いが生まれる。


8.x intelにおいては、APICを使うこと自体を止めれば別タイマ(i8254, RTC)を使ってくれる。
ただ、C3からの復帰に時間がかかってしまうので(といってもusのレベル)、/boot/loader.confで調整を行う。


9.x intelにおいては、eventtimersという適切なタイマを選んでくれる仕組みがあるので特に考慮不要。


8.x amdにおいては、
OSから分からないところでC3に遷移してAPICタイマを止められてはかなわないので、OSレベルでC1E機能が抑止される。
つまりC-statesによる節電は無理。これが解散の理由。


9.x amdにおいては、
APICタイマが有効なときのみC1E機能が抑止される。
だからAPICタイマを無効にすればOK。


参考

CPU throttling
http://en.wikipedia.org/wiki/Dynamic_frequency_scaling

C-States
http://okwave.jp/qa/q4539201.html

EIST
http://ja.wikipedia.org/wiki/Intel_SpeedStep_%E3%83%86%E3%82%AF%E3%83%8E%E3%83%AD%E3%82%B8

FreeBSDをインストールしたらやること。(no GUI編)

FreeBSDをインストールしてやることをまとめたよ。


まずrootでログイン

シェル、sudo、screen、vim-lite(日本語OKなvi)をインストール。

# pkg_add -r bash sudo screen vim-lite

以降、viはvim等と読み替えておくれ。

# vipw

自アカウントのシェルを変更。

# vi /etc/group

wheelに自アカウントを追加。


sudoが使えるように。
これ以降、原則としてrootは使わない。

# visudo
(以下の%wheelの行をアンコメントする。)
## Uncomment to allow members of group wheel to execute any command
%wheel ALL=(ALL) ALL

自分のアカウントでログイン。

ホームディレクトリの.profileに以下を追加。
言語設定とパッケージの取得先変更。

#
# modified
#
LANG=ja_JP.UTF-8;export LANG
PACKAGEROOT="ftp://ftp2.jp.freebsd.org";export PACKAGEROOT


上記設定を読み込み。

$ . ~/.profile


portsの更新

$ sudo vi /etc/portsnap.conf
(portsnapの取得先をfreebsd.orgからallbsd.orgへ変更(感謝))

#SERVERNAME=portsnap.FreeBSD.org
SERVERNAME=portsnap.allbsd.org

既存のportsは一回捨てる。
rmするのも時間がかかるので、いったんmvして消す。
で、portsnapで取り直し。

$ sudo mv /usr/ports /usr/ports.org
$ sudo rm -Rf /usr/ports.org
(このあとバックグラウンドにするとよい)
$ mkdir /usr/ports
$ sudo portsnap fetch extract

時間がかかるのでさらにターミナルを起動。


起動時のサービスの設定

$ sudo vi /etc/rc.conf
以下を(なければ)追加。

sshd_enable="YES"
powerd_enable="YES"	#低負荷の時にクロック等を下げる
powerd_flags="-a adp -n adp"
ntpdate_hosts="ntp.jst.mfeed.ad.jp"	#時刻合わせ
ntpdate_enable="YES"

#sendmail swtich. see rc.sendmail(8) sendmailを止める。
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"


powerd, ntpdateを起動。sendmailはまあ...後で再起動か。

$ sudo service powerd start
$ sudo service ntpdate start


locateデータベースの作成
放っておけば一週間に一回更新してくれるのだが、すぐに使いたいので。

$ sudo /etc/periodic/weekly/310.locate


あとはports管理とか。

$ sudo pkg_add -r psearch pkg_replace portmaster portaudit

でかい言語系。

$ sudo pkg_add -r perl python

とりあえずこんなもん。

起動スクリプト操作コマンドservice(Linuxのchkconfigの簡易版)

FreeBSDにおいて、各種サーバソフトウェアの起動・停止を行う起動スクリプトは/etc/rc.d、/usr/local/etc/rc.dに格納されている。
いちいち/usr/local/etc/rc.d/apache22 startなどとキーを叩くのは面倒で仕方がない。
そこでportsにあるbsdadminscriptsなどを使っていたのだが、ふと気が付くと7.3あたりからserviceというコマンドが作られたようだ。

使い方。

書式。

 service <起動スクリプト> start|stop|restart等々

使用例

$ sudo service dovecot status
Password:
dovecot is running as pid 1026.
$ sudo service dovecot restart
Stopping dovecot.
Waiting for PIDS: 1026.
Starting dovecot.

注意点としては、引数で与えるのはあくまでも起動スクリプト名であって、サーバソフトウェアの名前ではない、という点。
例えば、dhcpdだとisc-dhcpdで指定しないといけないが、それを思い出せないこともしばしば。
だから後述の使用法も使って、起動スクリプト名を調べるとよい。


そのほかの使い方:起動スクリプトに関する情報が得られる。

service -e
 有効になっているサービスを表示する。
 起動順(rcorder)に表示


service -r
 無効になっているものも含めてサービスを表示する。
 起動順(rcorder)に表示。
 もちろん無効になっているものは、もしも有効だったら
 という仮定で。

service -l
 rc.dディレクトリの下にあるファイルをすべてリストする。
 /etc/rc.dのほか、たとえば/usr/local/etc/rc.dなど。


-v
 ほんの少しだけ説明が増える。
 (試してみたら本当に少しだけだった)

例えば。-rだと、-eのときにはない起動スクリプトも表示されていることが分かる。

$ service -e|grep "/usr/local"
/usr/local/etc/rc.d/mrtg_daemon
/usr/local/etc/rc.d/jenkins
/usr/local/etc/rc.d/dovecot
/usr/local/etc/rc.d/clamav-clamd
/usr/local/etc/rc.d/clamav-freshclam
/usr/local/etc/rc.d/apache22
$ service -r|grep "/usr/local"
/usr/local/etc/rc.d/svnserve
/usr/local/etc/rc.d/rsyncd
/usr/local/etc/rc.d/rrdcached
/usr/local/etc/rc.d/munin-node
/usr/local/etc/rc.d/mrtg_daemon
/usr/local/etc/rc.d/jenkins
/usr/local/etc/rc.d/htcacheclean
/usr/local/etc/rc.d/dovecot
/usr/local/etc/rc.d/clamav-clamd
/usr/local/etc/rc.d/clamav-freshclam
/usr/local/etc/rc.d/apache22

ZFSの重複ファイル節約機能dedupがすげえ(ただしメモリ大尽に限る)

最初にお断りするが、十分なメモリ、あるいはSSDをお持ちでない方は帰っていただいて結構です。


Dedupとは

ZFSにはdedupという機能がある。
その機能を有効にすると、例えばここに1GBのファイルが一つあるとして、それをコピーしても、場所が同じpool内である限り、1GBのディスクしか消費しない。


何それただのハードリンクと思うのは早い。


仮に同一のファイルA, Bがあるとする。いずれも1GB。
ハードリンクすればディスク消費量は1GBだ。
さてここで、ファイルBの一部、1bitだけを変えたいとする。
もはやハードリンクはできず、別個のファイルとして扱うことになる。
したがってディスク消費は2GB。


ではdedupだとどうなるか。
1bit違う1GBのファイル二つがあっても、なんと1GBと128KBだけしかディスクを消費しないという驚きの仕組み。


どういうことかというと、dedupはファイルが同じかどうかをブロックごとに判断するということ。
先の例でいえば、異なる1bitを含むブロック分だけを追加で確保し、それ以外はファイルAと同じものを使う。
なお、ZFSでブロックサイズは512B〜128KB。
つまり大目に見積もっても1GBと128KBだけの消費でよいわけ。


種明かし:テーブルと大量のメモリ

なぜそんなことができるのか。

ZFSはプール上にあるデータのすべてのブロックのハッシュをメモリ上に持っている。
あるファイルをディスクに書き込む前に、ファイルをブロックに分解しハッシュテーブルと照合、書き込み要否を判断するという仕組み。


問題はメモリ上に置くテーブルのサイズだ。
dedupを有効に使うには、テーブルを置けるほど十分なメモリが必要になる。
しかし、のちほど見積もりをするが、数TBのディスクを考えるとメモリで賄うのは少々厳しい。
当然、メモリをこればっかりに使うわけにもいかないのだし。
もちろん、テーブルをハードディスクに置くことはできるが、ファイルを書き込むたびにディスク上のハッシュテーブルを参照することになる。
つまりすっごく遅くなる。
よろしい。ならばSSDだ。

とはいえ、Dedupの目的がディスクの容量節約ならば、安いHDDケチってメモリ、SSD無理して買うのも本末転倒という話になってくる。
月並みだけど、よく考えた方がいいよね。


Dedupの見積もり。

では仮に2TBのデータが詰まったZFSでDedupしたら、どれくらいのメモリが必要か。

ハッシュテーブルは1ブロックにつき320Bytes。

zfsのブロックサイズは512Bから128KBで可変。
ざっくり64KBとみなす。
では計算。

2TB=1024 * 1024 * 1024 * 2 = 2147,483,648KB。
2TB/64KB=33,554,432 blocks

2TBは33,554,432 blocks。
1blockあたり320Bytesなので、かければテーブルに必要なサイズが出る。

33,554,432 blocks * 320 Bytes = 10,737,418,240 = 10GBytes


はい解散。
と言いたくなるレベルですな。
念のため記載するが、上記は2TBのデータを使っているときのdedupテーブルの試算。
2TBのプールに100bytes程度のファイル一つ置いただけなら、ハッシュテーブルは320Bytes程度。


Dedupの活きる道

そもそも2TB全部にDedupするのが間違いであった。
Dedupを活かしたいなら、扱うファイルで決めるのも手。
ざっくり言えばオフィスドキュメント、仮想マシンイメージなど、重複が見込まれるファイルを多く保管するディレクトリに対してのみDedupするとよいでしょう。
一方で動画などはあまり有効ではないでしょう。

なお、プールでDedupするとどれくらい得か、というのは調べることができる。
zdbにプール名を与えてやればいい。
一番下に重複具合が表示される。以下の例では1.06。あまり意味はないってことですな。
ちなみに、あるプールに同一のファイルを3つだけ置くとここが3.00になる。

$ sudo zdb -S vault
パスワード:
Simulated DDT histogram:

bucket              allocated                       referenced
______   ______________________________   ______________________________
refcnt   blocks   LSIZE   PSIZE   DSIZE   blocks   LSIZE   PSIZE   DSIZE
------   ------   -----   -----   -----   ------   -----   -----   -----
     1    8.22M   1.02T   1.02T   1.02T    8.22M   1.02T   1.02T   1.02T
     2     406K   50.6G   50.6G   50.6G     815K    102G    102G    102G
     4      185   17.1M   17.1M   17.1M      835   73.6M   73.6M   73.6M
     8      146   14.2M   14.2M   14.2M    1.75K    182M    182M    182M
    16       17   8.50K   8.50K   8.50K      407    204K    204K    204K
    32      150   16.7M   16.7M   16.7M    5.43K    600M    600M    600M
    64        9    132K    132K    132K      820   9.49M   9.49M   9.49M
   128        6      3K      3K      3K    1.02K    521K    521K    521K
   256        3    129K    129K    129K      884   40.5M   40.5M   40.5M
   64K        1    128K    128K    128K    73.4K   9.18G   9.18G   9.18G
 Total    8.62M   1.07T   1.07T   1.07T    9.10M   1.13T   1.13T   1.13T

dedup = 1.06, compress = 1.00, copies = 1.00, dedup * compress / copies = 1.0

DedupのONのしかた

まあzfs set dedup=ONとかすればいいんだけど、現状使う予定もないので詳しく調べてない。

trは一文字ごとに判断する件について

$ cat sample.txt
<a><b>

上記のテキストに対して以下のtrを実行するとどうなるか。

tr "ab" "cd"


試してみる。

$ tr "ab" "cd" < ./sample.txt
<c><d>

げえっ。
つまり、trは1文字ずつ判断する。
 a→cに変わり、
 b→dに変わる。
 ※「ab」を置換しない点に注意。


応用。
同じファイルに対して。

$ tr -d "<>" < sample.txt
ab

「<>」ではなく「<」「>」を消去していることに注意。

/var/logの下がえらいことになっていたでござる。(あるいはFreeBSDでログのローテーション設定をするには(logrotateではなくnewsyslog))。

ある日、ふと/var/logの下を見てみたら、1.5GBytesに膨れ上がった某ログファイルがあって腰を抜かした件について。


思えば、サーバソフトウェアなどでは、インストールしたらまずそのものの設定で頭が一杯だ。
一方で、いわゆるシモの世話といいますか、吐き出すログの設定には頭が回ってなかったことに深く反省するのであります。


俺の例でいえば、apacheclamav、dhcpdのログが手つかずでありました(冒頭、1.5GBytesになっていたログはdhcpdのもの)。
portsから入れたサーバのログは、いちど確認したほうがいいだろう。
基本は/var/logの下に出力されるが、/usr/local/var/logが(あれば)見た方がいいし、場合によっては思わぬところに吐き出されてる可能性もある。


newsyslogd

さて、FreeBSDではログのローテートはnewsyslogdが行う。Linuxではlogrotateにあたるもの。


handbookではこのへん
英語(推奨)
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/configtuning-configfiles.html
日本語
http://www.freebsd.org/doc/ja_JP.eucJP/books/handbook/book.html#CONFIGTUNING-CONFIGFILES


newsyslogの設定サンプル

man newsyslog.confを見ればだいたい分かる。以降、英文はここからの引用。
http://www.freebsd.org/cgi/man.cgi?query=newsyslog.conf&apropos=0&sektion=0&manpath=FreeBSD+9.0-RELEASE&arch=default&format=html


以下の順番で並べるだけ。間はスペースで埋めること(separated with whitespace)。

# filename          [owner:group]    mode count size when [ZB] [/pid_file] [sig_num]

以下、サンプル。

/var/log/local7.log    600  10 1024 * JC 

/var/log/local7.logが、1MBytesを超えた時点でローテーション。
生成されたログのパーミッションは600で、bzip2で圧縮され(J)、10個保存される。

/var/log/httpd-access.log    644  7 * @T03 JC

apacheのログを毎日午前3時にローテーション、圧縮して7日分残す。

設定を変えたらnewsyslogdを再起動。

# /etc/rc.d/newsyslog restart
Creating and/or trimming log files.
#


設定について


filename
 その名の通り。

[owner:group]
 省略可。アーカイブ後ファイルの所有ユーザとグループ

mode
 ログファイルとアーカイブ後ファイルのパーミッション
 サーバソフトが作るオリジナルのパーミッションと合わせておくのがよい。
 というのも、newsyslogdがログをローテーションするときに新しいログファイルを作るから。
 owner:groupにはなく、こちらにだけ「ログファイル」という記載があるのはなぜでしょうな。

count
 残す「アーカイブ後の」ログファイル数。
 3なら、アーカイブされたログが3つになる。

size
 このサイズを超えたときにローテーションされる。
 キロバイトで指定。
 アスタリスク(*)の場合には、サイズベースでのローテーションはしない。

when
 ローテーションする時間、時刻契機を指定。
 インターバル、時刻を指定できる。
 書式は二つ。後述する。
 注意すべき点は、newsyslog自体が一時間に一回しか起動しないこと。
 これはつまり以下のような動作となる、と理解した。
 ・仮に、newsyslogdが毎時0分に起動し、かつ
 ・毎時1分にローテーションする設定にした場合、
 →例えば、1時1分ではなく、2時にローテーションが発生する。

newsyslog.conf(5)より抜粋

If a time is specified, the log file will only be trimmed if newsyslog(8) is run within one hour of the specified time. If an interval is specified, the log file will be trimmed if that many hours have passed since the last rotation.

 書式

 @で書くもの、$で書くものの二つ。
 @は、[[[[[cc]yy]mm]dd][T[hh[mm[ss]]]]]
 $は、[Dhh], [Ww[Dhh]]と[Mdd[Dhh]]
 サンプルを見るのが一番よい。(これもmanから抜粋)

 $D0 毎日午前0時。@T00と同じ意味
 $D23 毎日23時。@T23と同じ意味
 $W0D23 毎週日曜23時
 $W5D16 毎週金曜16時
 $M1D0 毎月1日の午前0時。@01T00と同じ意味
 $M5D6 毎月5日の午前6時。@05T06と同じ意味

flags 一部のみ。基本JCでよい。
 J ログをbzip2で圧縮。Zならgzip。Xならxz。
 C ログが存在しない場合に作る。

 G パターンにマッチしたログファイルを対象にできる。
 
pid_file
 通常、ログをローテーションした後はsyslogdにシグナルが送られる。
 syslogd以外のプロセスにシグナルを送りたい場合には、プロセスの
 pidが書かれたファイルをここで指定する。


以上