Hatena::ブログ(Diary)

(ひ)メモ このページをアンテナに追加 RSSフィード

2007-10-26 (Fri)

いっぱい接続したいの

とあるホストに、TCP接続を張っては切るという処理をぐるんぐるん繰り返すベンチマーク的なプログラムを書いて動かしました。

最初のうちは期待した通りの動作をしてるんですが、途中から対向のホストにTCP接続できなくなってエラー出まくり。

$ netstat -tna | grep TIME_WAIT | wc -l
28230

これが原因ぽい。

KERNEL_SOURCE/Documentation/networking/ip-sysctl.txt によれば、

ip_local_port_range - 2 INTEGERS
        Defines the local port range that is used by TCP and UDP to
        choose the local port. The first number is the first, the
        second the last local port number. Default value depends on
        amount of memory available on the system:
        > 128Mb 32768-61000
        < 128Mb 1024-4999 or even less.
        (snip)

ということで、計算してみると、

$ cat /proc/sys/net/ipv4/ip_local_port_range | awk '{print $2-$1}'
28232

さっき数えた TIME_WAIT の数とだいたい一致してる。

ここちょっとあやふやな記憶なんですが、コネクションテーブルの管理は、SIP:SPORT:DIP:DPORTをキーとしていたはず。で、今回のケースはSIP, DIP, DPORTが固定でSPORTだけが変化してって、28232個使い果たして一意性が保てなくなったんで、エラーになった、ってことだと思うす。実際、他のホストには接続張れましたし。

でで、

最初はTIME_WAITの滞留時間を短くすればいいのかなぁと思ったんすけど、TIME_WAITのコネクションを再利用するオプションがあったような記憶がうっすらあったので、さっきのip-sysctl.txtをgrepしたらお目当てのを発見。

tcp_tw_recycle - BOOLEAN
        Enable fast recycling TIME-WAIT sockets. Default value is 0.
        It should not be changed without advice/request of technical
        experts.

tcp_tw_reuse - BOOLEAN
        Allow to reuse TIME-WAIT sockets for new connections when it is
        safe from protocol viewpoint. Default value is 0.
        It should not be changed without advice/request of technical
        experts.

おお。この2つの値を変えて、件のベンチマーク的なプログラムを実行した結果は以下の通り。

recyclereusenetstat -tna | wc -l
0 0→たくさん。繋げなくなりエラーになる。
0 1→たくさん。エラーにはならない。
1 0→最大で3000個ぐらいまで増えるけどすぐに減る。
1 1→最大で3000個ぐらいまで増えるけどすぐに減る。

最初のエラーになるケースを除いては、秒あたりの接続数はどれも同じぐらい。

挙動だけ見るとrecycle,reuseが1,0の場合と1,1の場合のは同じぽいんですが、recycleだけを1にするべきなのか、両方1にするべきかはわからず…

↓の参考文書にも書いてますが、この設定はWebサーバなんかでも有効なんじゃないかと思います。特に、keepaliveをOffにしている場合とか。

以下、参考。

追記 2009-05-09

tcp_tw_recycleの弊害について。

2007-10-24 (Wed)

freenodeで文字化けする件

registerしてるチャンネルでたまに文字化けするなーで、clear #channel allすると直るなー、原因わかんねーなーと思ってたんですが、先達の方々に教えてもらいましたのでメモ。

結論からいうと、チャンネルモードで-cしないとiso-2022-jpな発言が文字化けする。

なんでかというと、+cはHyperion-ircdの拡張モードらしく、その効能は、

+c (color filter)
This cmode activates the colour filter for the channel. This filters out bold, underline, reverse video, beeps, mIRC colour codes, and ANSI escapes. Note that escape sequences will usually leave cruft sent to the channel, just without the escape characters themselves.
404?Not Found - freenode

で、これが有効になっている(+c)と、iso-2022-jpのエスケープ(0x1B)がフィルタされて削られて文字化けするって寸法らしい。

