プロキシ(Squid)を最新化
参照:squid-cache.org
Blogの常時SSL化やPHPの最新化ができたので、次はプロキシ(Squid)を最新化してみた
Blogの常時SSL化やPHPの最新化ができたので、次はプロキシを最新化してみた。ウチのサーバー(Mac mini G4)ではフォワードプロキシとして Squid を使用している。
Squid公式ホームページ:<http://www.squid-cache.org>
ウチのサーバーの Squid は Ver.3.1.23 → 3.5.8 → 3.5.28 と更新して来た。今回は、2019/2/19 にリリースされたばかりの最新安定版 squid-4.6 へ一気に移行してみた。Ver.3系の Squid はC言語で記述されていたが、Ver.4系ではC++で書き直され、かなり大規模な改修が行われたらしい。
実は今まで Ver.4.0〜4.5 についても時々味見していたのだが、少しソースの修正が必要だったり、動かすとすぐに異常終了したりデッドロックしたりで、原因を調べるのも面倒なので、ずるずると Ver.3系を使い続けていたのだった。とは言え、遂に Ver.3.5 も Old Versions へ仲間入りし、これで全Ver.3系が EOLになってしまったようなので、重い腰を上げて Ver.4系へ移行することにした次第である。
squid-4.6 をダウンロードして解凍(安定版ではないかもしれないが、現時点では squid-4.6-20190225r8521ecd21 が最新版かな?)。
$ bzcat squid-4.6.tar.bz2 | tar xf -
$ cd squid-4.6
|
ビルドスクリプトは以下のとおり。
#!/usr/local/bin/bash -x
export MACOSX_DEPLOYMENT_TARGET=10.4
export GCC="/usr/local"
export SSL="/usr/local/libressl"
export PATH="${GCC}/bin:$PATH"
export DYLD_LIBRARY_PATH="${GCC}/lib:$DYLD_LIBRARY_PATH"
export PKG_CONFIG_PATH="${SSL}/lib/pkgconfig:$PKG_CONFIG_PATH"
export PREFIX="/usr/local/squid-4"
./configure \
--prefix=${PREFIX} \
--with-large-files \
--with-openssl=${SSL} \
--without-mit-krb5 \
--without-heimdal-krb5 \
CC="${GCC}/bin/gcc" \
CXX="${GCC}/bin/g++" \
CPP="${GCC}/bin/cpp" \
CFLAGS="-O2 -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" \
CXXFLAGS="-O2 -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" \
CPPFLAGS="-I${SSL}/include -I/usr/local/include -I/usr/include" \
LDFLAGS="-L${SSL}/lib -L/usr/local/lib -L/usr/lib -lresolv"
make all
注)「¥」は実際には半角の「\」(バックスラッシュ)
インストール場所は"/usr/local/squid-4"。SSLライブラリはLibreSSLの方を使用している。
ビルドしてインストール。
$ ./build.sh
$ sudo make install
|
ビルドにはかなり時間がかかった。インストール後、古い Squid("/usr/local/squid")のディレクトリ名を変更し、新しい Squid-4 の方にシンボリックリンクを張ることで古い環境を保存しつつ、新しい環境へ移行させるようにする。
$ cd /usr/local
$ sudo mv ./squid ./squid-3.5
$ sudo ln -s ./squid-4 ./squid
|
設定ファイル("/usr/local/squid-4/etc/squid.conf")は squid-3.5の時と殆ど同じで、"visible_hostname unknown" という設定項目が廃止になったようなので、それをコメントアウトした程度。設定ファイルのチェック結果も以下のとおり問題なし。
$ sudo /usr/local/squid-4/sbin/squid -k parse
2019/02/20 20:31:07| Startup: Initializing Authentication Schemes ...
2019/02/20 20:31:07| Startup: Initialized Authentication Scheme 'basic'
2019/02/20 20:31:07| Startup: Initialized Authentication Scheme 'digest'
2019/02/20 20:31:07| Startup: Initialized Authentication Scheme 'negotiate'
2019/02/20 20:31:07| Startup: Initialized Authentication Scheme 'ntlm'
2019/02/20 20:31:07| Startup: Initialized Authentication.
2019/02/20 20:31:07| Processing Configuration File: /usr/local/squid-4/etc/squid.conf (depth 0)
〜略〜
2019/02/20 20:31:07| Initializing https:// proxy context
|
試しに起動させてみたところ問題が発生!
$ sudo /usr/local/squid-4/sbin/squid -N -s -d 1
|
で、何のメッセージも出さないままハング状態になった。ターミナルをもう1枚開いて、psでsquidのプロセス見ると
$ ps -aux | grep squid
squid 6117 96.6 0.7 71756 7636 p1 R+ 2:53PM 0:21.07 /usr/local/squid-4/sbin/squid -N -s -d 1
|
こんな状態でだんまりになってしまい、当然Proxyとしても動作していない(*1)。
そこでデバッガをアタッチして、どこで止まっているのかを調べてみた。
$ sudo gdb -p 6117
Attaching to process 6117.
Reading symbols for shared libraries . done
Reading symbols for shared libraries ................ done
0x008e5dbc in execute_cfa_program ()
(gdb) where
#0 0x008e5dbc in execute_cfa_program ()
#1 0x008e76fc in _Unwind_RaiseException ()
#2 0x018175b8 in __cxa_throw (obj=0x25803a0, tinfo=0x5148bc, dest=0x1fd840 <TextException::~TextException()>) at ../../../../gcc-5.5.0/libstdc++-v3/libsupc++/eh_throw.cc:82
#3 0x001fb7dc in File::open ()
#4 0x001fc1c4 in File::File ()
#5 0x001fc23c in File::Optional ()
#6 0x000d6ab8 in Instance::ThrowIfAlreadyRunning ()
#7 0x000df714 in SquidMain ()
#8 0x00441e5c in main ()(gdb)
|
SquidMain() の中なので、本当に起動した直後っぽい。止まっているソース上の箇所は以下と思われる。
[main.cc]
int
SquidMain(int argc, char **argv)
{
〜略〜
// Master optimization: Where possible, avoid pointless daemon fork() and/or
// pointless wait for the exclusive PID file lock. This optional/weak check
// is not applicable to kids because they always co-exist with their master.
if (opt_send_signal == -1 && IamMasterProcess())
Instance::ThrowIfAlreadyRunning(); ←ここから呼び出している
[Instance.cc]
void
Instance::ThrowIfAlreadyRunning()
{
const auto filename = PidFilename();
if (filename.isEmpty())
return; // the check is impossible
if (const auto filePtr = File::Optional(filename, File::Be::ReadOnly().locked())) { ←この場所で停止
const std::unique_ptr pidFile(filePtr);
ThrowIfAlreadyRunningWith(*pidFile);
} else {
// It is best to assume then to check because checking without a lock
// might lead to false positives that lead to no Squid starting at all!
debugs(50, 5, "cannot lock " << TheFile << "; assuming no other Squid is running");
// If our assumption is false, we will fail to _create_ the PID file,
// and, hence, will not start, allowing that other Squid to run.
}
}
どうやら pidファイルの有無を調べて squidの二重起動を抑止する処理のようだ。pidファイルとは、中に squidのプロセスIDが入っているだけのファイルで、デフォルトのファイル名は "squid.pid"になる。場所は"/var/run/squid.pid"だったり、ウチの場合は"/usr/local/squid-4/var/run/squid.pid"になっていた。
このファイルが無いので、新規に作成(open)しようとする際に例外を上げようとして何故かそこで停まっているように見える。稀に、その先の pthread_mutex_lockで停まっているように見える事もあるので、例外を上げる際のスレッド排他処理でロックが獲得できずに永久待ちになっているのかもしれない。と言った現象は見当つくのだが、原因となるととんと分からない。何となくC++ライブラリのバグっぽい気はするのだが・・・
そこで回避策を探ってみた。pidファイルが無いときに現象が起きるのであれば、事前に pidファイルを作っておけばどうか?例えば、
$ sudo touch /usr/local/squid-4/var/run/squid.pid
$ sudo chown squid:squid /usr/local/squid-4/var/run/squid.pid
$ sudo /usr/local/squid-4/sbin/squid -N -s -d 1
|
という具合。しかし、これでも現象は変わらなかった。色々試行錯誤した結果、pidファイルの中身が空ではダメで、存在しないプロセスIDの値など何かしら入っていれば現象を回避できることが判った。具体的には以下のようにすると正常に起動できた。
$ su
# echo 99999 >/usr/local/squid-4/var/run/squid.pid
# chown squid:squid /usr/local/squid-4/var/run/squid.pid
# /usr/local/squid-4/sbin/squid -N -s -d 1
|
そのような訳で、launchdから直接squidをキックするのではなく、起動スクリプトを間にかませることにした。起動スクリプト"/usr/local/squid-4/sbin/launch_squid.sh"はこんな感じになった。
#!/usr/local/bin/bash
SQUID_DIR="/usr/local/squid-4"
SQUID_PID="${SQUID_DIR}/var/run/squid.pid"
SQUID="${SQUID_DIR}/sbin/squid"
/bin/sleep 30
if [ ! -e ${SQUID_PID} ]; then
echo 99999 > ${SQUID_PID}
chown squid:squid ${SQUID_PID}
fi
${SQUID} -N -s -d 1
exit $?
launchdのファイル"/Library/LaunchDaemons/org.squid.plist"は、以下のようにして上記のスクリプトをキックするようにした。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>GroupName</key>
<string>squid</string>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.squid</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/usr/local/squid-4/sbin/launch_squid.sh</string>
</array>
<key>ServiceIPC</key>
<false/>
<key>UserName</key>
<string>squid</string>
</dict>
</plist>
|
以上で、プロキシSquid-4.6への移行も完了した。これでWeb環境の最新化は、ほぼ完了かな?
備考(*1):
正常に動作する場合は、以下のようなメッセージが出力されて、
2019/02/22 19:34:24| Created PID file (/usr/local/squid-4/var/run/squid.pid)
2019/02/22 19:34:24| Set Current Directory to /usr/local/squid-4/var/cache/squid
2019/02/22 19:34:24| Starting Squid Cache version 4.6 for powerpc-apple-darwin8.11.0...
2019/02/22 19:34:24| Service Name: squid
2019/02/22 19:45:33| Process ID 604
〜略〜
2019/02/22 19:34:26| Beginning Validation Procedure
2019/02/22 19:34:26| Completed Validation Procedure
2019/02/22 19:34:26| Validated 270 Entries
2019/02/22 19:34:26| store_swap_size = 3836.00 KB
2019/02/22 19:34:26| storeLateRelease: released 0 objects
|
少なくともこれだけのプロセスが生成されているはずなのだ。
squid 370 0.0 1.1 73644 11692 ?? S 3:49PM 0:00.40 /usr/local/squid-4/sbin/squid -N -s -d 1
squid 385 0.0 0.3 42680 3120 ?? SNs 3:49PM 0:00.26 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Support/mdimportserver
squid 391 0.0 0.1 53064 1220 ?? Ss 3:49PM 0:00.02 (logfile-daemon) /usr/local/squid-4/var/logs/access.log
squid 392 0.0 0.1 53044 1228 ?? Ss 3:49PM 0:00.02 (unlinkd)
|
|