2009年 4月 24日 金曜日
やっぱり Sun がスキ!
Sunグッズ紹介(21) なにがあってもやっぱり Sun Goods もスキ!
Sun のロゴ入りグッズ紹介の第二十一弾です。
Sun Goods コレクターとして日々グッズ収集に勤しんでいたら 個人持ちのグッズが大変な量になってしまいました。
整理整頓する機会があったので一部公開してみます。 写真並べまくっただけですがご容赦を。 是非、懐かしんだり・驚いたりしてください。 (画像をクリックすると拡大出来ます)
Posted at 11:15午前 4 24, 2009 by Chizu Kitano in Goods | 投稿されたコメント[2]
X4270 の prtdiag 解説
先日、サンは Intel Xeon 5500 番台 CPU を搭載したサーバ群を 発表しましたが、今回この CPU を搭載した Sun Fire X4270 の prtdiag コマンドの出力結果を取得しましたので、アーキテクチャの解説と併せて 解説してみます。

Sun Fire X4270
まずは、 prtdiag -v の結果をご覧下さい。
# prtdiag -v System Configuration: SUN MICROSYSTEMS SUN FIRE X4170/X4270/X4275 SERV BIOS Configuration: American Megatrends Inc. 07013853 02/26/2009 BMC Configuration: IPMI 1.5 (KCS: Keyboard Controller Style) ==== Processor Sockets ==================================== Version Location Tag -------------------------------- -------------------------- Intel(R) Xeon(R) CPU L5520 @ 2.27GHz CPU 1 Intel(R) Xeon(R) CPU L5520 @ 2.27GHz CPU 2 ==== Memory Device Sockets ================================ Type Status Set Device Locator Bank Locator ------- ------ --- ------------------- -------------------- other in use 0 D2 BANK2 other empty 0 D1 BANK1 other empty 0 D0 BANK0 other in use 0 D5 BANK5 other empty 0 D4 BANK4 other empty 0 D3 BANK3 other in use 0 D8 BANK8 other empty 0 D7 BANK7 other empty 0 D6 BANK6 other in use 0 D2 BANK2 other empty 0 D1 BANK1 other empty 0 D0 BANK0 other in use 0 D5 BANK5 other empty 0 D4 BANK4 other empty 0 D3 BANK3 other in use 0 D8 BANK8 other empty 0 D7 BANK7 other empty 0 D6 BANK6 FLASH in use 0 ==== On-Board Devices ===================================== Zoar 2x GbE. Zoar 2x GbE. Zoar 2x GbE. Zoar 2x GbE. ==== Upgradeable Slots ==================================== ID Status Type Description --- --------- ---------------- ---------------------------- 0 in use PCI Express PCIE0 1 available PCI Express PCIE1 2 available PCI Express PCIE2 3 available PCI Express PCIE3 4 in use PCI Express PCIE4 5 available PCI Express PCIE5
まず、 Processor Sockets の情報から、このサーバに搭載されている CPU の種類とソケット数が確認できます。
Ultra SPATC T シリーズの prtdiag では、スレッド単位で表示(例えば T5120 では 64 CPU) されますが、Sun Fire X4270 では、 CPU ソケット単位で表示されます。
mpstat で OS が認識しているスレッド数を確認すると、Intel Xeon 5500 番台 CPU は、4 Core で かつ Hyper-Threading を実装していますので、合計 16( 4 core x 2 Thread x 2 CPU) スレッドとなります。
# mpstat CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 249 0 73 383 159 73 0 4 53 0 335 0 1 0 99 1 89 0 49 28 0 63 0 3 40 0 211 0 0 0 100 2 62 0 44 43 15 64 0 2 38 0 170 0 0 0 100 3 70 0 44 32 4 62 0 2 36 0 155 0 0 0 100 4 275 0 84 29 4 57 0 3 49 0 384 0 0 0 99 5 91 0 36 37 9 25 0 2 35 0 146 0 0 0 100 6 52 0 25 29 0 21 0 1 29 0 139 0 0 0 100 7 64 0 27 29 0 20 0 1 29 0 123 0 0 0 100 8 58 0 16 30 0 41 0 1 31 0 89 0 0 0 100 9 33 0 8 30 0 35 0 1 28 0 43 0 0 0 100 10 24 0 5 30 0 32 0 1 28 0 32 0 0 0 100 11 21 0 4 30 0 44 0 1 27 0 27 0 0 0 100 12 52 0 12 30 0 7 0 1 26 0 62 0 0 0 100 13 30 0 6 30 0 6 0 1 25 0 34 0 0 0 100 14 21 0 3 30 0 4 0 1 25 0 22 0 0 0 100 15 21 0 3 30 0 4 0 1 25 0 22 0 0 0 100
Memory Device Sockets 関して、Intel Xeon 5500 番台 CPU は、DDR3 メモリを採用 し、CPU 毎に 3 メモリチャンネルあります。Sun Fire X4270 では、各チャンネ ル毎に 3 バンクの実装なので、メモリスロットは合計 18 ( 3 Channel x 3 BANK x 2 CPU) スロットになります。(ちなみに Sun Fire X4250 では 16 スロットでした。)
On-Board ネットワークに関して、ネットワークコントローラは Intel の Zoar(Intel 82575EB Gigabit Ethernet Controller) を 2 個搭載しています。各 Zoar 毎にネットワークのポートが 2 つありますので、合計で Gigabit Ethernet を 4 ポート搭載しています。
dladm で確認すると、 4 ポート表示され、ネットワークドライバは e1000g でなく igb である事が確認できます。
# dladm show-dev igb0 link: up speed: 1000 Mbps duplex: full igb1 link: unknown speed: 0 Mbps duplex: half igb2 link: unknown speed: 0 Mbps duplex: half igb3 link: unknown speed: 0 Mbps duplex: half
最後に、拡張 PCI Express スロットに関して、Sun Fire X4270 は PCIe2 を採用しており、 合計で 6 スロットあるのが確認できます。
今回は、prtdiag の結果から Intel Xeon 5500 番台 CPU 搭載サーバ Sun Fire X4270 の アーキテクチャを解説しました。今後新しいアーキテクチャのサーバが発表された時は また prtdiag の紹介をしたいと思います。
(参考情報)
過去の 「やっぱり Sun がスキ!」blog 記事一覧はこちらを参照下さい。 http://wikis.sun.com/display/yappri/Home
Posted at 04:18午後 4 23, 2009 by Naoyuki Yamada in Sun | 投稿されたコメント[0]
SJSMS - Solaris 10 の SMF に登録しよう
今回は久しぶり(なんと半年振り!)に Messaging Server ネタです。
以前のブログ記事(その 1,その 2)でインストールしてみた Messaging Server 関連コンポーネントを Solaris 10 の
SMF に登録して、自動起動の設定をしてみましょう。
前回インストールした関連コンポーネントは以下の通りです。
- Directory Server 6.3
- Messaging Server 7.0
- Application Server 9.1
- Access Manager 7.1
- Delegated Administrator 6.4
- Sun Convergence 1.0
上記コンポーネントの中で、Access Manager, Delegated Administrator, Sun Convergence は、Application Server 9.1
上に配備されておりますので、SMF に登録して自動起動の設定をする必要があるコンポーネントは以下
の 3 つになります。
- Directory Server 6.3
- Messaging Server 7.0
- Application Server 9.1
では、順番に、SMF に登録していきましょう。
目次
Directory Server 6.3 を SMF に登録
実は、Directory Server 6.3 の提供方法は、パッケージ版と ZIP アーカイブ版の 2 種類があり、
インストール・設定に若干の差異があります。
パッケージ版の Directory Server では、dsadm コマンドから SMF にサービスを登録する方法が
あるのですが、ZIP アーカイブ版では、dsadm コマンドから SMF にサービスを登録する事が出来ません。
※ パッケージ版のためのご参考
以前のブログ記事で紹介したインストール手順では、ZIP アーカイブ版の Directory Server を
使用しているので、dsadm enable-service コマンドが使えません。
そこで今回は、/opt/SUNWdsee/ds6/install 配下に用意されているテンプレートファイルを
使って、SMF に登録します。
sw-89# pwd
/opt/SUNWdsee/ds6/install
sw-89# cp tmpl_smf.manifest ds6_for_ms7_smf.manifest
※ あらかじめ、template ファイルをコピーします。
sw-89# vi ds6_for_ms7_smf.manifest
※ manifest ファイルを下記 diff に示される様に編集します。
※ 具体的には、"%%%DATE_CREATED%%%", "%%%INSTALL_PATH%%%"
※ "%{sunds/path}", "%%%TIMEOUT_SECONDS%%%" を適宜編集します。
sw-89# diff ds6_for_ms7_smf.manifest tmpl_smf.manifest
6c6
< Created on : 2009/04/16
---
> Created on : %%%DATE_CREATED%%%
24,25c24,25
< exec="/opt/SUNWdsee/ds6/bin/dsadm start --exec /var/opt/SUNWdsee/dsins1"
< timeout_seconds="600">
---
> exec="%%%INSTALL_PATH%%%/bin/dsadm start --exec %{sunds/path}"
> timeout_seconds="%%%TIMEOUT_SECONDS%%%">
35,36c35,36
< exec="/opt/SUNWdsee/ds6/bin/dsadm stop --exec /var/opt/SUNWdsee/dsins1"
< timeout_seconds="600">
---
> exec="%%%INSTALL_PATH%%%/bin/dsadm stop --exec %{sunds/path}"
> timeout_seconds="%%%TIMEOUT_SECONDS%%%">
sw-89#
sw-89# cat ds6_for_ms7_smf.manifest
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<!--
Document : ds6-service.xml
Created on : 2009/04/16
Author : Directory Server Enterprise Edition Team
Description: The SMF Service Manifest file for Directory Server 6
-->
<service_bundle type="manifest"
name="SUNWldap-directory services">
<service name="application/sun/ds" type="service" version="1">
<dependency name="filesystems" grouping="require_all"
restart_on="none" type="service">
<service_fmri value="svc:/system/filesystem/local:default"/>
</dependency>
<dependency name="network" grouping="require_all"
restart_on="none" type="service">
<service_fmri value="svc:/network/initial:default"/>
</dependency>
<exec_method type="method"
name="start"
exec="/opt/SUNWdsee/ds6/bin/dsadm start --exec /var/opt/SUNWdsee/dsins1"
timeout_seconds="600">
<method_context working_directory=":default">
<method_credential user="root"
group=":default"
privileges=":default"/>
</method_context>
<stability value="Evolving"/>
</exec_method>
<exec_method type="method"
name="stop"
exec="/opt/SUNWdsee/ds6/bin/dsadm stop --exec /var/opt/SUNWdsee/dsins1"
timeout_seconds="600">
<method_context working_directory=":default">
<method_credential user="root"
group=":default"
privileges=":default"/>
</method_context>
<stability value="Evolving"/>
</exec_method>
<instance name="default" enabled="false"/>
<stability value="Evolving"/>
<template>
<common_name>
<loctext xml:lang="C"> Directory Server </loctext>
</common_name>
<documentation>
<doc_link name="Directory Server Enterprise Edition 6 Administration Guide" uri="http://docs.sun.com/doc/819-0995/"/>
</documentation>
</template>
</service>
</service_bundle>
sw-89#
sw-89# svccfg import ./ds6_for_ms7_smf.manifest
※ 上記で作成した manifest ファイルを svccfg コマンドにて import します。
sw-89# svcs ds
STATE STIME FMRI
disabled 14:52:43 svc:/application/sun/ds:default
※ svc:/application/sun/ds:default が追加されている事を確認します。
sw-89# svcadm enable ds
※ svc:/application/sun/ds:default サービスをスタートします。
sw-89# ps -ef | grep slapd
root 13460 8891 0 14:54:59 ? 0:01 /opt/SUNWdsee/ds6/lib/64/ns-slapd -D /var/opt/SUNWdsee/dsins1 -i /var/opt/SUNWd
root 13463 9868 0 14:55:01 pts/3 0:00 grep slapd
sw-89#
※ ns-slapd (Directory Server のプロセス) が起動している事が確認出来ます。
sw-89# svcs ds
STATE STIME FMRI
online 14:55:02 svc:/application/sun/ds:default
sw-89#
※ svc:/application/sun/ds:default サービスも online になっている事が確認出来ます。
sw-89# svcadm disable ds
※ svc:/application/sun/ds:default サービスを停止します。
sw-89# svcadm disable ds
sw-89# svcs ds
STATE STIME FMRI
online* 14:57:23 svc:/application/sun/ds:default
sw-89# svcs ds
STATE STIME FMRI
disabled 14:57:27 svc:/application/sun/ds:default
sw-89#
※ svc:/application/sun/ds:default サービスが停止された事が確認出来ます。
sw-89# svcadm enable ds
sw-89# svcs ds
STATE STIME FMRI
offline* 14:58:12 svc:/application/sun/ds:default
sw-89# svcs ds
STATE STIME FMRI
online 14:58:19 svc:/application/sun/ds:default
sw-89#
※ 最後に svc:/application/sun/ds:default サービスを起動させておきます。
以上で、Directory Server の SMF の登録が完了しました。
Messaging Server 7.0 を SMF に登録
次に Messaging Server を SMF に登録しましょう。
Messaging Server の登録方法も Directory Server と同様テンプレートファイル
を利用して SMF に登録します。
sw-89# pwd /opt/sun/comms/messaging64/data/install sw-89# ls pab.ldif schema2ug_store.ldif schema2usergroup.ldif.rej restofmessaging.xml schema2usergroup.ldif watcher.xml sw-89#
まずこの場所に messaging.xml ファイルが存在するか確認してください。
messaging.xml が存在する場合は下記の手順(messaging.xml の作成・msgexe の編集)を
省略してください。
※ 当初提供されていた restofmessaging.xml, watcher.xml を利用する方法では
※ ただしく動作しない問題が見つかっております。
※ その問題の回避のため、messaging.xml の作成・msgexe の編集を行ないます。
sw-89# pwd /opt/sun/comms/messaging64/lib sw-89# cp msgexe msgexe.orig ※ SMF から利用する起動・停止スクリプトのバックアップを作成します。 sw-89# vi msgexe ※ msgexe を下記に示される様に編集します。 ※ 具体的には、start-msg, stop-msg の引数($2) を削除、 ※ refresh 時のコマンドを refresh コマンドに変更します。 sw-89# cat msgexe #!/sbin/sh ## Copy/Rename this script to //lib/ ## Please change $REPOS to the location of your SVN Repo . /lib/svc/share/smf_include.sh parser() { PROPERTY=$1 # VALUE=`svcprop -p ${PROPERTY} watcher` VALUE=`svcprop -p ${PROPERTY} messaging_server` if [ "${VALUE}" = "\"\"" ] ; then VALUE= fi echo $VALUE } MESSAGING_BASE=`parser application/messaging_server_base` if [ -z "${MESSAGING_BASE}" ] ; then exit $SMF_EXIT_ERR_CONFIG fi case $1 in 'start') # ${MESSAGING_BASE}/bin/start-msg $2 ${MESSAGING_BASE}/bin/start-msg if [ $? -ne 0 ] ; then exit $SMF_EXIT_ERR_FATAL fi exit $SMF_EXIT_OK ;; 'stop') # ${MESSAGING_BASE}/bin/stop-msg $2 ${MESSAGING_BASE}/bin/stop-msg if [ $? -ne 0 ] ; then exit $SMF_EXIT_ERR_FATAL fi exit $SMF_EXIT_OK ;; 'refresh') # ${MESSAGING_BASE}/bin/stop-msg $2 # sleep 5 # ${MESSAGING_BASE}/bin/start-msg $2 ${MESSAGING_BASE}/bin/refresh if [ $? -ne 0 ] ; then exit $SMF_EXIT_ERR_FATAL fi exit $SMF_EXIT_OK ;; *) echo "Usage: $0 { start | stop | refresh }" exit $SMF_EXIT_ERR_FATAL ;; esac sw-89# sw-89# cd /opt/sun/comms/messaging64/data/install sw-89# cp restofmessaging.xml messaging.xml ※ restofmessaging.xml を messaging.xml にコピーします。 sw-89# vi messaging.xml ※ messaging.xml ファイルを下記に示される様に編集します。 ※ 具体的には、dependency name='watcher' 部分をコメントアウト、 ※ dependency name='DirectoryServer' を追加します。 ※ 尚、dependency name='DirectoryServer' は、Directory Server ※ を別サーバにインストールしている場合は、不要です。 sw-89# cat messaging.xml <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- Sun Java Enterprise System Messaging Server 7.0 ( Cascabel ) --> <service_bundle type='manifest' name='messaging_server'> <service name='network/messaging_server' type='service' version='1'> <create_default_instance enabled='false' /> <single_instance /> <dependency name='network-service' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/network/service' /> </dependency> <dependency name='fs-local' grouping='require_all' restart_on='none' type='service'> <service_fmri value='svc:/system/filesystem/local' /> </dependency> <dependency name='name-services' grouping='require_all' restart_on='refresh' type='service'> <service_fmri value='svc:/milestone/name-services' /> </dependency> <dependency name='identity' grouping='optional_all' restart_on='refresh' type='service'> <service_fmri value='svc:/system/identity:domain' /> </dependency> <!-- <dependency name='watcher' grouping='require_all' restart_on='refresh' type='service'> <service_fmri value='svc:/network/watcher' /> </dependency> --> <dependency name='DirectoryServer' grouping='require_all' restart_on='refresh' type='service'> <service_fmri value='svc:/application/sun/ds:default' /> </dependency> <exec_method type='method' name='start' exec='/opt/sun/comms/messaging64/lib/msgexe start' timeout_seconds='180' > </exec_method> <exec_method type='method' name='stop' exec='/opt/sun/comms/messaging64/lib/msgexe stop' timeout_seconds='180' > </exec_method> <exec_method type='method' name='refresh' exec='/opt/sun/comms/messaging64/lib/msgexe refresh' timeout_seconds='180' > </exec_method> <property_group name='application' type='framework'> <propval name='messaging_server_base' type='astring' value='/opt/sun/comms/messaging64' /> </property_group> <property_group name='startd' type='framework'> <propval name='ignore_error' type='astring' value='core,signal' /> </property_group> <stability value='Unstable' /> </service> </service_bundle> sw-89#
messaging.xml ファイルがあった場合もここから先は実行してください。
sw-89# svccfg import ./messaging.xml ※ messaging.xml ファイルが出来たら、svccfg コマンドにて import します。 sw-89# svcs network/messaging_server STATE STIME FMRI disabled 15:12:37 svc:/network/messaging_server:default sw-89# ※ svc:/network/messaging_server:default が追加されている事を確認します。 sw-89# svcadm enable messaging_server ※ svc:/network/messaging_server:default サービスをスタートします。 sw-89# svcs messaging_server STATE STIME FMRI offline* 15:23:08 svc:/network/messaging_server:default sw-89# svcs messaging_server STATE STIME FMRI online 15:23:16 svc:/network/messaging_server:default sw-89# ※ svc:/network/messaging_server:default サービスが online になっている事が確認出来ます。
以上で、Messaging Server の SMF の登録が完了しました。
Application Server 9.1 を SMF に登録
最後に Application Server を SMF に登録しましょう。
Application Server は、テンプレートファイルの利用では無く、asadmin コマンドにて SMF に
登録出来ます。
sw-89# cat /.passwordfile AS_ADMIN_USER=admin AS_ADMIN_PASSWORD=<admin ユーザの実際のパスワードを記載して下さい。> AS_ADMIN_MASTERPASSWORD=<マスターパスワードを記載して下さい。> sw-89# ※ 自動起動用の password ファイルを作成します。 sw-89# /opt/SUNWappserver/bin/asadmin create-service --type das --passwordfile /.passwordfile /opt/SUNWappserver/domains/domain1 サービスが正常に作成されました。詳細は次のとおりです: サービスの名前:application/SUNWappserver/domain1 サービスのタイプ:Domain サービスの設定場所:/opt/SUNWappserver/domains システム上のマニフェストファイルの場所:/var/svc/manifest/application/SUNWappserver/domain1_opt_SUNWappserver_domains/Domain-service-smf.xml このサービスは svcadm コマンドを使用して有効にできます。 コマンド create-service は正常に実行されました。 sw-89# ※ asadmin create-service コマンドにて、SMF に登録します。 sw-89# svcs domain1 STATE STIME FMRI disabled 15:50:17 svc:/application/SUNWappserver/domain1:default sw-89# ※ svc:/application/SUNWappserver/domain1:default が登録されている事が確認出来ます。 sw-89# svcadm enable domain1 ※ svc:/application/SUNWappserver/domain1:default サービスを起動します。 sw-89# svcs domain1 STATE STIME FMRI offline* 15:50:38 svc:/application/SUNWappserver/domain1:default sw-89# svcs domain1 STATE STIME FMRI offline* 15:50:38 svc:/application/SUNWappserver/domain1:default sw-89# svcs domain1 STATE STIME FMRI online 15:52:34 svc:/application/SUNWappserver/domain1:default sw-89# ※ svc:/application/SUNWappserver/domain1:default サービスが online になっている事が確認出来ます。
以上で、前回インストールした Messaging Server 関連コンポーネントが Solaris の
SMF に登録され、OS 起動時に自動起動されるように設定されました。
sw-89# svcs ds messaging_server domain1 STATE STIME FMRI online 14:58:19 svc:/application/sun/ds:default online 15:23:16 svc:/network/messaging_server:default online 15:52:34 svc:/application/SUNWappserver/domain1:default sw-89#
- Directory Server インスタンスを作成する
- Using Service Management Framework with Messaging Server
- 付録 A ドメインまたはノードエージェントの自動再起動
Posted at 04:00午後 4 22, 2009 by Masayuki Imai in Sun | 投稿されたコメント[0]
mpstat コマンドの読み方
はじめに
先日 Solaris の vmstat コマンドについての記事 を書きましたが、今回は mpstat コマンドについて解説したいと思います。最近は Linux にも mpstat コマンドがありますが、Solaris の mpstat とは出力内容や実装が大きく異なりますので注意が必要です。
mpstat について
CPU がボトルネックになっている可能性がある場合は mpstat を使用する事で CPU の使用状況を調べる事が出来ます。vmstat でも CPU の統計情報を見る事が可能ですが、mpstat ではプロセッサ毎の統計情報が見られるため、より細かな分析が可能です。
mpstat は vmstat と同様に kstat のデータを集計しています。mpstat のソースコードは以下の URL にあります。本体のソースコードは 500 行程度しかありません。
mpstat のお勧めのオプション
インターバルのみ
% mpstat 1
オプションはインターバルのみ指定して下さい。より正確な負荷状況を見る為、長期間の性能監視の場合でもインターバルは 1 秒にする事をお勧めします。ログとして保存する場合も、今時のマシンであればファイルのサイズはそれ程気にしなくて良いと思います。
mpstat の出力例
mpstat の出力はヘッダに加えて CPU 毎に一行ずつ出力されます。4 CPU Machine の場合は毎回 5 行ずつ出力されます。
# mpstat 1 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 189 11 185 42 38 51 1 15 3 0 291 1 2 0 98 1 166 9 193 22 17 191 1 16 5 0 256 1 4 0 96 2 131 10 190 28 23 49 1 14 3 0 282 1 1 0 98 3 119 10 207 257 154 54 1 15 5 0 230 1 2 0 97 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 2 21 16 8 0 2 0 0 2 0 0 0 100 1 0 0 2 19 13 121 0 5 0 0 0 0 5 0 95 2 6 0 1 13 8 8 0 1 0 0 65 0 0 0 100 3 0 0 1 223 120 12 0 5 0 0 1 0 0 0 100 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 0 0 1 9 6 2 0 1 0 0 5 0 0 0 100 1 0 0 7 10 6 121 0 1 0 0 0 0 0 0 100 2 0 0 2 12 7 6 0 0 0 0 55 0 0 0 100 3 0 0 2 218 115 6 0 3 0 0 0 0 3 0 97
各カラムの意味
CPU
CPU はプロセッサ番号です。
CPU の値は 0 から 517 まで(正確には _SC_CPUID_MAX の値まで)です。 0 番から順に p_online(2) で CPU が存在しているか確認し、もし存在していていたらその番号を表示しています。CPU の値は /usr/src/cmd/stat/common/acquire.c の acquire_cpus() 関数でセットされている cs_id から取られています。
_SC_CPUID_MAX は /usr/src/uts/common/sys/unistd.h で定義されています。
211 #define _SC_CPUID_MAX 517 /* maximum CPU id */
minf
minf はマイナーフォルトが発生した回数です。現在はアドレススペースフォルトが発生した回数がそのままマイナーフォルトの回数として計算されています。
minf の値は /usr/src/uts/common/vm/vm_as.c の as_fault() 関数の中の CPU_STATS_ADDQ(CPU, vm, as_fault, 1); で加算されています。
minf の値は kstat -p 'cpu::vm:as_fault' 1" でも取得出来ます。
mjf
mjf はメジャーフォルトが発生した回数です。メジャーフォルトはメモリページを読み込む際に物理 I/O が発生した物のことを言います。
mjf の値は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中で集計されています。ページング用のバッファを用意する際に、B_READ フラグが立っていて B_ASYNC フラグが立っていない場合に CPU_STATS_ADDQ(cpup, vm, maj_fault, 1); で maj_fault の値がインクリメントされます。この maj_fault が mpstat の mjf の値として使用されます。
mjf の値は "kstat -p 'cpu::vm:maj_fault' 1" でも取得出来ます。
xcal
xcal はプロセッサ間のクロスコールの回数です。
xcal の値は CPU 毎に異なるコードで、カーネル内の様々な箇所で更新されています。
sun4v アーキテクチャの環境では /usr/src/uts/sun4v/os/mach_cpu_states.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); と send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); で集計されています。
x86 環境では /usr/src/uts/i86pc/os/x_call.c の xc_capture_cpus() 関数や xc_common() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); で集計されています。
sun4u 環境では CPU 毎に /usr/src/uts/sun4u/cpu/us3_cheetah.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids); 、/usr/src/uts/sun4u/cpu/us3_cheetahplus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、/usr/src/uts/sun4u/cpu/opl_olympus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_jalapeno.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、/usr/src/uts/sun4u/cpu/spitfire.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_common.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); 等で更新されています。
sun4 環境では /usr/src/uts/sun4/os/x_call.c の xc_some() 関数の中の SEND_MBOX_ONLY(xc_cpuset, func, arg1, arg2, lcx, XC_WAIT);(SEND_MBOX_ONLY は /usr/src/uts/sun4/sys/xc_impl.h で定義されています)で加算されています。
xcal の値は "kstat -p 'cpu::sys:xcalls' 1" でも取得出来ます。
intr
intr はインタラプトの回数です。PIL_MAX(=15) までのレベルのインタラプト回数の総計を数えています。PIL は Processor Interrupt Level の略です。
intr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。
intr の値は "kstat -p 'cpu::sys:intr' 1" でも取得出来ます。
ithr
ithr はインタラプト処理用のスレッドで処理されるインタラプトの回数です。LOCK_LEVEL(=10) までのレベルのインタラプト回数の総計を数えています。
ithr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。
ithr の値は "kstat -p 'cpu::sys:intrthread' 1" でも取得出来ます。
csw
csw はコンテキストスイッチの回数です。icsw と対比して、自発的なコンテキストスイッチとも呼ばれます。リソース待ち等で CPU を明け渡した回数です。
csw の値は /usr/src/uts/common/disp/disp.c の swtch() 関数や swtch_to() 関数の CPU_STATS_ADDQ(cp, sys, pswitch, 1);、swtch_from_zombie() 関数の CPU_STATS_ADDQ(CPU, sys, pswitch, 1); で加算されています。
csw の値は "kstat -p 'cpu::sys:pswitch' 1" でも取得出来ます。
icsw
icsw はインボランタリー(非自発的)なコンテキストスイッチの回数です。csw が自発的に CPU を明け渡しているのに対し、よりプライオリティの高いプロセス等に CPU を横取りされた回数です。
icsw の値は /usr/src/uts/common/disp/disp.c の preempt() 関数の中で CPU_STATS_ADDQ(CPU, sys, inv_swtch, 1); で加算されています。
icsw の値は "kstat -p 'cpu::sys:inv_swtch' 1" でも取得出来ます。
migr
migr はスレッドが他の CPU へ移動した回数です。
migr の値は /usr/src/uts/intel/ia32/ml/swtch.s の "incq CPU_STATS_SYS_CPUMIGRATE(%r13)" や "addl $1, CPU_STATS_SYS_CPUMIGRATE(%esi)" (x86)、/usr/src/uts/sun4/ml/swtch.s の "stx %g2, [%i1 + CPU_STATS_SYS_CPUMIGRATE]" (SPARC) で更新されています。CPU_STATS_SYS_CPUMIGRATE は cpu_stats.sys.cpumigrate のオフセットです。
migr の値は "kstat -p 'cpu::sys:cpumigrate' 1" でも取得出来ます。
smtx
smtx は Mutex 変数で Adaptive Lock がスピンした回数です。
Adaptive Lock で他のスレッドが別のプロセッサ上で Lock を保持している場合(その場合はスピンする)最初のスピンの前に 1 加算されます。最初から Spin Lock の場合は加算されません。
smtx の値は /usr/src/uts/common/os/mutex.c の mutex_vector_enter() 関数の中の CPU_STATS_ADDQ(cpup, sys, mutex_adenters, 1); で加算されています。
smtx の値は "kstat -p 'cpu::sys:mutex_adenters' 1" でも取得出来ます。
srw
srw は RW Lock でスピンした回数です。
srw の値は /usr/src/uts/common/os/rwlock.c の rw_enter_sleep() 関数の中の CPU_STATS_ADDQ(CPU, sys, rw_rdfails, 1); と CPU_STATS_ADDQ(CPU, sys, rw_wrfails, 1); の累積値を足し合わせた値です。
srw の値は "kstat -p 'cpu::sys:rw_rdfails' 1" と "kstat -p 'cpu::sys:rw_wrfails' 1" を足す事でも取得出来ます。
syscl
syscl はシステムコールの回数です。
syscl の値はカーネル内の様々な場所で更新されています。
- /usr/src/uts/sparc/v9/ml/syscall_trap.s の CPU_STATS_SYS_SYSCALL (SPARC)
- /usr/src/uts/intel/ia32/os/syscall.c の CPU_STATS_ADDQ(CPU, sys, syscall, 1); (x86)
- /usr/src/uts/i86pc/ml/syscall_asm.s の CPU_STATS_SYS_SYSCALL_INC (x86) と CPU_STATS_SYS_SYSCALL (x86)
- /usr/src/uts/i86pc/ml/syscall_asm_amd64.s の CPU_STATS_SYS_SYSCALL (x86)
syscl の値は "kstat -p 'cpu::sys:syscall' 1" でも取得可能です。
usr
usr はユーザモードで使用した CPU 時間の割合です。
usr の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。
usr の値は "kstat -p 'cpu::sys:cpu_ticks_user' 1" でも取得出来ます。
sys
sys はカーネルサービスやシステムコールなど、システムモードで使用した CPU 時間の割合です。
sys の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。
sys の値は "kstat -p 'cpu::sys:cpu_ticks_kernel' 1" でも取得出来ます。
wt
wt は I/O wait ですが、Solaris 10 では更新されておらず、常に 0 です。その為、このカラムは無視して構いません。
wt の値は "kstat -p 'cpu::sys:cpu_ticks_wait' 1" でも取得出来ます。
idl
idl は CPU が使用されていなかった時間の割合です。
idl の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。
idl の値は "kstat -p 'cpu::sys:cpu_ticks_idle' 1" でも取得出来ます。
値の見方
usr が多い場合
全ての CPU で usr が 80% 以上になっていて idl が殆ど無い場合は、システムのリソースが十分に利用されていると言って良いでしょう。多くの場合、usr の値が高い事はアプリケーション自体の処理に CPU を使えているという事です。処理のフェイズによってリソースの使い方が変わる場合もありますので、プログラムの実行開始から終了まで観察して下さい。
usr の値は TLB miss でも増加します。この場合はアプリケーション自体の処理と言うよりはリソースの確保に CPU が使われています。SPARC マシンでは trapstat(1M) コマンドで TLB miss の有無を確認する事が出来ます(x86 マシンでは trapstat は使えません)。
# trapstat -T 1 10
cpu m size| itlb-miss %tim itsb-miss %tim | dtlb-miss %tim dtsb-miss %tim |%tim
----------+-------------------------------+-------------------------------+----
0 u 8k| 49 0.0 0 0.0 | 27 0.0 0 0.0 | 0.0
0 u 64k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
0 u 512k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
0 u 4m| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
- - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
0 k 8k| 7 0.0 0 0.0 | 262 0.0 2 0.0 | 0.0
0 k 64k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
0 k 512k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
0 k 4m| 0 0.0 0 0.0 | 3 0.0 0 0.0 | 0.0
----------+-------------------------------+-------------------------------+----
1 u 8k| 521 0.0 1 0.0 | 46 0.0 1 0.0 | 0.0
1 u 64k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
1 u 512k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
1 u 4m| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
- - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
1 k 8k| 161 0.0 0 0.0 | 222 0.0 9 0.0 | 0.0
1 k 64k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
1 k 512k| 0 0.0 0 0.0 | 0 0.0 0 0.0 | 0.0
1 k 4m| 0 0.0 0 0.0 | 7 0.0 0 0.0 | 0.0
==========+===============================+===============================+====
ttl | 738 0.0 1 0.0 | 567 0.0 12 0.0 | 0.0
...
trapstat の出力の一番右の %tim のカラムが各 CPU で TLB miss / TSB miss が発生している割合です。この値が 10% を超えている様であれば MPSS を使用する等の対策を取って下さい。trapstat はシステムに対する負荷が高いコマンドなので、あまり頻繁に実施しない様にして下さい。目安としては一番負荷が高い時に 10 秒程度実施します。
usr や sys の値が高く(idl の値がゼロの状態が続いて)、性能が目に見えて劣化している場合は、過負荷である可能性があります。Solaris は高負荷の状況でも非常に粘り強い OS ですが、ネットワークを使ったアプリケーションの場合は "netstat -sP tcp 1" や "dladm show-dev -s -i 1 <NIC>" 等でエラーが発生していないか確認して下さい。
# dladm show-dev -s -i 1 e1000g0 ipackets rbytes ierrors opackets obytes oerrors e1000g0 140895 9390183 0 507 75864 0 ipackets rbytes ierrors opackets obytes oerrors e1000g0 3 192 0 2 340 0 ipackets rbytes ierrors opackets obytes oerrors e1000g0 4 256 0 2 246 0
sys が多い場合
特定の CPU 又は全ての CPU で sys が 20% 以上出ている場合は、カーネルサービスの CPU 使用率が多くなっています。具体的にはシステムコールやスケジューラ、ファイルシステム等が該当します。sys が多い場合はシステムチューニングの余地があるかもしれません。
sys が多く syscl のカラムも高い数値を示している場合、システムコールが sys の発生源になっている可能性があります。まずは prstat で CPU 負荷の高いプロセスを探します。prstat のオプションは -m を付けて下さい。
% prstat -m 1
PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP
29044 root 0.0 0.1 0.0 0.0 0.0 0.0 100 0.0 42 0 256 0 prstat/1
14923 noaccess 0.0 0.0 0.0 0.0 0.0 68 32 0.0 19 1 19 0 java/19
751 root 0.0 0.0 0.0 0.0 0.0 3.4 97 0.0 41 0 205 0 nscd/29
9819 root 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 snmpd/1
29032 root 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 in.telnetd/1
10465 smmsp 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 sendmail/1
9666 root 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 dmispd/1
9660 root 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 snmpXdmid/2
9122 root 0.0 0.0 0.0 0.0 0.0 0.0 100 0.0 0 0 0 0 snmpdx/1
prstat の出力は CPU 使用率の高い順にソートされるので、上の方に表示されているプロセスが一番 CPU 負荷の高いプロセスです。SYS のカラムを見るとそのプロセスがどのくらい sys を発生させているかが分かります。SYS の値が大きいプロセスを見つけたら、そのプロセスに対し truss を掛けてシステムコールの統計を観察します。
# truss -cp <PID>
時間を多く使っているシステムコールがあれば、そのシステムコールが sys の原因である可能性があります。
syscl の値が小さい場合はシステムコール以外のカーネルサービスが時間を使っている可能性があります。もしインタラプト処理に CPU を使用している場合は intrstat や lockstat -I コマンドで調べる事が可能です。
# intrstat 1 # lockstat -kgIW sleep 10
Ultra SPARC T1 の浮動小数点数演算命令シミュレーションが発生していると sys が増えます。Ultra SPARC T1 の浮動小数点数演算命令のシミュレーションが起きているかどうかは kstat で確認する事が出来ます。
% kstat -p 'unix::fpu_info:fpu_sim*' 1
idl が多い場合
どのプロセッサでも平均して idl が出ている場合は CPU 以外のリソースがボトルネックになっていると考えられます。メモリ、ネットワーク、ディスク等のリソースに不足がないか確認して下さい。
CPU 以外のリソースにも不足が無い場合はリソースが余っている可能性があります。その場合は負荷を増やして挙動を観察してみて下さい。
CPU によって idl の値に偏りがある場合
幾つかの CPU では idl が 0 なのに、残りの CPU では idl が 100 の場合があります。これはプログラムがスケールしていない状態です。その場合は prstat でアプリケーションのスレッド数を確認して下さい。prstat の出力の一番右端、NLWP のカラムがスレッド数です。スレッド数が CPU 数よりも少ない場合は、(可能であれば)スレッド数を増やしてみるのも手です。
スレッド数が CPU の数より多いのにも関わらず CPU が使い切れていない場合はプログラムの作りに問題がある可能性があります。prstat -L でスレッドのアクティビティを観察して下さい。特定のスレッドの処理量が多い場合は、そのスレッドがボトルネックになっている可能性があります。Web Server 等のネットワークサーバでは少数のディスパッチャースレッドと多数のワーカースレッドという構成になっていて、ディスパッチャーの部分がボトルネックになるケースがあります。truss でプログラムの動きをトレースすると、特定のスレッドが張り付いている場合は同じスレッド ID のスレッドばかりが処理を行うので一つの目安となります。
% prstat -L 1 % truss -vall -D -p <PID>
特定の CPU に張り付いているスレッドが見られない場合はロックの競合が発生している可能性があります。plockstat でどのくらい競合が発生しているか確認して下さい。例えば、Solaris の標準の malloc() 関数はシングルスレッドで性能が出る様な実装になっており、複数のスレッドで同時にメモリを確保しようとするとロックの競合が発生します。複数のスレッドで同時に動的にメモリを確保する必要がある場合は mtmalloc ライブラリをプリロードするとスケーラビリティが向上します。
% plockstat -Cv -e 10 -p <PID>
ロックの競合が発生していると lwp_park というシステムコールが多く呼び出されている事があります。lwp_park が発生している場合はスレッドが休止しています。lwp_park の発生は truss コマンドで確認出来ます。また、どの関数コールが lwp_park の原因になっているかは DTrace を使う事で調べる事が出来ます。
# truss -cp <PID>
# dtrace -n 'syscall::lwp_park:entry /execname == "<PROCESS NAME>"/ { @[ustack(22)] = count() }'
スレッド数が増やせない、又はこれ以上スケールしないと分かった場合はプログラムの起動数を増やす事が出来るか確認して下さい。特定のポートで Listen する必要がある場合は Zone を構成して IP Address を分散させる事でリソースを有効に使う事が出来ます。併せて psrset でプロセッサセットを作成すると CPU の利用状況が分散されてリソース効率が上がる場合があります。
また、どのプロセッサでも平均して idl が出ているのに、実際は CPU が張り付いているというケースもあります。これを確認するには prstat でスレッド毎の CPU 使用率を観察します。-L オプションを付けるとスレッド毎の統計が表示されます。 prstat -L の CPU のカラムは 100 / CPU 数が最大です。1 つのスレッドの CPU 使用率が 100 / CPU 数に近い値になっている場合はスレッドが CPU に張り付いていると考えられます。該当のスレッドを pbind してあげると、綺麗に 1 つの CPU に張り付くと思います。
% prstat -L 1 % pbind -b <CPUID> <PID>/<TID>
intr が多い場合
intr が多く発生している場合は高レベルの割り込みが多く発生している状態です。NIC 等のデバイスに負荷が掛かっている場合によく発生します。インタラプトの詳細は intrstat や lockstat -I で確認して下さい。
# intrstat 1 # lockstat -kgIW sleep 10
icsw が多い場合
icsw が多い場合はシステムリソースに対して負荷が高すぎる可能性があります。頻繁にコンテキストスイッチが発生すると性能に大きく影響します。適切な負荷になる様にスレッド数やプロセス数を調節して下さい。
migr が多い場合
migr が 200 を超える場合は /etc/system で rechoose_interval を増やしてみると効果があるかもしれません。
smtx が多い場:
smtx が多い場合は何のロックでスピンしているのか、lockstat や plockstat で確かめて下さい。lockstat はシステム全体の統計、plockstat はプロセスレベルの統計です。
# lockstat -g -D 10 sleep 10 # plockstat -Cve 5 -x bufsize=10k -x aggsize=2m -p <PID>
srw が多い場合
srw が多い場合は、同様に lockstat や plockstat で調べてみて下さい。
syscl が多い場合
syscl が多い場合は truss -c や DTrace を使って、どのシステムコールが多く発生しているのかを確認して下さい。
終わりに
以上、mpstat コマンドの出力の読み方をご紹介しました。mpstat は vmstat や iostat コマンドと並んで性能解析の基本的なコマンドです。どんなベンチマークでも mpstat コマンドを使用しない事はありません。特に CPU のコア数やストランド数が多い場>合やスレッド数の多いプログラムでベンチマークを行う際には必須のコマンドです。是非ご活用下さい。
参考文献
- http://blogs.sun.com/anish/entry/hardware_interrupts_overview_for_solaris
- http://developers.sun.com/solaris/articles/processbehavior.html
- http://prefetch.net/articles/dtracecookbook.html
Posted at 03:25午後 4 21, 2009 by Daisuke Homma in Sun | 投稿されたコメント[0]
ネットワークを調査する 50 の方法
はじめに
今回は Solaris でネットワークの性能や障害を調査するコマンドをご紹介したいと思います。私が普段よく使用する物を中心に、用途別に大体 50 種類の手順をまとめました。
ネットワークの解析方法
ネットワークインターフェイスの一覧を表示する
ifconfig -a
現在使用可能なネットワークインターフェイスの一覧は "ifconfig -a" で調べる事が出来ます。インターフェイス名、MTU、IP アドレス、ネットマスク等の情報も得る事が出来ます。
% ifconfig -a
lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255
root ユーザで実行した場合は MAC アドレスも表示されます。
# ifconfig -a
lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255
ether 0:23:8b:64:88:60
"ifconfig -a plumb" で全てのインターフェイスを有効にしてから "ifconfig -a" を実行すると、システムで利用可能な全てのインターフェイスを表示する事が出来ます。
# ifconfig -a plumb
ifconfig: SIOCSLIFNAME for ip: e1000g0: already exists
# ifconfig -a
lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255
ether 0:23:8b:64:88:60
e1000g1: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 3
inet 0.0.0.0 netmask 0
ether 0:23:8b:64:88:61
e1000g2: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 4
inet 0.0.0.0 netmask 0
ether 0:23:8b:64:88:62
e1000g3: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 5
inet 0.0.0.0 netmask 0
ether 0:23:8b:64:88:63
dladm show-dev
"dladm show-dev" コマンドでもインターフェイスの一覧を表示する事が出来ます。リンクの状態やリンクスピード、デュプレックスの情報も入手出来ます。また、有効になっていないインターフェイスについても見る事が出来ます。dladm コマンドは root ユーザで実行する必要があります。
# dladm show-dev e1000g0 link: up speed: 100 Mbps duplex: full e1000g1 link: down speed: 0 Mbps duplex: half e1000g2 link: down speed: 0 Mbps duplex: half e1000g3 link: down speed: 0 Mbps duplex: half
dladm show-link
"dladm show-link" をすると、リンクタイプや MTU を表示する事が出来ます。
# dladm show-link e1000g0 type: non-vlan mtu: 1500 device: e1000g0 e1000g1 type: non-vlan mtu: 1500 device: e1000g1 e1000g2 type: non-vlan mtu: 1500 device: e1000g2 e1000g3 type: non-vlan mtu: 1500 device: e1000g3
インターフェイス名のみを取得するスクリプト
シェルスクリプトで NIC の名前だけをリストにして抜き出せると便利です。以下の一行を実行すると ${NIC} にリンクアップしているインターフェイスの名前がスペース区切りで格納されます。
# NIC=`dladm show-dev -p | grep 'link=up' | awk '{printf "%s ", $1}'`
これはスクリプトの中で使うと便利です。以下のスクリプトでは各インターフェイスについて "dladm show-dev -s -i 1 <NIC>" を実行して統計情報をログに保存しています。
#!/bin/sh
NIC=`dladm show-dev -p | grep 'link=up' | awk '{printf "%s ", $1}'`
for i in ${NIC}
do dladm show-dev -s -i 1 ${i} > dladm-${i}.log &
done
インターフェイスの状態を調べる
インターフェイスがリンクアップしているかどうかは "kstat -p ':::link_up'" でも調べられます。1 がリンクアップです。
# kstat -p ':::link_up' e1000g:0:mac:link_up 1 e1000g:1:mac:link_up 0 e1000g:2:mac:link_up 0 e1000g:3:mac:link_up 0
インターフェイスのリンクスピードは "kstat -p ':::link_speed'" でも調べられます。単位は Mbps です。
# kstat -p ':::link_speed' e1000g:0:statistics:link_speed 100 e1000g:1:statistics:link_speed 0 e1000g:2:statistics:link_speed 0 e1000g:3:statistics:link_speed 0
インターフェイスのデュプレックスは "kstat -p ':::duplex'" でも調べられます。2 が full duplex です。
# kstat -p ':::link_duplex' e1000g:0:mac:link_duplex 2 e1000g:1:mac:link_duplex 1 e1000g:2:mac:link_duplex 1 e1000g:3:mac:link_duplex 1
ネットワークセッションの一覧を表示する
netstat -a
"netstat -a" コマンドを使用すると現在のソケットの状態を調べる事が出来ます。State が "ESTABLISHED" になっているソケットはセッションが確立している接続です。
# netstat -a
...
TCP: IPv4
Local Address Remote Address Swind Send-Q Rwind Recv-Q State
-------------------- -------------------- ----- ------ ----- ------ -----------
*.* *.* 0 0 49152 0 IDLE
*.sunrpc *.* 0 0 49152 0 LISTEN
*.* *.* 0 0 49152 0 IDLE
*.32771 *.* 0 0 49152 0 LISTEN
*.32772 *.* 0 0 49152 0 LISTEN
...
sanuki05.5001 10.16.62.7.35163 49640 0 49640 0 ESTABLISHED
sanuki05.5001 10.16.62.7.35164 49640 0 49640 0 ESTABLISHED
sanuki05.5001 10.16.62.7.35165 49640 0 49640 0 ESTABLISHED
sanuki05.5001 10.16.62.7.35166 49640 0 49640 0 ESTABLISHED
sanuki05.5001 10.16.62.7.35167 49640 0 49640 0 ESTABLISHED
"netstat -aP tcp -f inet" を実行すると、IPv4 で TCP を使用しているソケットだけを抜き出す事が出来ます。
# netstat -aP tcp -f inet
TCP: IPv4
Local Address Remote Address Swind Send-Q Rwind Recv-Q State
-------------------- -------------------- ----- ------ ----- ------ -----------
*.* *.* 0 0 49152 0 IDLE
*.sunrpc *.* 0 0 49152 0 LISTEN
*.* *.* 0 0 49152 0 IDLE
*.32771 *.* 0 0 49152 0 LISTEN
*.32772 *.* 0 0 49152 0 LISTEN
*.lockd *.* 0 0 49152 0 LISTEN
...
セッション数を調べる
netstat -a | grep ESTAB | wc -l
"netstat -a | grep ESTAB | wc -l" を実行すると、現在繋がっているネットワークセッションの本数を調べる事が出来ます。以下の様に while 分で回せば、毎秒のセッション数の増減を記録する事が出来ます。以下の例では 34 本のセッションが張られています。
# while :; do netstat -a | grep ESTAB | wc -l; sleep 1; done
34
34
34
"netstat -a | grep telnet | grep ESTAB | wc -l" を実行すると、telnet のセッションだけを抜き出す事が出来ます。同じ様に while で回せば、telnet セッションの増減を記録する事が出来ます。telnet 以外にも http や 1521 番の Oracle のセッションだけを抜き出す事も可能です。以下の例では 8 本の telnet セッションが張られています。
# while :; do netstat -a | grep telnet | grep ESTAB | wc -l; sleep 1; done
8
8
8
kstat -p tcp:0:tcp:currEstab 1
"kstat -p tcp:0:tcp:currEstab 1" を実行すると TCP のセッション数を出力します。この値は /usr/src/uts/common/inet/tcp/tcp.c の tcp_kstat_update() 関数で集計されています。
% kstat -p tcp:0:tcp:currEstab 1 tcp:0:tcp:currEstab 4 tcp:0:tcp:currEstab 4 tcp:0:tcp:currEstab 3
スループットを調べる
dladm show-dev -s -i 1 <NIC>
"dladm show-dev -s -i 1 <NIC>" を実行すると、受信したパケット数(ipackets)、受信したデータのバイト数(rbytes)、受信の際に発生したエラーの数(ierrors)、送信したパケット数(opackets)、送信したデータのバイト数(obytes)、送信の際に発生したエラーの数(oerrors)を 1 秒毎に表示する事が出来ます。最初の出力はブートしてからの累積値です。
# dladm show-dev -s -i 1 e1000g0
ipackets rbytes ierrors opackets obytes oerrors
e1000g0 4048080 2168050372 0 611314 120697887 0
ipackets rbytes ierrors opackets obytes oerrors
e1000g0 5 320 0 2 366 0
ipackets rbytes ierrors opackets obytes oerrors
e1000g0 6 384 0 2 280 0
netstat -i -I <NIC> 1
"netstat -i -I <NIC> 1" でもネットワークのスループットを表示する事が出来ますが、送受信バイト数を見る事は出来ません。出来る限り dladm コマンドをお使い下さい。
# netstat -i -I e1000g0 1
input e1000g output input (Total) output
packets errs packets errs colls packets errs packets errs colls
4048518 0 611396 0 0 4048688 0 611566 0 0
3 0 1 0 0 3 0 1 0 0
4 0 2 0 0 4 0 2 0 0
kstat -p '<NIC>:::*bytes' 1
"kstat -p '<NIC>:::*bytes' 1" を実行すると送受信バイト数の累積を表示する事が出来ます。これが dladm や netstat の出力の元データです。kstat の引数はインターフェイス毎に多少異なります。kstat のデータは殆ど整形されていない生データなので加工してお使い下さい。
# kstat -p 'e1000g:0:e1000g0:*bytes' 1 e1000g:0:e1000g0:obytes 120717403 e1000g:0:e1000g0:rbytes 2168116829 e1000g:0:e1000g0:obytes 120717532 e1000g:0:e1000g0:rbytes 2168117213 e1000g:0:e1000g0:obytes 120717789 e1000g:0:e1000g0:rbytes 2168117597
"kstat -p '<NIC>:::*packets' 1" を実行すると送受信パケット数の累積を表示する事が出来ます。kstat には他にも便利な統計情報が入っていますので、是非お試し下さい。
# kstat -p 'e1000g:0:e1000g0:*packets' 1 e1000g:0:e1000g0:ipackets 4050305 e1000g:0:e1000g0:opackets 611558 e1000g:0:e1000g0:ipackets 4050309 e1000g:0:e1000g0:opackets 611559 e1000g:0:e1000g0:ipackets 4050315 e1000g:0:e1000g0:opackets 611561
ネットワークインターフェイスの CPU 使用率を見る
intrstat 1
"intrstat 1" を実行するとデバイスが発生させたインタラプトの処理に使用している CPU の割合を調べる事が出来ます。以下の例では e1000g0 インターフェイスが CPU 6 番を 5.0% 使用している事が分かります。
# intrstat 1
...
device | cpu0 %tim cpu1 %tim cpu2 %tim cpu3 %tim
-------------+------------------------------------------------------------
ahci#0 | 0 0.0 0 0.0 0 0.0 0 0.0
e1000g#0 | 0 0.0 0 0.0 0 0.0 0 0.0
e1000g#2 | 0 0.0 0 0.0 0 0.0 0 0.0
ehci#0 | 0 0.0 0 0.0 0 0.0 0 0.0
uhci#0 | 0 0.0 0 0.0 0 0.0 0 0.0
uhci#1 | 0 0.0 0 0.0 0 0.0 0 0.0
uhci#2 | 0 0.0 0 0.0 0 0.0 0 0.0
uhci#3 | 0 0.0 0 0.0 0 0.0 0 0.0
device | cpu4 %tim cpu5 %tim cpu6 %tim cpu7 %tim
-------------+------------------------------------------------------------
ahci#0 | 0 0.0 2 0.0 0 0.0 0 0.0
e1000g#0 | 0 0.0 0 0.0 8204 5.0 0 0.0
e1000g#2 | 0 0.0 0 0.0 1 0.0 0 0.0
ehci#0 | 18 0.0 0 0.0 0 0.0 0 0.0
uhci#0 | 18 0.0 0 0.0 0 0.0 0 0.0
uhci#1 | 0 0.0 1 0.0 0 0.0 0 0.0
uhci#2 | 0 0.0 1 0.0 0 0.0 0 0.0
uhci#3 | 0 0.0 2 0.0 0 0.0 0 0.0
ネットワークインターフェイスの統計情報を見る
kstat -p '<NIC>:::' 1
"kstat -p '<NIC>:<Instance>::' 1" を実行すると、カーネルに保存してあるインターフェイスの情報を表示する事が出来ます。kstat には性能に関する情報を含め、様々なデータが記録されています。<Instance> は ifconfig コマンド等で表示される NIC のインスタンス番号です。以下の例では e1000g0 インターフェイスの統計情報を表示しています。出力はそれぞれ重要な意味を持っています。例えば norcvbuf が発生している場合は受信用のバッファが不足している事を意味しています。
# kstat -p 'e1000g:0::' e1000g:0:e1000g0:brdcstrcv 2621877 e1000g:0:e1000g0:brdcstxmt 4542 e1000g:0:e1000g0:class net e1000g:0:e1000g0:collisions 0 e1000g:0:e1000g0:crtime 135.093656493 e1000g:0:e1000g0:ierrors 0 e1000g:0:e1000g0:ifspeed 100000000 e1000g:0:e1000g0:ipackets 4533601 e1000g:0:e1000g0:ipackets64 4533601 e1000g:0:e1000g0:multircv 21570 e1000g:0:e1000g0:multixmt 0 e1000g:0:e1000g0:norcvbuf 0 e1000g:0:e1000g0:noxmtbuf 0 e1000g:0:e1000g0:obytes 135842713 e1000g:0:e1000g0:obytes64 135842713 e1000g:0:e1000g0:oerrors 0 e1000g:0:e1000g0:opackets 846546 e1000g:0:e1000g0:opackets64 846546 e1000g:0:e1000g0:rbytes 2884822219 e1000g:0:e1000g0:rbytes64 2884822219 ...
nxge の DMA Channel の統計情報を取得する
nxge インターフェイスは複数の転送経路にデータを分散する事で高いスループットを達成しています。データの分散状況は kstat コマンドを使用して調べる事が出来ます。kstat の出力の各行が転送経路です。一番右側の数値がその経路を通って転送されたパケット数の累積値です。値の増加に偏りがある場合はインターフェイスの設定を見直して下さい。
# kstat -p 'nxge:1::*dc_packets' 1 nxge:1:RDC Channel 0 Stats:rdc_packets 17920164 nxge:1:RDC Channel 1 Stats:rdc_packets 17876325 nxge:1:RDC Channel 2 Stats:rdc_packets 18551372 nxge:1:RDC Channel 3 Stats:rdc_packets 17262833 nxge:1:RDC Channel 4 Stats:rdc_packets 17916873 nxge:1:RDC Channel 5 Stats:rdc_packets 18427140 nxge:1:RDC Channel 6 Stats:rdc_packets 18380673 nxge:1:RDC Channel 7 Stats:rdc_packets 18262768 nxge:1:TDC Channel 0 Stats:tdc_packets 25398140 nxge:1:TDC Channel 1 Stats:tdc_packets 26289370 nxge:1:TDC Channel 2 Stats:tdc_packets 25947133 nxge:1:TDC Channel 3 Stats:tdc_packets 25353460 nxge:1:TDC Channel 4 Stats:tdc_packets 27044560 nxge:1:TDC Channel 5 Stats:tdc_packets 26080875 nxge:1:TDC Channel 6 Stats:tdc_packets 25467176 nxge:1:TDC Channel 7 Stats:tdc_packets 25782669 ...
ネットワークインターフェイスのパラメータを調べる
ndd -get /dev/<NIC>
"ndd -get /dev/<NIC> \?" を実行するとインターフェイスのパラメータ一の一部を取得する事が出来ます。
# ndd -get /dev/e1000g0 \? ? (read only) autoneg_cap (read only) pause_cap (read only) asym_pause_cap (read only) 1000fdx_cap (read only) 1000hdx_cap (read only) 100T4_cap (read only) 100fdx_cap (read only) 100hdx_cap (read only) 10fdx_cap (read only) 10hdx_cap (read only) adv_autoneg_cap (read and write) ...
パラメータの値を取得する場合はパラメータ名を指定します。"(read and write)" と表示されているパラメータは -set オプションを使用して値を設定する事も可能です。
# ndd -get /dev/e1000g0 max_num_rcv_packets 128
TCP の統計情報を見る
netstat -sP tcp 1
"netstat -sP tcp 1" を実行すると TCP の統計情報を表示する事が出来ます。もし tcpListenDrop が発生していたら要対応です。
# netstat -sP tcp 1
...
TCP tcpRtoAlgorithm = 0 tcpRtoMin = 400
tcpRtoMax = 60000 tcpMaxConn = -1
tcpActiveOpens = 0 tcpPassiveOpens = 0
tcpAttemptFails = 0 tcpEstabResets = 0
tcpCurrEstab = 23 tcpOutSegs = 20
tcpOutDataSegs = 16 tcpOutDataBytes = 5568
tcpRetransSegs = 0 tcpRetransBytes = 0
tcpOutAck = 4 tcpOutAckDelayed = 2
tcpOutUrg = 0 tcpOutWinUpdate = 0
tcpOutWinProbe = 0 tcpOutControl = 0
tcpOutRsts = 0 tcpOutFastRetrans = 0
tcpInSegs = 15
tcpInAckSegs = 9 tcpInAckBytes = 5568
tcpInDupAck = 0 tcpInAckUnsent = 0
tcpInInorderSegs = 6 tcpInInorderBytes = 3122
tcpInUnorderSegs = 0 tcpInUnorderBytes = 0
tcpInDupSegs = 0 tcpInDupBytes = 0
tcpInPartDupSegs = 0 tcpInPartDupBytes = 0
tcpInPastWinSegs = 0 tcpInPastWinBytes = 0
tcpInWinProbe = 0 tcpInWinUpdate = 0
tcpInClosed = 0 tcpRttNoUpdate = 0
tcpRttUpdate = 9 tcpTimRetrans = 0
tcpTimRetransDrop = 0 tcpTimKeepalive = 0
tcpTimKeepaliveProbe= 0 tcpTimKeepaliveDrop = 0
tcpListenDrop = 0 tcpListenDropQ0 = 0
tcpHalfOpenDrop = 0 tcpOutSackRetrans = 0
kstat -p 'tcp:0::'
"kstat -p 'tcp:0::' 1" を実行すると TCP に関する統計情報を出力する事が出来ます。このコマンドで取得出来るデータが "netstat -sP tcp 1" の元になっています。
% kstat -p 'tcp:0::' 1 tcp:0:tcp:activeOpens 67462 tcp:0:tcp:attemptFails 445 tcp:0:tcp:class mib2 tcp:0:tcp:connTableSize 72 tcp:0:tcp:connTableSize6 96 tcp:0:tcp:crtime 105.965466 tcp:0:tcp:currEstab 23 tcp:0:tcp:estabResets 56804 ...
tcpstat.d
DTrace Toolkit には tcpstat.d という TCP の送受信量をカウントするスクリプトが入っています。
# ./tcpstat.d
TCP_out TCP_outRe TCP_in TCP_inDup TCP_inUn
0 0 0 0 0
122 0 0 0 0
61 0 0 0 0
61 0 0 0 0
314670 0 314609 0 0
159488 0 159427 0 0
31213 0 31152 0 0
...
ndd -get /dev/tcp
"ndd -get /dev/tcp \?" を実行すると TCP のパラメータの一部を表示する事が出来ます。
# ndd -get /dev/tcp \? ? (read only) tcp_time_wait_interval (read and write) tcp_conn_req_max_q (read and write) tcp_conn_req_max_q0 (read and write) tcp_conn_req_min (read and write) tcp_conn_grace_period (read and write) tcp_cwnd_max (read and write) tcp_debug (read and write) tcp_smallest_nonpriv_port (read and write) ...
パラメータ名を指定するとパラメータの値を取得する事が出来ます。"(read and write)" なパラメータに関しては -set を指定すると値を設定する事が出来ます。
# ndd -get /dev/tcp tcp_time_wait_interval 60000
IP の統計情報を見る
netstat -sP ip 1
"netstat -sP ip 1" を実行すると IP の統計情報を表示する事が出来ます。
% netstat -sP ip 1
...
IPv4 ipForwarding = 2 ipDefaultTTL = 255
ipInReceives = 2 ipInHdrErrors = 0
ipInAddrErrors = 0 ipInCksumErrs = 0
ipForwDatagrams = 0 ipForwProhibits = 0
ipInUnknownProtos = 0 ipInDiscards = 0
ipInDelivers = 2 ipOutRequests = 2
ipOutDiscards = 0 ipOutNoRoutes = 0
ipReasmTimeout = 0 ipReasmReqds = 0
ipReasmOKs = 0 ipReasmFails = 0
ipReasmDuplicates = 0 ipReasmPartDups = 0
ipFragOKs = 0 ipFragFails = 0
ipFragCreates = 0 ipRoutingDiscards = 0
tcpInErrs = 0 udpNoPorts = 0
udpInCksumErrs = 0 udpInOverflows = 0
rawipInOverflows = 0 ipsecInSucceeded = 0
ipsecInFailed = 0 ipInIPv6 = 0
ipOutIPv6 = 0 ipOutSwitchIPv6 = 0
...
同様に ICMP や RAWIP の統計情報を表示させる事も可能です。
% netstat -sP icmp 1
ICMPv4 icmpInMsgs = 0 icmpInErrors = 0
icmpInCksumErrs = 0 icmpInUnknowns = 0
icmpInDestUnreachs = 0 icmpInTimeExcds = 0
icmpInParmProbs = 0 icmpInSrcQuenchs = 0
icmpInRedirects = 0 icmpInBadRedirects = 0
icmpInEchos = 0 icmpInEchoReps = 0
icmpInTimestamps = 0 icmpInTimestampReps = 0
icmpInAddrMasks = 0 icmpInAddrMaskReps = 0
icmpInFragNeeded = 0 icmpOutMsgs = 0
icmpOutDrops = 0 icmpOutErrors = 0
icmpOutDestUnreachs = 0 icmpOutTimeExcds = 0
icmpOutParmProbs = 0 icmpOutSrcQuenchs = 0
icmpOutRedirects = 0 icmpOutEchos = 0
icmpOutEchoReps = 0 icmpOutTimestamps = 0
icmpOutTimestampReps= 0 icmpOutAddrMasks = 0
icmpOutAddrMaskReps = 0 icmpOutFragNeeded = 0
icmpInOverflows = 0
kstat -p 'ip:::' 1
"kstat -p 'ip:::' 1" を実行すると、カーネル内に保存されている IP に関する統計情報を出力する事が出来ます。これが "netstat -sP ip 1" の出力の元データです。
% kstat -p 'ip:::' 1 ... ip:0:ip:inDelivers 4629963 ip:0:ip:inDiscards 0 ip:0:ip:inErrs 0 ip:0:ip:inHdrErrors 0 ip:0:ip:inIPv6 0 ip:0:ip:inReceives 4862389 ip:0:ip:inUnknownProtos 21643 ...
ndd -get /dev/ip
"ndd -get /dev/ip \?" を実行すると IP のパラメータの一部を取得する事が出来ます。
# ndd -get /dev/ip \? ? (read only) ip_respond_to_address_mask_broadcast(read and write) ip_respond_to_echo_broadcast (read and write) ip_respond_to_echo_multicast (read and write) ip_respond_to_timestamp (read and write) ip_respond_to_timestamp_broadcast(read and write) ip_send_redirects (read and write)
パラメータ名を指定すると値を取得する事が出来ます。"(read and write)" と表示されているパラメータは -set オプションで値を設定する事も可能です。
# ndd -get /dev/ip ip_lso_outbound 1
どんなパケットが流れているかを調べる
snoop -d <NIC>
"snoop -d <NIC>" を実行すると、送受信したパケット毎に送信元 IP アドレス、宛先 IP アドレス、プロトコル、ポート番号等を調べる事が出来ます。他の OS の tcpdump に相当するコマンドです。"TELNET" と表示されているパケットは telnet のパケットです。-r オプションは名前解決をさせない為に付けていますが、必ずしも付ける必要はありません。snoop の実行はそれ自体がネットワークの負荷になりますので、必要な時にだけ使用して下さい。
# snoop -r -d e1000g0
Using device /dev/e1000g0 (promiscuous mode)
10.16.100.16 -> 10.16.67.5 TELNET C port=40383
10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev/e1
10.16.100.16 -> 10.16.67.5 TELNET C port=40383
10.16.11.16 -> (broadcast) ARP C Who is 10.16.0.200, 10.16.0.200 ?
10.16.64.5 -> (broadcast) ARP C Who is 10.16.201.102, 10.16.201.102 ?
? -> * ETHER Type=9000 (Loopback), size = 60 bytes
パケットサイズを調べる
snoop -d <NIC> -S
"snoop -d <NIC> -S" を実行すると length: に続いてパケットのサイズを出力させる事が可能です。パケットのサイズによってネットワークの負荷が変わってきます(一般にパケットが小さい方が負荷が高い)。
# snoop -d e1000g0 -S
10.16.98.12 -> (broadcast) length: 60 ARP C Who is 10.16.38.2, 10.16.38.2 ?
? -> (multicast) length: 52 ETHER Type=0000 (LLC/802.3), size = 52 bytes
10.16.38.2 -> 10.255.255.255 length: 178 BPARAM C GETFILE root
10.16.64.5 -> (broadcast) length: 60 ARP C Who is 10.16.64.54, 10.16.64.54 ?
10.16.98.16 -> (broadcast) length: 60 ARP C Who is 10.16.38.2, 10.16.38.2 ?
詳しくパケットの中身を調べる
snoop -d <NIC> -V
"snoop -r -d <NIC> -V" を実行するとネットワークの階層毎に詳細な情報を出力させる事が出来ます。"________________________________" で挟まれている部分が一つのパケットです。"ETHER"、"IP"、"TCP"、"TELNET" と階層毎に一行出力されているのが分かります。
# snoop -r -d e1000g0 -V Using device /dev/e1000g0 (promiscuous mode) ________________________________ 10.16.100.16 -> 10.16.67.5 ETHER Type=0800 (IP), size = 60 bytes 10.16.100.16 -> 10.16.67.5 IP D=10.16.67.5 S=10.16.100.16 LEN=40, ID=44170, TOS=0x0, TTL=64 10.16.100.16 -> 10.16.67.5 TCP D=23 S=40383 Ack=2979015144 Seq=1218855275 Len=0 Win=49640 10.16.100.16 -> 10.16.67.5 TELNET C port=40383 ________________________________ 10.16.67.5 -> 10.16.100.16 ETHER Type=0800 (IP), size = 100 bytes 10.16.67.5 -> 10.16.100.16 IP D=10.16.100.16 S=10.16.67.5 LEN=86, ID=8412, TOS=0x0, TTL=60 10.16.67.5 -> 10.16.100.16 TCP D=40383 S=23 Push Ack=1218855275 Seq=2979015144 Len=46 Win=49640 10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev/e1 ________________________________
snoop -d <NIC> -v
"snoop -d <NIC> -v" を実行すると更に詳しくパケットの中身を調べる事が出来ます。各ヘッダの中身とペイロードの中身が可能な限り分かりやすく整形されて出力されます。
# snoop -d <NIC> -v ... ETHER: ----- Ether Header ----- ETHER: ETHER: Packet 2999 arrived at 17:59:25.31440 ETHER: Packet size = 91 bytes ETHER: Destination = 0:3:ba:37:34:a8, ETHER: Source = 0:23:8b:64:88:60, ETHER: Ethertype = 0800 (IP) ETHER: IP: ----- IP Header ----- IP: IP: Version = 4 IP: Header length = 20 bytes IP: Type of service = 0x00 IP: xxx. .... = 0 (precedence) IP: ...0 .... = normal delay IP: .... 0... = normal throughput IP: .... .0.. = normal reliability IP: .... ..0. = not ECN capable transport IP: .... ...0 = no ECN congestion experienced IP: Total length = 77 bytes IP: Identification = 18244 IP: Flags = 0x4 IP: .1.. .... = do not fragment IP: ..0. .... = last fragment IP: Fragment offset = 0 bytes IP: Time to live = 60 seconds/hops IP: Protocol = 6 (TCP) IP: Header checksum = 0000 IP: Source address = 10.16.67.5, 10.16.67.5 IP: Destination address = 10.16.100.16, 10.16.100.16 IP: No options IP: TCP: ----- TCP Header ----- TCP: TCP: Source port = 23 TCP: Destination port = 40383 TCP: Sequence number = 2990317620 TCP: Acknowledgement number = 1218855394 TCP: Data offset = 20 bytes TCP: Flags = 0x18 TCP: 0... .... = No ECN congestion window reduced TCP: .0.. .... = No ECN echo TCP: ..0. .... = No urgent pointer TCP: ...1 .... = Acknowledgement TCP: .... 1... = Push TCP: .... .0.. = No reset TCP: .... ..0. = No Syn TCP: .... ...0 = No Fin TCP: Window = 49640 TCP: Checksum = 0xbb74 TCP: Urgent pointer = 0 TCP: No options TCP: TELNET: ----- TELNET: ----- TELNET: TELNET: "IP: ----- IP Header -----\r\nIP: \r\n" TELNET: ...
snoop -d <NIC> -x <OFFSET>
"snoop -d <NIC> -x <OFFSET>" を実行すると、パケットの中身をダンプする事が出来ます。通信の内容を調査したい時に使用して下さい。<OFFSET> をゼロにするとパケットのヘッダも含めて全てのデータをダンプする事が出来ます。以下は telnet ポートの通信をペイロードのみ表示させた例です。telnet で接続した状態で id コマンドを を発行して "uid=0(root) gid=0(root)" の出力を得ています。
# snoop -r -d e1000g0 -x 54 port 23
Using device /dev/e1000g0 (promiscuous mode)
10.16.100.16 -> 10.16.67.5 TELNET C port=40386 i
0: 6900 0000 0000 i.....
10.16.67.5 -> 10.16.100.16 TELNET R port=40386 i
0: 69 i
10.16.100.16 -> 10.16.67.5 TELNET C port=40386
0: 0000 0000 0000 ......
10.16.100.16 -> 10.16.67.5 TELNET C port=40386 d
0: 6400 0000 0000 d.....
10.16.67.5 -> 10.16.100.16 TELNET R port=40386 d
0: 64 d
10.16.100.16 -> 10.16.67.5 TELNET C port=40386
0: 0000 0000 0000 ......
10.16.100.16 -> 10.16.67.5 TELNET C port=40386
0: 0d00 0000 0000 ......
10.16.67.5 -> 10.16.100.16 TELNET R port=40386
0: 0d0a ..
10.16.100.16 -> 10.16.67.5 TELNET C port=40386
0: 0000 0000 0000 ......
10.16.67.5 -> 10.16.100.16 TELNET R port=40386 uid=0(root) gid=0(ro
0: 7569 643d 3028 726f 6f74 2920 6769 643d uid=0(root) gid=
16: 3028 726f 6f74 290d 0a23 20 0(root)..#
10.16.100.16 -> 10.16.67.5 TELNET C port=40386
0: 0000 0000 0000 ......
パケットをファイルにダンプする
snoop -o <FILE> -d <NIC>
"snoop -o <FILE> -d <NIC> を実行すると送受信したパケットを全てファイルに保存する事が出来ます。通信の内容を一旦ファイルに保存して後でゆっくり解析する事が出来るので非常に便利です。通信量に応じてファイルのサイズも大きくなりますので、ご注意下さい。
# snoop -o /var/tmp/snoop01.dump -d e1000g0 Using device /dev/e1000g0 (promiscuous mode) 24 ^C
保存したファイルは "snoop -i <FILE>" で読み込む事が出来ます。今までご紹介した snoop のオプションも合わせて使用する事が出来ます。
# snoop -r -i /var/tmp/snoop01.dump -V | head ________________________________ 1 0.00000 10.16.100.16 -> 10.16.67.5 ETHER Type=0800 (IP), size = 60 bytes 1 0.00000 10.16.100.16 -> 10.16.67.5 IP D=10.16.67.5 S=10.16.100.16 LEN=40, ID=21844, TOS=0x0, TTL=64 1 0.00000 10.16.100.16 -> 10.16.67.5 TCP D=23 S=40383 Ack=3027145344 Seq=1218855542 Len=0 Win=49640 1 0.00000 10.16.100.16 -> 10.16.67.5 TELNET C port=40383 ________________________________ 2 0.00001 10.16.67.5 -> 10.16.100.16 ETHER Type=0800 (IP), size = 104 bytes 2 0.00001 10.16.67.5 -> 10.16.100.16 IP D=10.16.100.16 S=10.16.67.5 LEN=90, ID=28393, TOS=0x0, TTL=60 2 0.00001 10.16.67.5 -> 10.16.100.16 TCP D=40383 S=23 Push Ack=1218855542 Seq=3027145344 Len=50 Win=49640 2 0.00001 10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev
別のホストに到達可能かを調べる
ping <HOST>
"ping <HOST>" を実行すると、指定したホストまで到達可能か確認する事が出来ます。
# ping 10.16.62.7 10.16.62.7 is alive
"ping -s <HOST>" を実行すると、定期的に ping を打つ事が出来ます。
# ping -s 10.16.62.7 PING 10.16.62.7: 56 data bytes 64 bytes from 10.16.62.7: icmp_seq=0. time=0.872 ms 64 bytes from 10.16.62.7: icmp_seq=1. time=0.280 ms 64 bytes from 10.16.62.7: icmp_seq=2. time=0.214 ms ^C ----10.16.62.7 PING Statistics---- 3 packets transmitted, 3 packets received, 0% packet loss round-trip (ms) min/avg/max/stddev = 0.214/0.455/0.872/0.36
ブロードキャストアドレス宛に ping を打つと同じセグメントに居るマシンを調べる事が出来ます。
# ping -s 10.16.255.255 PING 10.16.255.255: 56 data bytes 64 bytes from sanuki05.jp.iforce.net (10.16.67.5): icmp_seq=0. time=0.0850 ms 64 bytes from 10.16.11.15: icmp_seq=0. time=0.325 ms 64 bytes from 10.16.65.51: icmp_seq=0. time=0.485 ms 64 bytes from 10.16.11.13: icmp_seq=0. time=0.581 ms 64 bytes from 10.16.62.65: icmp_seq=0. time=0.666 ms ...
ルーティングテーブルを表示する
netstat -nr
"netstat -r" を実行するとルーティングテーブルを表示する事が出来ます。"default" の行がデフォルトゲートウェイです。経路情報が正しくないと宛先のホストに到達する事が出来ません。
# netstat -nr Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 10.16.0.254 UG 1 1054 10.16.0.0 10.16.67.5 U 1 202 e1000g0 224.0.0.0 10.16.67.5 U 1 0 e1000g0 127.0.0.1 127.0.0.1 UH 4 77 lo0
"route -f" を実行するとルーティングテーブルを最新の状態に更新する事が出来ます。
# route -f
宛先ホストまでの経路を調べる
traceroute <HOSTNAME>
"traceroute <HOSTNAME>" を実行すると、宛先ホストまでの経路を調べる事が出来ます。
# traceroute 10.16.0.254 traceroute to 10.16.0.254 (10.16.0.254), 30 hops max, 40 byte packets 1 10.16.100.254 (10.16.100.254) 0.474 ms * 0.493 ms
プロセスが開いているソケットを調べる
pfiles <PID>
"pfiles <PID>" を実行すると、プロセスが開いているファイルとソケットを調べる事が出来ます。以下の例では sshd プロセスがポート 22 番を開いている事が分かります。どのホスト宛にどんなオプションで幾つのセッションを張っているのかを把握する事はネットワークの解析に役立ちます。
# pfiles 570
570: /usr/lib/ssh/sshd
Current rlimit: 256 file descriptors
0: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
O_RDWR|O_LARGEFILE
/devices/pseudo/mm@0:null
1: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
O_RDWR|O_LARGEFILE
/devices/pseudo/mm@0:null
2: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
O_RDWR|O_LARGEFILE
/devices/pseudo/mm@0:null
3: S_IFSOCK mode:0666 dev:291,0 ino:50619 uid:0 gid:0 size:0
O_RDWR|O_NONBLOCK
SOCK_STREAM
SO_REUSEADDR,SO_SNDBUF(49152),SO_RCVBUF(49152),IP_NEXTHOP(0.192.0.0)
sockname: AF_INET6 :: port: 22
7: S_IFREG mode:0666 dev:285,1 ino:65539 uid:0 gid:0 size:0
O_RDWR|O_LARGEFILE
/system/contract/process/template
以下のコマンドを実行すると全てのプロセスが開いているソケットをプロセス毎に調べる事が出来ます。
# ps -eo pid,fname | grep -v PID | while read pid fname; do echo ${fname}; pfiles ${pid} | egrep 'peername|sockname' ; done
プロセスが発行したシステムコールを監視する
truss -cp <PID>
"truss -cp <PID>" を実行するとプロセスが発行したシステムコールとその回数を調べる事が出来ます。ネットワークの送受信もシステムコールを利用しています。例えば以下の例は sshd をトレースした物ですが、read, write, shutdown 等はネットワークのトラフィックに使用されたシステムコールです。システムコールの種類や回数は性能に大きく影響します。予想したよりもスループットが出ていない場合は、このコマンドを試してみて下さい。なお、<PID> に指定するプロセス ID は pgrep コマンドで渡す事も可能です。
# truss -cp `pgrep -xn sshd`
signals ------------
SIGCLD 1
total: 1
syscall seconds calls errors
_exit .000 1
read .185 9804 1
write .152 9641
close .000 4
chmod .000 1
chown .000 1
brk .000 2
getuid .000 1
sigaction .000 1
setcontext .000 1
waitid .000 2 1
lwp_sigmask .128 19433
pollsys .081 9717
stat64 .000 1
shutdown .000 1
-------- ------ ----
sys totals: .549 48611 2
usr time: .256
elapsed: 5.690
truss -vall -E -p <PID>
"truss -vall -E -p <PID>" を実行するとプロセスが発行しているシステムコールを逐次表示する事が出来ます。システムコールに消費した時間、引数、返り値等も合わせて調べる事が出来るので、ネットワークの解析にも非常に有効です。snoop コマンドではパケットレベルでの通信内容を見る事が出来ましたが、truss を使用するとアプリケーションレベルで通信内容を調べる事が出来ます。以下の例では telnet で "ls" と入力しています。
# truss -vall -E -p `pgrep -xn telnet`
pollsys(0x08047670, 2, 0x00000000, 0x00000000) (sleeping...)
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=POLLOUT
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=POLLRDNORM
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
0.0000 read(0, " l", 1024) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
timeout: 0.000000000 sec
0.0000 send(4, " l", 1, 0) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 0
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
timeout: 0.000000000 sec
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=POLLRDNORM
0.0000 recv(4, " l", 1024, 0) = 1
0.0000 pollsys(0x08047670, 3, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=1 ev=POLLOUT rev=POLLOUT
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
timeout: 0.000000000 sec
0.0000 write(1, " l", 1) = 1
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=POLLRDNORM
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
0.0000 read(0, " s", 1024) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
timeout: 0.000000000 sec
0.0000 send(4, " s", 1, 0) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 0
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
timeout: 0.000000000 sec
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=POLLRDNORM
0.0000 recv(4, " s", 1024, 0) = 1
0.0000 pollsys(0x08047670, 3, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=1 ev=POLLOUT rev=POLLOUT
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
timeout: 0.000000000 sec
0.0000 write(1, " s", 1) = 1
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=POLLRDNORM
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
0.0000 read(0, "\r", 1024) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
timeout: 0.000000000 sec
truss -o <FILE> -vall -E -p <PID>
truss も snoop と同様にファイルにダンプする事が可能です。
# truss -o /var/tmp/truss01.dump -vall -E -p `pgrep -xn telnet`
ダンプしたファイルはテキストファイルです。
# head /var/tmp/truss01.dump
pollsys(0x08047670, 2, 0x00000000, 0x00000000) (sleeping...)
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLRDNORM|POLLRDBAND rev=POLLOUT
0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=POLLRDNORM
fd=4 ev=POLLRDNORM|POLLRDBAND rev=0
0.0000 read(0, " l", 1024) = 1
0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000) = 1
fd=0 ev=POLLRDNORM rev=0
fd=4 ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
プロセス毎にトラフィックを監視する
tcpwdist.d
DTrace Toolkit には tcpwdist.d というプロセス毎に TCP の送受信サイズの分布を調査するスクリプトが入っています。
# ./tcpwdist.d
Tracing... Hit Ctrl-C to end.
^C
PID: 0 CMD: sched\0
value ------------- Distribution ------------- count
1 | 0
2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
4 | 0
PID: 19299 CMD: /usr/sbin/dtrace -s ./tcpwdist.d\0
value ------------- Distribution ------------- count
8 | 0
16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1
32 | 0
PID: 19246 CMD: telnet 10.16.100.16\0
value ------------- Distribution ------------- count
0 | 0
1 |@ 13
2 | 3
4 | 3
8 | 1
16 | 6
32 |@ 12
64 |@ 22
128 |@ 15
256 |@@@@@@@@@@@@@@@@ 258
512 |@@ 28
1024 |@@@@@@@@@@@@@@@@@@ 286
2048 | 0
おわりに
以上 Solaris のネットワーク解析ツールの内、基本的な物をご紹介しました。状況に応じて各コマンドを使い分け、問題解決にお役立て下さい。DTrace や kstat を使用すると、更に詳細な分析を行う事も可能です。是非ご活用下さい。
Posted at 03:17午後 4 20, 2009 by Daisuke Homma in Sun | 投稿されたコメント[0]