registerしているユーザが出入りすると、そのタイミングでチャンネルモードがクリアされ、+cされ、化けラッタになってた模様。

解決方法としては、いちいち-cするか、mlockでモード固定するか。後者のほうが将来の手間がかからないのでいい。

ほか、nickservとかchanservのメモも残しておきます。これ以外のコマンドもたくさんあるのですが、それはhelpを見てください><


/msg nickserv register PASSWORD
自分の名前(ニックネーム)を登録。
/msg nickserv identify PASSWORD
認証要求。登録したパスワードが必要。
/msg nickserv help
nickservのヘルプを表示。
/msg chanserv register #CHANNEL
#CHANNELを登録。事前にnickservの認証をパスしている必要がある。
/msg chanserv op #CHANNEL
なるとを自分につける。なるとを落としてしまったときに回復するときとかに。事前に当該チャンネルにregisterしている必要がある。
/msg chanserv set #CHANNEL mlock -c+snt
チャンネルのモードを(この例の場合は-c+sntに)強制固定化する。
/msg chanserv help
chanservのヘルプを表示。

2007-10-23 (Tue)

WEB+DB PRESS Vol.41 とイベント参加のお知らせ (どちらも手前味噌)

f:id:hirose31:20071022233713j:image:w350:left


今回の連載記事は、「LinuxとVLANで作る、シンプル&スケーラブルネットワークの極意」というタイトルで、前半は理想のネットワーク構成の考察を、後半は理想の構成を実現するためのVLANの紹介と、Linux (vconfig) とスイッチを使ったタグVLANの構成例・設定例を書きました。

必要に迫られてない方でも、前半の理想の構成を探求するステップのあたりは楽しんでいただけるんではないかなーと思っております。

それともう一つ。

7周年を記念して、WEB+DB PRESS編集部主催でWEB+DB PRESS Tech Meetingというイベントが12/20に開催されるんですが、

  • 登壇予定
    • 小飼弾さん
    • 伊藤直也さん (はてな)
    • ひろせまさあきさん (KLab)
    • 天野仁史さん (サイボウズ・ラボ)
    • 羽生章洋さん (スターロジック)
    • 岡島幸男さん (永和システムマネージメント) ほか

(応募方法など詳細はVol.41の24ページに書いてますんで、そちらを見てみてください)

ということでぼくもしゃべる予定です。

スピーカの方々が有名人ばかりなのに加え、参加者も80名程度と多めなので、若干、緊張してますが、とても楽しみにしてますー

2007-10-21 (Sun)

離れたところからGrowlで通知 - UDPのパケットをSSHでポートフォワードする方法

  • Growlに、LANの外のマシンから通知リクエストを投げたい。
  • Growlは、リモートから通知リクエストを受ける機能がある。
    • UDPの9887番ポートを使用
  • が、Growlが動いているマシンと通知リクエストを行うマシンは、それぞれ異なるLANに属していて、直接通信できない。
  • そんなときお手軽便利なのは、SSHのポートフォワード。これでずるっとトンネルを開通すればいい。
  • が、TCPのパケットしかポートフォワードできない。

というわけで、

  • 発信側のマシン
  • 受信側のマシン
    • stoneでTCPUDP
    • Growlに着信

な構成にすればOK

が、Mac (Mac OS X 10.4.10, Intel) だと stone (2.3d) のUDP/TCP変換がうまく動かない —もうちょっと具体的にいうと、sendtoがエラーリターンする(調査中…)—

TCP5>UDP6: sendto failed err=56: to 127.0.0.1:9889/udp

56 EISCONN Socket is already connected. A connect request was made on an already connected socket; or, a sendto or sendmsg request on a connected socket specified a destination when already connected.

Page Not Found - Apple Developer

ので、Growlなマシンと同じLAN内にあるLinuxマシンでTCPUDPの変換をしました。

図にするとこんな感じ。

┏━━━━━━━━━━━━━━━━━
┃┌[notifier]───────────
┃│Net::Growl
┃│↓
┃│localhost:9887/udp
┃│  stone // stone -nr localhost:9888 localhost:9887/udp
┃│↓
┃│localhost:9888/tcp
┃│  ssh   // ssh -L 9888:localhost:9888 relay
┃└────────────────
┗━━━━━━━━━━━━━━━━━
  ↓
〜〜〜
  ↓
┏━━━━━━━━━━━━━━━━━
┃┌[relay ]────────────
┃│localhost:9888/tcp
┃│  stone // stone -nr growl:9887/udp localhost:9888
┃└────────────────
┃  ↓
┃┌[growl ]────────────
┃│*:9887/udp
┃│  Growl
┃└────────────────
┗━━━━━━━━━━━━━━━━━

追記 2007-10-22 14:05

Mac (Mac OS X 10.4.10, Intel)とFreeBSD 6.2で、

stone-2.3d
本文と同じく、EISCONNが発生。
stone.c 2.3.2.2
正常に通信成功。

を確認しました。対応ありがとうございました!> id:gcd san

また、『UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI』の「8.11 UDPにおけるconnect関数」(p.216) に関連する記述がありました。

要約すると、接続済みUDPソケット(connectしたもの)に対して終点指定ありのsendtoを行った場合の結果は以下のようになるそうです。

環境結果
4.4BSDEISCONN
Posix.1gEISCONN
Solaris 2.5OK
Linux 2.6OK (これは私の実験の結果から)

2007-10-16 (Tue)

kernel 2.6.23

より。

ext4とOCFS2でnanosecondのタイムスタンプに対応したっぽい。

ext3でnanosecondしたときのメモは d:id:hirose31:20060228 へんにあります。

あとext4で、サブディレクトリの上限は65,000個、という制限がなくなったらしい。

2007-10-12 (Fri)

Class::Component その2

※ 例文中の個人名などは架空のものです。

やりたいこと

  • 人によって自転車の色は異なる。色の情報は外部のデータファイルとかDBとかにある。色の情報は最初に調べておいて、聞かれたらすぐに答えられるようにしておきたい。
  • やれることは全部やりたい。

やったこと

妥当かどうかわからないすけどやったこと。

  • Pluginが呼ばれる前に外部データを読むとかの初期化処理をしたい。でもってその初期化処理は、Pluginされたエッジクラスに応じて変化させたい。
    • エッジクラス (NaoyaとかKanjiManとか) で、config に { injected => __PACKAGE__ } を詰める。
      • __PACKAGE__->class_component_reinitialize(config => $config); でセットする。
      • __PACKAGE__->class_component_reinitialize と use Class::Component config => {...} は等価。らしい→ 503 Service Temporarily Unavailableの38ページ
    • Plugin (Jitensyaとか) は、newの中で$self->initが呼ばれる。なのでここで初期化処理をやる。
      • Pluginでは $self->config->{injected} でエッジクラスで詰めたデータがとれる。
      • initでもこれを参照して、この値に応じて初期化処理を変えたりなんかしちゃう。
  • Pluginされたメソッドを全部呼びたい。
    • Naoya->new->allで、injectされたPluginのMethodを全部呼ぶようにする。
      • NaoyaのスーパークラスのHStaffでall関数を定義。
      • $self->class_component_methods で、injectされたMethod名をキーとしてもつハッシュが返ってくる。
      • ループでぐるんぐるん回して全部実行する。
$ ./hatena.pl
blue
ring ring by Naoya
---
no color
watami DE nonderu.
chin chin by KanjiMan

コードは↓で。

続きを読む

2007-10-09 (Tue)

YAML::DumpとかJSON::objToJsonみたいな感じでshのsyntaxでダンプru

例外処理とかユルユルですが。

#!/usr/bin/env perl
# Time-stamp: <2007-10-09 20:01:58 JST, hirose31>

use strict;
use warnings;
use utf8;
use Carp;
use String::ShellQuote;
use Test::Base;

### ========================================================================
plan tests => 1 * blocks;

filters {
    input    => [qw(eval)],
    expected => [qw()],
};

run {
    my $block = shift;

    my $out;
    eval { $out = objToSh($block->input) };
    $out =~ s/\s+\z// if $out;

    is($out, $block->expected, $block->name);
};

### ========================================================================
sub objToSh {
    my($obj) = @_;
    my $out;

    my $type = ref $obj;
    return unless $type;

    if ($type eq 'HASH') {
        while (my ($k,$v) = each %$obj) {
            my $vtype = ref $v;
            if (! $vtype) {
                $out .= sprintf "%s=%s ", _sh_name($k), _sh_value($v);
            } elsif ($vtype eq 'ARRAY') {
                $out .= sprintf "%s=(", _sh_name($k);
                $out .= join " ", _sh_value(@$v);
                $out .= ") ";
            }
        }
        return $out;
    }
    return;
}

sub _sh_name {
    my($k) = @_;
    $k =~ /^[a-zA-Z_][a-zA-Z_0-9]+$/ or croak 'contain invalid character';
    return $k;
}
sub _sh_value {
    shell_quote_best_effort @_;
}

__END__
=== name=val
--- input: { varname => 'valval' }
--- expected: varname=valval

=== value contain space
--- input: { varname => 'foo bar baz' }
--- expected: varname='foo bar baz'

=== value contain single quote
--- input: { varname => q{val'val} }
--- expected: varname='val'\''val'

=== value contain double quote
--- input: { varname => q{val"val} }
--- expected: varname='val"val'

=== value contain single and double quote
--- input: { varname => q{val'val"val} }
--- expected: varname='val'\''val"val'

=== hash
--- input: { one => 'ichi', two => 'ni', three => 'san' }
--- expected: three=san one=ichi two=ni

=== array
--- input: { ary => [qw(foo bar baz)] }
--- expected: ary=(foo bar baz)

=== array contains single and double quote
--- input: { ary => ['foo', q{ba'r}, q{ba"z}] }
--- expected: ary=(foo 'ba'\''r' 'ba"z')

=== invalid name  start with digit
--- input: { '0varname' => 'valval' }
--- expected eval: undef

=== invalid name  contain hyphen
--- input: { 'var-name' => 'valval' }
--- expected eval: undef

--- LAST

# for Emacsen
# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# indent-tabs-mode: nil
# coding: utf-8
# End:

# vi: set ts=4 sw=4 sts=0 :

2007-10-05 (Fri)

KanjiManもJitensyaに乗せてあげたい

  • PluginとかはHStaff::Plugin::*に。
  • NaoyaやKanjiManはHStaffを継承。
#!/usr/bin/env perl
use strict;
use warnings;
use Naoya;
Naoya->new->bell;
use KanjiMan;
KanjiMan->new->bell;
package HStaff;
use strict;
use warnings;
use Class::Component;
__PACKAGE__->load_components(
    qw/ Autocall::InjectMethod /
);
1;
package HStaff::Plugin::Jitensya;
use strict;
use warnings;
use base 'Class::Component::Plugin';
use Perl6::Say;
sub bell : Method {
    my($self, $context, @args) = @_;
    say $self->config->{sound};
}
1;
package Naoya;
use strict;
use warnings;
use base 'HStaff';
use Class::Component config => {
    Jitensya => { sound => 'ちりんちりん' },
};
__PACKAGE__->load_plugins(qw/ Jitensya /);
1;
package KanjiMan;
use strict;
use warnings;
use base 'HStaff';
use Class::Component config => {
    Jitensya => { sound => 'りんりん' },
    Nijikai  => { where => 'watami' },
};
__PACKAGE__->load_plugins(qw/ Jitensya Nijikai /);
1;
  • サーバの種類(Web, DB, LVSとか)ごとにエッジクラスを作る。
  • エッジクラスは Server クラスを継承。
  • Server::Plugin::* でメタ情報を返すモジュール/メソッドを作る。
  • IPアドレスを返すメソッドは全部のエッジクラスに生やす。
  • DBのスレーブを返すメソッドはDBクラスだけに生やす。
  • VRRPのIDを返すメソッドはLVSクラスだけに生やす。
  • とか
  • そんなことを。

2007-10-03 (Wed)

脳内発音

ちょうど脳内発音を書き留めててたんで並べてみます。

表記脳内発音
makeまけ
chmodちもっど
chgrpちぐるぷ
sshしゅしゅ
YAPCやっぷく
CPANTSしーぱんつ
XXX-ngXXX-んぐ
svnすぶん
svkえすぶいけー
sexpせっくすぴー
warnうぉーん
2。0
pseudoぷせうどぅ

2007-10-02 (Tue)

Pure PerlなHTTPdを物色

HTTP::Daemon
forkしないので、1個詰まると後続のリクエストは待たされる。
HTTP::Simple::Server
デフォルトではforkしない。
HTTP::Simple::Server + Net::Server::Fork
forkするので多重化可能。が、リクエストごとに新しいプロセスをforkしちゃう。
HTTP::Simple::Server + Net::Server::PreFork
forkするので多重化可能。pre-forkするのでプロセスは使いまわせる。
Net::HTTPServer
type=>'forking'でpre-forkする。
URLのパスと関数をマッピングできるのもよさげ。
PerlBal
Danga::Socketベースなので、IO多重化(epollとか)な実装。(だと思うす)
POE::Component::Server::HTTP
ぽぅ
Catalyst::Engine::Server
未試用...

ちっさめのがいいんで、Net::HTTPServer を使おうかなと思ってますが、ほかにも実装があったら教えてもらえるとうれしいデス。

追記

  • Catalyst::Engine::Serverを追加 (どもす>id:kazeburo)

sshdが対応している認証機構を判別する方法

拙作でアレなんですが、Net::Scan::SSH::Server::SupportedAuth を使うといいかも。

同梱しているsample/scan-sshauth.plを使うと、

$ scan-sshauth.pl 10.6.25.0/24
HOST                   : SSH2  SSH1 (K=publickey, P=password)
===================================
10.6.25.0              : 2=--  1=--
10.6.25.1              : 2=K-  1=--
10.6.25.2              : 2=K-  1=K-
10.6.25.3              : 2=K-  1=K-
10.6.25.4              : 2=--  1=--
10.6.25.5              : 2=--  1=--
10.6.25.6              : 2=--  1=--
10.6.25.7              : 2=--  1=--
(snip)

的なことができます。

この例の場合、

  • 10.6.25.1はSSHv2の公開鍵認証だけを受け入れている
  • 10.6.25.2はSSHv2の公開鍵認証と、SSHv1の公開鍵認証を受け入れている

となります。

scan-sshauth.plをいじってYAMLを吐くようにしてPlaggerでNotify::*するとか、Assurer Assurer::Plugin::Test::SSH::SupportedAuthとかして、continuousにチェックするといいんではないかと思うす。

だれがいったか忘れましたが、「初期構成状態の継続的確認=監視」というのを思い出しました。

ちんちん係

会長のご命令でちんちん係を仰せつかりました。

途中、ちんするのをほけっと忘れてたのを、隣に座っていた京王線で途方に暮れているid:lopnorに助けて貰いつつもなんとかこなしました。

ドラを鳴らすPerl moduleをCPANにうpしたら英雄になれるんではないかと思いました。

また、初代幹事マンの偉大さを知った一日でもありました。

2003 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 05 | 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 | 12 |
2012 | 01 | 02 | 03 | 06 | 08 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 |
2015 | 01 | 02 | 07 | 10 |
2016 | 01 | 05 | 10 | 12 |
2017 | 07 |
2018 | 05 | 11 |