2009年 6月 29日 月曜日
やっぱり Sun がスキ!
StarSuite (OpenOffice) で写真の背景を透明化するには
仕事柄、お客様に製品やソリューションのご紹介をすること が多いのですが、プレゼンテーションの資料作りにはいつも StarSuite のお世話になっています。写真をペタペタ貼って 視覚に訴えるのが好きなので、ファイルサイズはいつも10MB 近くになってしまいます。なのでCPUが速すぎて困るなん てことはありません。
サンの社員としては当然、サン製品の写真を多用するわけで、 そういうときは http://photos.sun.com/ からダウンロードします。ログイン の必要なページもありますが、"Products" のページは誰でも アクセスできますので、覚えておいて損は無いと思います。 きれいな製品写真が入手できるのでとても便利です。
ところで、製品単体を紹介する場合はこれで良いのですが、 最近はソリューション提案というのが重要らしく、従って プレゼン資料も1つのページに何枚も写真を貼らなくては なりません。で、実際切り貼りしてみると気が付くのですが、 写真の周辺部が透明でないとどうしても2枚の写真を寄せら れないんですね。フォトレタッチソフトを使えば良いのでしょ うが、どうも面倒です。
そういう時便利なのがスポイト機能です。この機能を使う には、プレゼンテーションファイルを開いた状態で、プル ダウンメニューの "ツール"->"スポイト" を選択・クリック します。するとスポイトダイアログが現れます。
左側に4つあるチェックボックスのうち、上の1つをチェック し、置換候補を「塗りつぶしなし」にした後、マウスを写真の 上へ持ってくると、スポイトダイアログの左上のボックスが マウスの指している部分の色に変わります。マウスを写真の周辺 部に置いて透明にしたい色が決まったら左クリックし、スポイト ダイアログの「置換」ボタンを押します。
こんなふうに重ね合わせも自然な感じです。皆さんもぜひ ご活用ください。知的生産性向上間違いなしです。
Posted at 10:33午前 6 29, 2009 by masahiko in Sun | 投稿されたコメント[1]
統計情報を一挙に取得するスクリプト
はじめに
今回はシステムの性能情報をまとめて取得するスクリプトをご紹介したいと思います。私が普段ベンチマークテストを行う時に使用しているスクリプトです。
システムの性能を解析する際は、解析対象のシステムの負荷が高い時に現場で解析を行う事が鉄則です。稼働中のシステムに接続して、コマンドの結果を見ながら問題範囲を狭めて行くと、効率の良い解析が出来るからです。しかし現実的には、常にシステムの負荷が高い時に解析を行える訳ではありません。何らかの事情で現場に行く事が出来ず、他の人に統計情報の取得を依頼して、後からログを解析する様な事は良くあります。また、誰かに性能解析を依頼する場合も、あらかじめ必要なログを取得しておき現場から離れた場所で解析して貰う事があります。
現場で解析が出来無い場合は、入手する必要のある情報を解析の前に考えておかなければなりません。まだ状況が不明な状態でどのログを取るべきかを決定するのは困難ですので、通常は網羅的に統計情報を取得しておく事になるでしょう。広範囲に情報を取得しておけば、解析する段になって情報が不足する事を防げるからです。従来であれば、そのような時に使用するツールは sar(1) であったり、rpc.rstatd(1M) を使用した統合監視ユーティリティがありました。ここでの問題は sar(1) や rpc.rstatd(1M) は必ずしも必要なデータを取得出来ない事、そして不足している情報があってもカスタマイズ出来ない事です。
この様な時に自分で修正可能なスクリプトを持っていると便利です。「ちょっと現場に立ち会えないんだけど、このスクリプトを実行してログを送ってもらえる?」と言っておき、時間がある時にゆっくり解析を進める事も可能です。急な出張が入ってしまったり、ちょっと体調を崩して出社出来なかったり、同時に複数のサイトを調査する必要が出ても、これがあれば多少は安心です。厳しいセキュリティによりログを持ち出せない場合でも常にマシンに張り付いている必要は無くなります。
前置きが長くなりましたが、後で解析出来る様に統計情報をまとめて取得しておく為のスクリプトのご紹介です。
使い方
基本的な使い方
この記事の一番下にあるスクリプトを stat.sh という名前で保存し、実行権限を付け、実行します。
# mkdir /var/tmp/stat # cd /var/tmp/stat # vi stat.sh # chmod +x ./stat.sh # ./stat.sh Ctrl-C to stop this.
Ctrl-C を押すと実行が終了します。何も押さなければ延々と統計情報を取得し続けます。
結果の見方
スクリプトを実行したディレクトリに log ディレクトリが作成され、そこに統計情報のログが保存されています。
# ls log 0619-172209.about.txt 0619-172209.netstat-tcp.log 0619-172209.cfgadm-alv.log 0619-172209.netstat.log 0619-172209.defaultrouter 0619-172209.nodename 0619-172209.dladm-bge0.log 0619-172209.nsswitch.conf 0619-172209.dladm.log 0619-172209.prstat.log 0619-172209.format.log 0619-172209.prtdiag-v.log 0619-172209.hosts 0619-172209.ps-ef.log 0619-172209.ifconfig-a.log 0619-172209.psrinfo.log 0619-172209.iostat.log 0619-172209.psrset.log 0619-172209.kmastat.log 0619-172209.release 0619-172209.messages 0619-172209.system 0619-172209.mount.log 0619-172209.uname-a.log 0619-172209.mpstat.log 0619-172209.vfstab 0619-172209.ndd-ip.log 0619-172209.vmstat-p.log 0619-172209.ndd-tcp.log 0619-172209.vmstat.log 0619-172209.netstat-nr.log
ファイル名の先頭の 0619-172209 は日付と時間です。6/19 の 17:22:09 にスクリプトを実行しました。
各ファイルには最長 1 時間分のログが保存されます。スクリプトの実行が 1 時間を越えると、自動的に新しいファイルが作成され、ログは新しいファイルに保存されます。
取得される情報はファイル名の通りです。XXXX-XXXXXX.vmstat-p.log には "vmstat -p 1" を実行した結果が保存され、XXXX-XXXXXX.cfgadm-alv.log には "cfgadm -alv" を実行した結果が保存されています。vmstat, mpstat, iostat 等、基本的な統計情報から解析を始めて下さい。
結果を保存する
log ディレクトリを gtar と bzip2 で固めるだけです。この状態で性能解析を担当する人に渡してあげれば便利です。
# gtar jcf ./log.tar.bz2 ./log
その他
stat.sh の引数にコメントを指定する事が出来ます
# ./stat.sh "MySQL 5.4 Benchmark" Ctrl-C to stop this. ^C # cat ./log/*.about.txt MySQL 5.4 Benchmark
取得したい統計情報があれば、必要に応じてスクリプトを改変して下さい。
おわりに
Solaris の統計情報を網羅的に取得するスクリプトをご紹介しました。Solaris を管理する上で、こういうダーティーなスクリプトが役に立つ局面もあるのではないかと思います。是非、色々と改造して使って下さい。
もし GUI で統計情報を見たい場合は Dim STAT や JKstat もご覧下さい。
スクリプト
#!/bin/sh
IVAL=1
DURATION=3600
DIR=./log
SH_PID=$$
PID=${SH_PID}
COMMENT=$@
if [ ! -d ${DIR} ]
then mkdir ${DIR}
fi
LANG=C; export LANG
LC_ALL=C; export LC_ALL
echo "Ctrl-C to stop this."
while :
do DATE=`date '+%m%d-%H%M%S'`
echo ${COMMENT} > ${DIR}/${DATE}.about.txt
# system configurations
cp /etc/nodename ${DIR}/${DATE}.nodename &
uname -a > ${DIR}/${DATE}.uname-a.log &
cp /etc/release ${DIR}/${DATE}.release &
cp /etc/system ${DIR}/${DATE}.system &
cp /var/adm/messages ${DIR}/${DATE}.messages &
prtdiag -v > ${DIR}/${DATE}.prtdiag-v.log &
cfgadm -alv > ${DIR}/${DATE}.cfgadm-alv.log &
psrinfo > ${DIR}/${DATE}.psrinfo.log
psrset > ${DIR}/${DATE}.psrset.log &
# network configurations
ifconfig -a > ${DIR}/${DATE}.ifconfig-a.log &
dladm show-link > ${DIR}/${DATE}.dladm.log
dladm show-dev > ${DIR}/${DATE}.dladm.log &
cp /etc/defaultrouter ${DIR}/${DATE}.defaultrouter &
cp /etc/nsswitch.conf ${DIR}/${DATE}.nsswitch.conf &
cp /etc/hosts ${DIR}/${DATE}.hosts &
netstat -nr > ${DIR}/${DATE}.netstat-nr.log &
netstat -a > ${DIR}/${DATE}.netstat.log &
# disk configuration
echo | format > ${DIR}/${DATE}.format.log &
cp /etc/vfstab ${DIR}/${DATE}.vfstab &
mount > ${DIR}/${DATE}.mount.log &
#luxadm probe > ${DIR}/${DATE}.luxadm-probe.log &
#luxadm -e port > ${DIR}/${DATE}.luxadm-port.log &
# kernel memory usage
echo ::kmastat | mdb -k > ${DIR}/${DATE}.kmastat.log &
# ndd
echo "tcp_time_wait_interval" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_time_wait_interval >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_conn_req_max_q" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_conn_req_max_q >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_conn_req_max_q0" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_conn_req_max_q0 >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_keepalive_interval" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_keepalive_interval >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_naglim_def" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_naglim_def >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_smallest_anon_port" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_smallest_anon_port >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_max_buf" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_max_buf >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_conn_hash" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_conn_hash >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_bind_hash" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_bind_hash >> ${DIR}/${DATE}.ndd-tcp.log
echo "tcp_listen_hash" >> ${DIR}/${DATE}.ndd-tcp.log
ndd -get /dev/tcp tcp_listen_hash >> ${DIR}/${DATE}.ndd-tcp.log
echo "ip_conn_status" >> ${DIR}/${DATE}.ndd-ip.log
ndd -get /dev/ip ip_conn_status >> ${DIR}/${DATE}.ndd-ip.log
echo "ip_squeue_fanout" >> ${DIR}/${DATE}.ndd-ip.log
ndd -get /dev/ip ip_squeue_fanout >> ${DIR}/${DATE}.ndd-ip.log
echo "ip_soft_rings_cnt" >> ${DIR}/${DATE}.ndd-ip.log
ndd -get /dev/ip ip_soft_rings_cnt >> ${DIR}/${DATE}.ndd-ip.log &
# process list
ps -ef > ${DIR}/${DATE}.ps-ef.log
# trapstat
# trapstat -t 1 3 > ${DIR}/${DATE}.trapstat.log &
# prstat
prstat -n 50 1 60 > ${DIR}/${DATE}.prstat.log &
# vmstat
vmstat ${IVAL} ${DURATION} > ${DIR}/${DATE}.vmstat.log &
PID="$! ${PID}"
# vmstat -p
vmstat -p ${IVAL} ${DURATION} > ${DIR}/${DATE}.vmstat-p.log &
PID="$! ${PID}"
# iostat
iostat -xnCMmp ${IVAL} ${DURATION} > ${DIR}/${DATE}.iostat.log &
PID="$! ${PID}"
# mpstat
mpstat ${IVAL} ${DURATION} > ${DIR}/${DATE}.mpstat.log &
PID="$! ${PID}"
# netstat
netstat -sP tcp ${IVAL} ${DURATION} > ${DIR}/${DATE}.netstat-tcp.log &
PID="$! ${PID}"
# network performance counter
NIC=`dladm show-dev -p | grep 'link=up' | awk '{printf "%s ", $1}'`
for i in ${NIC}
do dladm show-dev -s -i 1 ${i} > ${DIR}/${DATE}.dladm-${i}.log &
DL_PID="$! ${DL_PID}"
done
trap "kill -9 ${DL_PID} ${PID}
echo 'script done' " 2
sleep ${DURATION}
kill -9 ${DL_PID}
PID=${SH_PID}
DL_PID=""
done
Posted at 02:31午後 6 24, 2009 by Daisuke Homma in Sun | 投稿されたコメント[0]
SS7000 Update 情報
今回は、昨年の11月に発表した Sun Storage 7000 シリーズに関して、 リリースされてから現在までのメジャーなアップデートを紹介します。
1. Sun Storage 7310 のリリース
5 月末に、新しいラインナップである Sun Storage 7310が発表されました。
SS7310 が発表される前は、クラスタ構成を組む場合、最上位機種 の SS7410 以外選択肢がありませんでしたが、SS7310 がラインナップに追加された事により価格を抑えたクラスタ 構成を組む事が可能になりました。( Read Cache 用 SSD も 600GB までサポートです。)
SS7410 と SS7310 の主な違いは、コントローラ部分に使用しているサーバが SS7410 は 2U なのに対して、SS7310 は 1U になります。

Sun Storage 7310 最大構成
2. SS7110 の容量アップ
SS7110 が発表された当初は、使用する SAS Disk が 146GB のみのサポートであった為、 最大容量が 2TB でしたが、4月末に 300GB SAS Disk がサポートされた事により、SS7110 の 最大容量が、4.2 TB になりました。これからも 400GB など大容量の構成が期待できます。
3. SS7210 に J4500 の拡張性
SS7210 は、高さ 4U で SATA Disk 48 本内蔵できる高密度のストレージサーバです。発表当時は最大で 48 TB までの 拡張性でしたが、5 月末のアップデートで J4500 JBOD ストレージの増設が可能になりました。
これで、48TB で足りない場合、さらに J4500 を 2 台増設できますので、最大で 142TB まで増設 可能になりました。
最後に、
SS7000 シリーズは、価格性能比に優れているだけでなく、使いやすい GUI が好評のプロダクトです。この GUI を 体感できるシミュレータが以前から公開されておりますが、このシミュレータも進化しており、VMware 版だけでなく VirtualBOX 版も 公開されております。是非お試し下さい!
[シミュレータ URL] http://www.sun.com/storage/disk_systems/unified_storage/resources.jsp
(参考情報)
過去の 「やっぱり Sun がスキ!」blog 記事一覧はこちらを参照下さい。 http://wikis.sun.com/display/yappri/Home
Posted at 11:14午前 6 23, 2009 by Naoyuki Yamada in Sun | 投稿されたコメント[0]
Solaris Crash Analysis Tool 5.1
システムの panic 等で採取される crash dump (/var/crash 配下に格納される)ですが、この中身を覗いてみたくなったこととかありませんか?
今回、ご紹介する Solaris Crash Analysys Tool (以下 SolarisCAT)は、採取された crash dump を解析するためのツールとなり、Solaris 2.6 から Solaris 10 および OpenSolaris をサポートしています。また、採取済みの crash dump 以外にも、稼働中のシステムの情報を採取することも可能です。
(CPU アーキテクチャが異なる環境では、crash dump の解析ができませんのでご注意ください。たとえば、SPARC 上で採取されたものを x86 環境で解析することはできず、その逆も同様となります。)
Solaris CAT は、下記 URL から入手可能です。
Solaris Crash Analysis Tool 5.1
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=SCAT-5.1-G-F@CDS-CDS_SMI
パッケージ形式での配布となりますので、download 後に pkgadd コマンドでシステムにインストールすることになります。コマンド群は、/opt/SUNWscat に配置され、マニュアルは HTML ファイル (/opt/SUNWscat/docs) にて提供されます。基本的なインターフェースは、CUI (/opt/SUNWscat/bin/scat コマンド)となり対話形式にて操作することが可能です。
引数を与えずに scat を起動すると下記のメッセージが表示されます。
--
# /opt/SUNWscat/bin/scat
Solaris[TM] CAT 5.1b for Solaris 11 64-bit x64
SV4842, Feb 24 2009
Copyright 2009 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
Feedback regarding the tool should be sent to SolarisCAT_Feedback@Sun.COM
Visit the Solaris CAT blog at http://blogs.sun.com/SolarisCAT
opening /dev/ksyms /dev/kmem ...symtab...core...done
loading core data: modules...symbols...CTF...done
files: /dev/ksyms /dev/kmem
user: Super-User (root:0)
release: 5.11 (64-bit)
version: snv_114
machine: i86pc
node name: macbook
system type: i86pc
hostid: 4fd7cf4c
dump_conflags: 0x10000 (DUMP_KERNEL) on /dev/zvol/dsk/rpool/dump(1G)
time in kernel: Thu May 28 11:35:29 JST 2009
age of system: 3 hours 28 minutes 53.88 seconds
CPUs: 2 (3.72G memory)
sanity checks: settings...vmem...sysent...misc...done
SolarisCAT(live/11X)>
--
試しに、採取された crash dump を覗いてみるには、下記のように実行します。analyze コマンドは、crash dump を自動的に解析し、原因究明への一歩を手助けしてくれる情報を出力してくれます。
-- # /opt/SUNWscat/bin/scat /var/crash/$HOSTNAME/vmcore.0 SolarisCAT(vmcore.0/11X)> analyze core file: /var/crash/macbook/vmcore.0 user: Super-User (root:0) release: 5.11 (64-bit) version: Apr_30_11:53_2009 machine: i86pc node name: macbook system type: i86pc hostid: 4fd7cf4c dump_conflags: 0x10000 (DUMP_KERNEL) on /dev/zvol/dsk/rpool/dump(1G) time of crash: Thu Apr 30 19:48:38 JST 2009 (core is 27 days old) age of system: 4 minutes 25.10 seconds panic CPU: 1 (2 CPUs, 3.72G memory) panic string: BAD TRAP: type=e (#pf Page fault) rp=ffffff0008da6a30 addr=20 occurred in module "unix" due to a NULL pointer dereference ==== checking for trap information ==== CPU 1 had the panic ==== panic thread: 0xffffff01be4aa000 ==== CPU: 1 ==== ==== panic kernel thread: 0xffffff01be4aa000 PID: 0 on CPU: 1 ==== cmd: t_procp: 0xffffff01cffe7e10 p_as: 0x0t_stk: 0xffffff0008da6f10 sp: 0xffffff0008da6790 t_stkbase: 0x0 t_pri: 60(FX) pctcpu: 0.000000 t_lwp: 0x0 address translation failed for cpupart: 320 bytes @ 0xfed00000 bound psrset: -70932464 last CPU: 1 idle: 1092044344150 ticks (126394 days 30 minutes 41.50 seconds) start: Wed Jul 19 11:24:56 .*.* age: 1092968065422 seconds (12650093 days 8 hours 23 minutes 42 seconds) tstate: TS_ONPROC - thread is being run on a processor tflg: T_PANIC - thread initiated a system panic T_DFLTSTK - stack is default size tpflg: TP_TWAIT - wait to be freed by lwp_wait TP_MSACCT - collect micro-state accounting information tsched: TS_LOAD - thread is in memory TS_DONT_SWAP - thread/LWP should not be swapped TS_SIGNALLED - thread was awakened by cv_signal() pflag: none set pc: unix:vpanic_common+0x13b: addq $0xf0,%rsp unix:vpanic_common+0x13b() unix:panic+0x94() unix:die+0xdd() unix:trap+0x175f() unix:cmntrap_pushed+0x3d() unix:mutex_enter+0xb() klmmod:lm_svc+0x45() nfs:nfssys+0x448() unix:_sys_sysenter_post_swapgs+0x14b() -- end of kernel thread's stack -- ==== analyzing panic thread stack for trap frames ==== no trap frames found --
また、稼働中のシステムの様々な情報も取得することが可能です。
例として、メモリ情報やページ情報を確認するには、下記のように実行します。
[メモリ情報の確認]
--
SolarisCAT(live/11X)> meminfo
pages bytes
physinstalled 976919 4001460224 (3.72G)
physmem 974870 3993067520 (3.71G)
total_pages 974869 3993063424 (3.71G)
freemem 375851 1539485696 (1.43G)
avefree 381934 1564401664 (1.45G)
avefree30 374878 1535500288 (1.43G)
availrmem (nonswapable) 683612 2800074752 (2.60G)
availrmem_initial 974869 3993063424 (3.71G)
swapfs_minfree 121858 499130368 (476M)
sw_pending_size 40960 (40K)
lotsfree 15232 62390272 (59.5M)
desfree 7616 31195136 (29.7M)
minfree 3808 15597568 (14.8M)
throttlefree 3808 15597568 (14.8M)
lookup failed for symbol segvn_pages_locked: symbol not found
pp_kernel(calculated) 290845 1191301120 (1.10G)
obp_pages 512 2097152 (2M)
kcage_on: 0
shared memory (SM) 540672 (528K)
intimate SM (ISM) 0 (0)
dynamic ISM (DISM) 0 (0)
locked DISM 0 0 (0)
total locked SM 0 (0) (0.00% of memory)
spt_used (ISM) 0 0 (0)
segspt_minfree 0 0 (0)
anoninfo: (physical == disk-backed)
ani_max - total reservable physical swap 488447 pages (1.86G)
ani_free - unallocated physical and memory 220853 pages (862M)
ani_phys_resv - reserved physical 341070 pages (1.30G)
ani_mem_resv - reserved memory 0 pages (0)
ani_locked_swap - swap locked in reserved mem swap 0 pages (0)
initial virtual swap available for reservation 1341458 pages (5.11G)
ani_max + MAX((availrmem_initial - swapfs_minfree), 0)
current virtual swap available for reservation 709131 pages (2.70G)
(ani_max - ani_phys_resv) + MAX((availrmem - swapfs_minfree), 0)
swap device pages free
/dev/zvol/dsk/rpool/swap 488447 (1.86G) 488447 (1.86G)
tmpfs:
tmount size mount point
0xffffff01bc091140 456K /etc/svc/volatile
0xffffff01be771918 6.10M /tmp
0xffffff01be80a108 52K /var/run
--
[ページ情報の確認]
--
# /opt/SUNWscat/bin/scat
SolarisCAT(live/11X)> page summary
reading page table...
reading page_freelists...
reading page_cachelists...
reading page_hash...
total: 974869 (3.71G)
mapped: 545810 (2.08G)
unmapped: 429059 (1.63G)
modified: 238948 (933M)
read-only: 0 (0)
locked in memory: 273714 (1.04G)
soft locked: 0 (0)
shared-locked: 291166 (1.11G)
excl-locked: 63 (252K)
IO_INUSE: 1 (4K)
FREE pages: 380541 (1.45G)
AGED pages: 230701 (901M)
NORELOC pages: 0 (0)
kernel(kvp): 171113 (668M)
anon: 242316 (946M)
exec: 9163 (35.7M)
page cache: 168381 (657M)
page cache(mod): 1687 (6.58M)
free (cachelist): 149840 (585M)
NULL vnode !free: 3355 (13.1M) (ramdisk?)
free (freelist): 230701 (901M)
freelist: 227066 pages
pages pagesize
=============== ========
227059 (886M) 4K
7 (14M) 2M
total size: 944713728 (900M)
constituent: 3577 pages
cachelist: 149429 (583M)
hashed: 740874 (2.82G)
pages pagesize
=============== ========
719370 (2.74G) 4K
21504 (84M) 2M
pages modified mapped vnode
=============== =============== =============== =====
234056 (914M) 0 1 (4K) 0
171113 (668M) 0 141084 (551M) unix(data):kvp+0x0
114705 (448M) 0 114705 (448M) unix(data):zvp+0x0
24522 (95.7M) 0 510 (1.99M) 0xffffff01cd37f100
8688 (33.9M) 0 158 (632K) 0xffffff01cf1ca580
7914 (30.9M) 0 3791 (14.8M) 0xffffff01d0d33600
6160 (24M) 0 5214 (20.3M) 0xffffff01ccebe080
...
pages modified mapped vnode ops
=============== =============== =============== =========
285819 (1.09G) 0 255789 (999M) 0
265316 (1.01G) 237261 (926M) 241334 (942M) *genunix(bss):swap_vnodeops
152844 (597M) 0 46491 (181M) *zfs(bss):zfs_fvnodeops
22657 (88.5M) 0 2168 (8.46M) 0xffffff01bb20b380
12487 (48.7M) 0 0 *nfs(bss):nfs4_vnodeops
1687 (6.58M) 1687 (6.58M) 27 (108K) *tmpfs(bss):tmp_vnodeops
3 (12K) 0 0 *specfs(bss):spec_vnodeops
--
Posted at 03:00午後 5 28, 2009 by masahiko in Sun | 投稿されたコメント[0]
ramdiskadm コマンドの紹介
今回は、カーネルのメモリ空間を RAM ディスクとして扱うことができる ramdiskadm コマンドを紹介します。
このコマンドで作成した RAM ディスクは、通常の高速なブロック型デバイス として扱えるので、ファイルシステムの作成や個別にマウントする事が可能です。
では、早速 RAM ディスクを作成してみましょう。
今回は、fastdisk という名前で 100 MB の RAM ディスクを作成します。
# ramdiskadm -a fastdisk 100m /dev/ramdisk/fastdisk
これで 100MB の RAM ディスクが作成できました。
作成したディスクの状況は、引数なしの ramdiskadm コマンドで確認できます。
# ramdiskadm ブロック型デバイス サイズ 削除可能 /dev/ramdisk/fastdisk 104857600 はい
次に作成した RAMディスクに対してファイルシステムを作成します。
# newfs /dev/ramdisk/fastdisk
/dev/ramdisk/fastdisk: メディアタイプが見つかりません。システムによって決め
られたパラメータで処理を続行しています。
newfs: 新しいファイルシステム /dev/rramdisk/fastdisk を作成しますか: (y/n)? y
/dev/rramdisk/fastdisk: 全セクター数: 204600 (シリンダ数: 341、トラック数: 1、 セクター数: 600)
99.9MB、22 シリンダグループ (16 c/g, 4.69MB/g, 2240 i/g)
スーパーブロックのバックアップの位置 (fsck -F ufs -o b=# のため) :
32, 9632, 19232, 28832, 38432, 48032, 57632, 67232, 76832, 86432,
115232, 124832, 134432, 144032, 153632, 163232, 172832, 182432, 192032, 201632
ファイルシステムの作成が完了したので早速マウントしてみましょう。
# mount /dev/ramdisk/fastdisk /mnt
# df -h /mnt
ファイルシステム サイズ 使用済み 使用可能 容量 マウント先
/dev/ramdisk/fastdisk
94M 1.0M 83M 2% /mnt
これで作成した RAM ディスクが通常のファイルシステム領域として利用可能に なりました。高速アクセスが求められる一時的な作業領域としてお使い下さい。
RAM ディスクを使用する注意点として、作成した RAM ディスクは、OS を再起動 すると設定情報が消えてしまいます。従いまして、RAM ディスク運用時は、OS 起動 時やアプリ起動時のスクリプトに RAM ディスクを作成する設定を入 れるなど考慮下さい。
(参考情報)
過去の 「やっぱり Sun がスキ!」blog 記事一覧はこちらを参照下さい。 http://wikis.sun.com/display/yappri/Home
Posted at 05:24午後 5 26, 2009 by Naoyuki Yamada in Sun | 投稿されたコメント[1]
iostat コマンドの読み方
はじめに
今回は iostat コマンドをご紹介したいと思います。iostat は I/O の統計情報を出力するコマンドです。物理ディスクやテープドライブ、ネットワーク越しにマウントしたファイルシステム、端末入出力等の入出力性能を監視する事が出来ます。I/O を監視するツールは他にも fsstat, nfsstat, zpool iostat, DTrace io Probider, kstat -p 'unix:0:biostats' 等がありますが、その中でも iostat は最も基本的で重要なコマンドです。是非ご活用下さい。
iostat のお勧めのオプション
-xnC 1
基本的なオプションとして -x, -n, -C オプションは常時付ける事をお勧めします。
% iostat -xnC 1
x オプションは拡張表示を有効にするオプションです。iostat のデフォルトでは iostat が抜き出した幾つかのデバイスに付いて kps, tps, serv の 3 つの統計を表示するだけです。-x を付けると全てのデバイスが出力対象となり、出力される統計情報も増加します。I/O の解析を行う際は必須のオプションです。
n オプションはデバイス名を分かりやすく表示するオプションです。デフォルトではデバイス名は "ssd223" の様にドライバー名とインスタンス番号で表示されますが、-n オプションを付けると "c0t0d0" の様にディスクを特定しやすい名前で出力されます。これも必須のオプションと言って良いでしょう。常に付ける様にして下さい。
C オプションはコントローラ毎の統計情報も表示するオプションです。複数の HBA を使用しているシステムでは、コントローラをまたいで I/O 負荷を分散した方がスループットが上がります。個別のディスクの統計情報だけでなく、途中の経路における統計情報も取得する事で、より詳細な分析が可能になります。
1 はインターバルです。1 秒ごとに統計情報を表示します。iostat 実行の負荷は小さく、ログのサイズも今時のハードディスクのサイズを考えれば非常に小さいので、長期間の負荷を監視する場合でもより精度の高い情報を取得する為に 1 秒毎に出力する事をお勧めします。
その他のオプション
場合によっては -M や -z, -p, -m オプションを付けると便利です。
M オプションは "kr/s", "kw/s" を MB 表示に直します。内蔵ディスクでも数百 MB/s のスループットが出る時代ですし、FC の帯域はギガの単位ですので -M を付けた方が見易い場合も多くあります。ただし、細かい I/O が少量発生しているのを監視したい場合はデフォルトの KB 単位の方が良いかもしれません。
z オプションは出力結果の全ての性能値が 0 であった場合に表示を省略するオプションです。ディスクが沢山あって出力が画面をはみ出してしまう場合に便利です。毎回出力される行数が変わるのでログを取得する用途には向いていません。
p オプションはパーティション毎の統計情報も表示します。cXtXdXsX の sX 単位で出力されますので、どのスライスに I/O が発生しているかを見たい場合に使用して下さい。
m オプションは -n, -p と一緒に使用するとマウントポイントも表示します。どのデバイスに I/O が発生しているかが更に分かりやすくなります。
iostat の出力例
例1
# iostat -xnC 1
...
extended device statistics
r/s w/s kr/s kw/s wait actv wsvc_t asvc_t %w %b device
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c0t6d0
0.0 14.1 0.3 148.8 0.0 0.1 0.9 5.9 0 3 c1
0.0 3.3 0.0 36.4 0.0 0.0 0.6 3.9 0 1 c1t1d0
0.0 3.3 0.0 36.6 0.0 0.0 0.6 4.1 0 1 c1t4d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t13d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t8d0
0.0 3.3 0.0 36.6 0.0 0.0 0.6 4.2 0 1 c1t3d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 0 0 c1t5d0
0.0 0.8 0.3 2.8 0.0 0.0 5.7 34.0 0 0 c1t0d0
0.0 3.3 0.0 36.4 0.0 0.0 0.6 4.2 0 1 c1t2d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 mikawa01.jp.iforce.net:vold(pid576)
例2
# iostat -xnCmp 1
...
extended device statistics
r/s w/s kr/s kw/s wait actv wsvc_t asvc_t %w %b device
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c0t6d0
0.0 14.1 0.3 148.8 0.0 0.1 0.9 5.9 0 3 c1
0.0 3.3 0.0 36.4 0.0 0.0 0.6 3.9 0 1 c1t1d0
0.0 3.3 0.0 36.4 0.0 0.0 0.6 3.9 0 1 c1t1d0s0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t1d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t1d0s3
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0 0 c1t1d0s4
0.0 3.3 0.0 36.6 0.0 0.0 0.6 4.1 0 1 c1t4d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t4d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7 0 0 c1t4d0s3
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t4d0s4
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t13d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t13d0s0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t13d0s1
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t13d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t8d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t8d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t8d0s3
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 c1t8d0s4
0.0 3.3 0.0 36.6 0.0 0.0 0.6 4.2 0 1 c1t3d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.6 0 0 c1t3d0s1
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t3d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.3 0 0 c1t3d0s5
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 0 0 c1t5d0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7 0 0 c1t5d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.7 0 0 c1t5d0s3
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t5d0s4
0.0 0.8 0.3 2.8 0.0 0.0 5.7 34.0 0 0 c1t0d0
0.0 0.8 0.3 2.8 0.0 0.0 5.7 34.0 0 0 c1t0d0s0 (/)
0.0 0.0 0.0 0.0 0.0 0.0 0.0 19.2 0 0 c1t0d0s1
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t0d0s2
0.0 3.3 0.0 36.4 0.0 0.0 0.6 4.2 0 1 c1t2d0
0.0 3.3 0.0 36.4 0.0 0.0 0.6 4.2 0 1 c1t2d0s0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.8 0 0 c1t2d0s2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.2 0 0 c1t2d0s6
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 mikawa01.jp.iforce.net:vold(pid576)
各カラムの意味
r/s(りーどぱーせかんど)
r/s は毎秒何回読み出しを行っているかを表しています。r/s と w/s を足し合わせた値が IOPS になります。なお、iostat の間隔を何秒に設定しても 1 秒辺りの数値で出力されます。
r/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::reads' 等で iostat の r/s と近い出力を得る事が可能です。iostat コマンドの中ではデバイスパスを比較してデバイスを選り分けている様です。
該当する kstat の値は主に以下の場所で更新されています。
- /usr/src/uts/sun/io/scsi/adapters/esp.c --> IOSP(last_slot)->reads++;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP->reads++;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP_PARTITION->reads++;
- /usr/src/uts/sun/io/fd.c --> KIOSP->reads++;
- /usr/src/uts/common/io/fd.c --> KIOSP->reads++;
- /usr/src/uts/common/io/scsi/targets/st.c --> IOSP->reads++;
- /usr/src/uts/common/io/lvm/md/md_subr.c --> KSTAT_IO_PTR(ui->ui_kstat)->reads++;
- /usr/src/uts/common/os/sunmdi.c --> KSTAT_IO_PTR(iostatp)->reads++;
- /usr/src/uts/common/sys/scsi/targets/sddef.h --> kip->reads++;
- /usr/src/uts/intel/io/dktp/drvobj/strategy.c --> KSTAT_IO_PTR(dsnglp->ds_kstat)->reads++;
- /usr/src/uts/common/io/ramdisk.c --> kioptr->reads++;
- /usr/src/uts/common/io/lofi.c --> kioptr->reads++;
w/s(らいとぱーせかんど)
w/s は毎秒何回書き込みを行っているかを表しています。細かい I/O が発生して書き込み回数が増えると、帯域が余っていてもディスクコントローラがボトルネックになる事があります。
w/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::writes' 等で iostat の w/s と近い出力を得る事が可能です。
該当する kstat の値は主に以下の場所で更新されています。
- /usr/src/uts/sun/io/scsi/adapters/esp.c --> IOSP(last_slot)->writes++;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP->writes++;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP_PARTITION->writes++;
- /usr/src/uts/sun/io/fd.c --> KIOSP->writes++;
- /usr/src/uts/common/io/fd.c --> KIOSP->writes++;
- /usr/src/uts/common/io/scsi/targets/st.c --> IOSP->writes++;
- /usr/src/uts/common/io/lvm/md/md_subr.c --> KSTAT_IO_PTR(ui->ui_kstat)->writes++;
- /usr/src/uts/common/os/sunmdi.c --> KSTAT_IO_PTR(iostatp)->writes++;
- /usr/src/uts/common/sys/scsi/targets/sddef.h --> kip->writes++;
- /usr/src/uts/intel/io/dktp/drvobj/strategy.c --> KSTAT_IO_PTR(dsnglp->ds_kstat)->writes++;
- /usr/src/uts/common/io/ramdisk.c --> kioptr->writes++;
- /usr/src/uts/common/io/lofi.c --> kioptr->writes++;
kr/s(きろりーどぱーせかんど)
kr/s は毎秒何 KB 読み出しを行っているかを表しています。r/s と w/s が IOPS を表していたのに対し、こちらは I/O のスループットを表しています。
kr/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::nread' 等で iostat の kr/s と近い出力を得る事が可能です。
該当する kstat の値は主に以下の場所で更新されています。
- /usr/src/uts/sun/io/scsi/adapters/esp.c --> IOSP(last_slot)->nread += sp->cmd_data_count;
- /src/uts/sun/io/dada/targets/dad.c --> IOSP->nread += n_done;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP_PARTITION->nread += n_done;
- /usr/src/uts/sun/io/fd.c --> KIOSP->nread += (bp->b_bcount - bp->b_resid);
- /usr/src/uts/common/io/fd.c --> KIOSP->nread += (bp->b_bcount - bp->b_resid);
- /usr/src/uts/common/io/scsi/targets/st.c --> IOSP->nread += n_done;
- /usr/src/uts/common/io/lvm/md/md_subr.c --> KSTAT_IO_PTR(ui->ui_kstat)->nread += n_done;
- /usr/src/uts/common/sys/scsi/targets/sddef.h --> kip->nread += n_done;
- /usr/src/uts/common/os/sunmdi.c --> KSTAT_IO_PTR(iostatp)->nread += xfer_cnt;
- /usr/src/uts/intel/io/dktp/drvobj/strategy.c --> KSTAT_IO_PTR(dsnglp->ds_kstat)->nread += (in_bp->b_bcount - in_bp->b_resid);
- /usr/src/uts/common/io/ramdisk.c --> kioptr->nread += nbytes;
- /usr/src/uts/common/io/lofi.c --> kioptr->nread += n_done;
kw/s(きろらいとばーせかんど)
kw/s は毎秒何 KB 書き込みを行っているかを表しています。
kw/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::nwritten' 等で iostat の kw/s と近い出力を得る事が可能です。
該当する kstat の値は主に以下の場所で更新されています。
- /usr/src/uts/sun/io/scsi/adapters/esp.c --> IOSP(last_slot)->nwritten += sp->cmd_data_count;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP->nwritten += n_done;
- /usr/src/uts/sun/io/dada/targets/dad.c --> IOSP_PARTITION->nwritten += n_done;
- /usr/src/uts/sun/io/fd.c --> KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
- /usr/src/uts/common/io/fd.c --> KIOSP->nwritten += (bp->b_bcount - bp->b_resid);
- /usr/src/uts/common/io/scsi/targets/st.c --> IOSP->nwritten += n_done;
- /usr/src/uts/common/io/lvm/md/md_subr.c --> KSTAT_IO_PTR(ui->ui_kstat)->nwritten += n_done;
- /usr/src/uts/common/sys/scsi/targets/sddef.h --> kip->nwritten += n_done;
- /usr/src/uts/common/os/sunmdi.c --> KSTAT_IO_PTR(iostatp)->nwritten += xfer_cnt;
- /usr/src/uts/intel/io/dktp/drvobj/strategy.c --> KSTAT_IO_PTR(dsnglp->ds_kstat)->nwritten += (in_bp->b_bcount - in_bp->b_resid);
- /usr/src/uts/common/io/ramdisk.c --> kioptr->nwritten += nbytes;
- /usr/src/uts/common/io/lofi.c --> kioptr->nwritten += n_done;
wait(うぇいと)
wait は I/O 要求が受け付けられたものの、実行まで待たされている I/O の数を表しています。実行待ちしている I/O 要求の数は kstat wait queue という名前で管理されています。
wait の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::wlentime' 等で iostat の wait と近い出力を得る事が可能です。
該当する kstat の値はカーネル内の kstat_waitq_enter(), kstat_waitq_exit(), kstat_waitq_to_runq() ,kstat_runq_back_to_waitq() で更新されています。
- sun4u システムでは /usr/src/uts/sun4u/cpu/common_asm.s の stx %o5, [%o0 + QTYPE/**/LENTIME]; が更新ポイントです。KSTAT_Q_UPDATE() マクロの QTYPE 引数が KSTAT_IO_W だった時に KSTAT_IO_WLENTIME として評価されます。更に KSTAT_IO_WLENTIME は /usr/src/uts/sun4/ml/offsets.in 内の定義によって wlentime に変換されます(offsets.in は common_asm.s でインクルードされている assym.h の元ファイルです)。
- sun4v では /usr/src/uts/sun4v/cpu/common_asm.s の stx %o5, [%o0 + QTYPE/**/LENTIME]; で更新されています。
- x86 では /usr/src/uts/common/os/kstat_fr.c の kiop->wlentime += kiop->wcnt * wfix; と kiop->wlentime += delta * wcnt; で更新されています。
actv(あくてぃぶ)
actv は毎秒、デバイスによって処理されている I/O 要求の数を表しています。現在処理されている I/O の数は kstat run queue という名前で管理されています。
actv の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::rlentime' 等で iostat の actv と近い出力を得る事が可能です。
kstat の rlentime の値はカーネル内の kstat_runq_enter(), kstat_runq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。
- /usr/src/uts/sun4u/cpu/common_asm.s --> stx %o5, [%o0 + QTYPE/**/LENTIME];
- /usr/src/uts/sun4v/cpu/common_asm.s --> stx %o5, [%o0 + QTYPE/**/LENTIME];
- /usr/src/uts/common/os/kstat_fr.c --> kiop->rlentime += kiop->rcnt * rfix; と kiop->rlentime += delta * rcnt;
wsvc_t(うぇいとさーびすたいむ)
wsvc_t は I/O 要求が待機させられている時間の平均値をミリ秒単位で表しています。待機待ちの I/O 要求の個数(wait) を IOPS(r/s と w/s を足した値) で割った値です。
wsvc_t の値は ("wait" / ("r/s" + "w/s") * 1000) の計算式で求められます。
asvc_t(あくてぃぶさーびすたいむ)
asvc_t は I/O 要求の処理に掛かった時間の平均値をミリ秒単位で表しています。処理中の I/O 要求の個数(actv) を IOPS(r/s と w/s を足した値) で割った値です。
asvc_t の値は ("actv" / ("r/s" + "w/s") * 1000) の計算式で求められます。
%w(ぱーせんとうぇいと)
%w は待機させられている I/O 要求が存在している時間の割合です。/usr/src/uts/common/sys/kstat.h に図示されている様に、この値は I/O 要求の数と時間のリーマン和になっています。
%w の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::wtime' 等で iostat の %w と近い出力を得る事が可能です。
kstat の wrime の値はカーネル内の kstat_waitq_enter(), kstat_waitq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。
- /usr/src/uts/common/os/kstat_fr.c --> kiop->wtime += wfix; と kiop->wtime += delta;
- /usr/src/uts/sun4u/cpu/common_asm.s --> stx %o4, [%o0 + QTYPE/**/TIME];
- /usr/src/uts/sun4v/cpu/common_asm.s --> stx %o4, [%o0 + QTYPE/**/TIME];
%b(ぱーせんとびじー)
%b はディスクが busy 状態になっている時間の割合です。%w と同じ様にリーマン和になっています。
%b の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::rtime' 等で iostat の %r と近い出力を得る事が可能です。
kstat の rtime の値はカーネル内の kstat_runq_enter(), kstat_runq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。
- /usr/src/uts/common/os/kstat_fr.c --> kiop->rtime += rfix; と kiop->rtime += delta;
- /usr/src/uts/sun4u/cpu/common_asm.s --> stx %o4, [%o0 + QTYPE/**/TIME];
- /usr/src/uts/sun4v/cpu/common_asm.s --> stx %o4, [%o0 + QTYPE/**/TIME];
device(でばいす)
device はデバイス名です。
値の見方
iostat コマンドの初回の出力はデバイスがオンラインになってから現在までの累積値です。2 回目からの出力がリアルタイムの値ですので、注意して下さい。
まずは %w と %b がどれだけ出ているかを確認します。通常は %b が 100% に達してから %w が発生します。%w が出ている時は I/O リクエストを完全には捌けておらず、I/O ボトルネックになっている状態です。%w が出ておらず、%b も 100% までいっていない場合は I/O に余力がある状態です。この状態では I/O ボトルネックを心配する必要はありません。
基本的な情報として IOPS と I/O サイズ、I/O スループットの 3 つを把握して下さい。IOPS は毎秒幾つの I/O リクエストを捌けているかという情報です。IOPS は "r/s" + "w/s" で求める事が出来ます。IOPS が多い場合は I/O リクエストが多量に発生しており、負荷が高くなっている状態です。
I/O サイズは "kr/s" / "r/s" が平均読み出しサイズ、 "kw/s" / "w/s" が平均書き込みサイズです。平均 I/O サイズが小さい場合は細かい書き込みが発生しており、一般的に性能が出にくい状態です。ある特定のプロセスがどんなサイズの I/O リクエストを出しているかは DTrace や truss で確認する事が出来ます。以下の様に truss を実行すると、入出力先のデバイス、I/O のサイズ、読み書きされているデータの中身、I/O に掛かった時間等、詳細な情報を入手する事が出来ます。
% truss -E -vall -wall -rall -p
I/O スループットは "kr/s" と "kw/s" のカラムを見ます。"kr/s" が毎秒何 KB 読み出しているか、"kw/s" が何 KB 書き込んでいるかを示しています。スループットの値は I/O パターンやディスクのレイアウトにも依りますが、期待したスループットが達成されているか確認して下さい。
I/O の重要な調査ポイントとして、発行されている I/O の特性も見極める必要があります。read only なのか write intensive なのか read と write の混在なのか、sequential access か random access か、等の I/O 特性によって I/O の性能は変化します。これらの情報は RAID 構成を決定する際のヒントにもなります。"r/s" が増加していて "w/s" が 0 の場合は read only access で、逆の場合は write only access です。I/O 特性が read only でデータサイズがそれ程大きくない場合は tmpfs にデータを置くと性能が大きく改善します。sequential か random かを iostat で正確に切り分ける方法はありませんが、read / write が両方発生している場合や、I/O サイズが不規則に変化している場合は random access の可能性が高いです。
関連するソースファイル
iostat の出力は iostat.c の show_disk() 関数にまとめられています。kstat からのデータの取得は acquire_iodevs.c の中で行っています。
- /usr/src/cmd/stat/iostat/iostat.c
- /usr/src/cmd/stat/common/acquire_iodevs.c
- /usr/src/uts/common/sys/kstat.h
- /usr/src/uts/common/io/scsi/targets/sd.c
参考文献
- Solaris のシステム管理 (上級編) - ディスク使用状況の表示 (iostat n)
- Solaris UFS and Disk IO Performance for Large Synchronous Sequential Writes
- 古いですが、SCSI と IDE の多重アクセス時の性能の違いについて比較しています。
終わりに
以上、iostat の実装と読み方に付いて解説しました。IOPS、I/O サイズ、スループット、wait queue, run queue 等の情報を活用する事でサーバを健全な状態で運用する事が可能になります。vmstat や mpstat 等のツールとともに頻繁に使用するツールですので、是非使い方を憶えて有効活用して下さい。
Posted at 12:00午後 5 25, 2009 by Daisuke Homma in Sun | 投稿されたコメント[0]
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]
Atom + OpenSolaris で低消費電力ミニサーバを自作しよう♪ ~へっぽこ SE 奮闘記~
今話題のインテル Atom プロセッサーと OpenSolaris 2008.11 を組み合わせて
消費電力がとっても低い "エコな" ミニサーバを自作しましたのでご紹介。
一家に一台 常時稼働の My Solaris サーバがあると色々できて便利ですし
会社にいなくとも新しい OS の機能テストなどで活用できそうですよね!
でも、自宅でサーバを動かすとなると、気になるのは電気代というランニングコスト。
サーバ用途となると常時電源 ON にしておく事になるので、消費電力を抑えて
なるべくエコに行きたいですよね!
そんな中、着目したのはインテルの Atom プロセッサー搭載ベアボーンキット。
ネットブックに採用されるような消費電力や発熱が低いインテル Atom プロセッサー
であれば電気代を抑えることが出来ます。 最近ではデュアルコアモデルも登場して
いるので、サーバとしての処理能力不足の心配もありません。
また純な IA 系のプロセッサーなので、そのまま一般の Solaris が動作できる環境で
あるのも大きなメリットです。
ということで早速コレは作らねば!っと、ベアボーンキットと PC パーツを購入しました!(^o^)
パーツ構成内容は以下の通りです。
・Shuttle X27D (DualCore Atom 330 ベアボーンキット)
・DDR2 2GB DIMM x1枚 (240pin Type)
・DVD Drive (SlimType SATA)
・SSD 60GB (SATA)
# HDD ではなく SSD を採用したのはミニサーバの静音性とパフォーマンスを
# 高める目的と消費電力の低さを期待してのチョイスです。


購入してからハッと気がついたのですが・・・オンボードで搭載されたネットワークやビデオ
オーディオのチップが OpenSolaris で問題なく認識されて動作するかということ・・(^o^;;
X27D のマザーボードにオンボードで搭載されている各種チップは以下のものが
使われているのですが・・


・NIC: Realtek 8111C
・ビデオ: Intel 945GC (Intel GMA 950)
・サウンド: ICH7
事前にあまり考慮せずに購入してしまっていたのでドキドキしながら
OpenSolaris 2008.11 Live CD 起動での Device Driver Utillity でチェック!
無事に認識されてほっと一安心 (^o^) で早速インストール!
Atom 330 は物理デュアルコアと Hyper-Threading で Solaris OS からは
4 スレッドの CPU リソースとして認識されます。
( もちろん perfbar を表示させれば 4 本のバーが立ちます。)
これなら Solaris が得意なマルチスレッドプログラムの開発の
簡単な動作テスト環境としても、使えるかもしれませんね!
さてさて肝心のシステム全体での消費電力チェックですが、使用したのは
自前のワットチェッカー。 # "自前の"というのがポイントです(笑)
このワットチェッカーを電源ケーブルとコンセントの間にはさんで計測!


【通常時は 27W~34W で稼動】

【瞬間最大でも 38W 以下】
なんと起動時 32W 前後で通常稼働時 27〜34W と予想以上に低消費電力な結果が!
色々と負荷をかけてみた結果、CPUのみの高負荷であれば消費電力への影響は
さほどでもなく、DVD ドライブを動かして且つ高負荷時状態の一瞬に 38W の表示を見ましたが
これは DVD ドライブの物理的に稼働するモーター部分が影響したものと思われます。
常時稼働のサーバ用途を考えるとおそらく普段は平均 30W 前後の消費電力でしょう。
地球に優しい省エネサーバです♪
と言うことで、Atom プロセッサーと OpenSolaris を組み合わせる事で
とうとう電気料金にビクビクせずに常時稼働の Solaris サーバ環境を
自宅にもお気楽に導入出来る時代がやって参りました!(^o^)/
さーて、どんなサービスをこのサーバの上で動かしましょうか?
夢は広がります!(^o^)
Posted at 01:15午後 3 26, 2009 by moridenki in Sun | 投稿されたコメント[4]
fstyp コマンドの紹介
今回は、fstyp コマンドの使い方を紹介します。
fstyp は、物理ディスクに対してどのようなファイルシステムが構築 されているか簡単に確認できるコマンドで、マウントされていないディスクの ファイルシステムを確認するときに便利です。
最近では、ZFS でファイルシステムを作成する機会も増えていると思います。 いざ、新しいファイルシステムを構成する際、古いディスクの内容が UFS か ZFS か マウントする前に確認できます。
では早速 fstyp コマンドを実行してみましょう。今回は、 ufs と zfs の パターンを試してみます。
# fstyp /dev/rdsk/c2t0d0s0 zfs # fstyp /dev/rdsk/c1d0s0 ufsこのように、ファイルシステムの種類が確認できます。
また、fstyp に -v オプションを付与して実行すると、ファイルシステムの 詳細な情報が出力されます。
# fstyp -v /dev/rdsk/c2t0d0s0
zfs
version=10
name='test-pool'
state=0
txg=4
pool_guid=6270673848113803569
hostid=732000556
hostname='pana'
top_guid=7931163825645079126
guid=7931163825645079126
vdev_tree
type='disk'
id=0
guid=7931163825645079126
path='/dev/dsk/c2t0d0s0'
phys_path='/pci@0,0/pci10f7,8338@1d,7/storage@2/disk@0,0:a'
whole_disk=0
metaslab_array=14
metaslab_shift=22
ashift=9
asize=504889344
is_log=0
# fstyp -v /dev/rdsk/c1d0s0
ufs
magic 11954 format dynamic time Tue Mar 24 16:18:53 2009
sblkno 16 cblkno 24 iblkno 32 dblkno 760
sbsize 2048 cgsize 8192 cgoffset 64 cgmask 0xffffffc0
ncg 417 size 20480544 blocks 20170273
bsize 8192 shift 13 mask 0xffffe000
fsize 1024 shift 10 mask 0xfffffc00
frag 8 shift 3 fsbtodb 1
minfree 1% maxbpg 2048 optim time
maxcontig 7 rotdelay 0ms rps 60
csaddr 760 cssize 7168 shift 9 mask 0xfffffe00
ntrak 48 nsect 128 spc 6144 ncyl 6667
cpg 16 bpg 6144 fpg 49152 ipg 5824
nindir 2048 inopb 64 nspf 2
nbfree 1483254 ndir 41078 nifree 2177920 nffree 247827
cgrotor 269 fmod 0 ronly 0 logbno 1568
version 2
fs_reclaim is not set
ファイルシステム状態は有効です。fsclean の値は -3 です。
どの回転配置でもブロックを利用できます。
シリンダ数 0:
位置 0: 0 8 16 24 32 40 48 56 64 72 80 88
96 104 112 120 128 136 144 152 160 168 176 184
192 200 208 216 224 232 240 248 256 264 272 280
288 296 304 312 320 328 336 344 352 360 368 376
....
....
(以下省略)
fstyp の -v オプションは、ZFS のバーション確認をしたい場合や、UFS の 状態を確認したい時に便利ですね。
Posted at 06:01午後 3 25, 2009 by Naoyuki Yamada in Sun | 投稿されたコメント[0]
vmstat コマンドの読み方
はじめに
今回は vmstat コマンドの出力について解説したいと思います。vmstat は性能解析や障害解析を行う際に最も基本的なコマンドです。vmstat を使用すると、サーバのリソースとして不足しがちな CPU とメモリの使用状況を俯瞰する事が出来ます。システムの解析を行う際はまず vmstat から始め、症状に応じて別のツールを試して行って下さい。
vmstat のお勧めのオプション
インターバルのみ
% vmstat 1
vmstat コマンドの最も一般的な使い方はインターバルのみを付けて実行する事です。インターバルは 1 秒を指定します。より正確な負荷状況を見る為、長期間の性能監視の場合でもインターバルは 1 秒にする事をお勧めします。
"-p" オプション
% vmstat -p 1
vmstat コマンドに -p オプションを付けると仮想メモリのページングに関する統計情報を取得する事が出来ます。ファイルシステムの仮想メモリ操作については fsstat -v で見る事も可能です。インターバルは 1 にして下さい。
vmstat の出力
インターバルのみの場合の出力
% vmstat 1 kthr memory page disk faults cpu r b w swap free re mf pi po fr de sr cd -- -- -- in sy cs us sy id 0 0 0 1496704 529544 7 7 19 0 0 0 2 3 0 0 0 259 559 296 1 1 97 0 0 0 1430068 455792 6 25 0 0 0 0 0 0 0 0 0 314 1175 458 2 2 96 0 0 0 1430068 455816 0 0 0 0 0 0 0 0 0 0 0 313 1133 440 1 2 97 0 0 0 1430068 455816 0 0 0 0 0 0 0 5 0 0 0 377 1340 511 1 2 97
"-p" を付けた場合の出力
% vmstat -p 1
memory page executable anonymous filesystem
swap free re mf fr de sr epi epo epf api apo apf fpi fpo fpf
1496676 529516 7 7 0 0 2 1 0 0 0 0 0 18 0 0
1430020 455744 7 26 0 0 0 0 0 0 0 0 0 0 0 0
1430020 455768 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1430020 455768 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vmstat のカラムの意味
kstat
vmstat の各カラムの値は Solaris の kstat という仕組みを利用して取得しています。kstat にはカーネルやドライバから統計情報が逐一報告されており、OS がブートして以降の様々なデータが保存されています。kstat に保存されている統計情報は kstat コマンドを引数無しで実行する事でダンプする事が可能です。また、C や Perl から libkstat というライブラリを使用する事でも kstat のデータにアクセスする事が出来ます。vmstat は libkstat ライブラリを使用しています。
vmstat の出力の殆どは /usr/src/cmd/stat/vmstat/vmstat.c の dovmstats() 関数の中で行われています。一部 I/O の統計情報は show_disk() 関数の中で出力しています。いずれも libkstat の関数を呼び出す事で kstat の情報を取得し、それを加工して出力しています。
数値が幾つなら問題なのか
vmstat の数値はシステムの異常を報せてくれますが、数値が幾つなら問題なのかは常に状況次第です。free の値が 0 ならば明らかにメモリを増強すべきです。しかし sy の値が 10 万を越えていたらどうでしょうか。システムの規模によっては多すぎるかもしれませんが、システムコールに大きく依存したアプリケーションを動かしているのかもしれません。id が 0 である事は問題でしょうか。もし必要なだけトランザクションを捌けているのであれば、vmstat の値が幾つであろうと問題は無いと言う事も可能です。この様に、vmstat の値に閾値を設定して異常かどうかを一律判断するのは困難です。他のコマンドと合わせて、こまめに統計情報を集めて、比較をする中で異常が発生しているかどうか判断して下さい。
r
r は run queue です。CPU の割り当てを待っているカーネルスレッドの数を表しています。この値が 10 以上又は CPU 数の倍以上の場合は CPU への負荷が高い状態になっていると言われています。CPU 負荷は mpstat や prstat 等、他にも様々な方法で確かめる事が出来ます。run queue は情報の一つとしてご覧下さい。
r の値は kstat の unix:0:sysinfo:runque という名前で保存されています。この値は "kstat -p 'unix:0:sysinfo:runque' 1" というコマンドを実行する事で取得する事が可能です。kstat コマンドの結果は累積値で出ますので、差分を取って下さい。
kstat の unix:0:sysinfo:runque は /usr/src/uts/common/disp/disp.c の disp_nrunnable を /usr/src/uts/common/os/clock.c の clock() 関数の中で集計した値です。それぞれの変数がどこで更新されているかは http://src.opensolaris.org/source/index.jsp から検索する事が可能です。
b
b は I/O で待たされているカーネルスレッドの数です。b の値が多い場合は iostat や fsstat, DTrace 等を使用して更に分析して下さい。I/O 待ちをしているスレッドの数が多い場合は I/O の対象となっているディスクを分散したり、ストレージを増強する等の対策が有効です。
b の値は kstat の unix:0:sysinfo:waiting から取られています。"kstat -p 'unix:0:sysinfo:waiting' 1" を実行すると同じ値を取得する事が可能です。kstat コマンドの結果は累積値で出ますので、差分を取って下さい。
kstat の unix:0:sysinfo:waiting は /usr/src/uts/common/os/clock.c の w_io の値から計算されています。w_io は /usr/src/uts/common/os/bio.c の biowait() 関数の中の atomic_add_64(&cpup->cpu_stats.sys.iowait, 1); で加算されている iowait の値を取っています。
w
w は メモリ不足により swap out されたカーネルスレッドの数です。スワップが発生している場合は、メモリを追加してあげるなどの対策が必要です。
w の値は kstat の unix:0:sysinfo:swpque から取られています。"kstat -p 'unix:0:sysinfo:swque' 1" を実行すると同じ値を取得する事が可能です。kstat コマンドの結果は累積値で出ますので、差分を取って下さい。
kstat の unix:0:sysinfo:swque の値は /usr/src/uts/common/os/clock.c の sysinfo.swpque += nswapped; で加算されています。nswapped 変数は /usr/src/uts/common/os/sched.c の swapin() 関数でデクリメントされ、swapout() 関数と process_swap_queue() 関数の中でインクリメントされています。
swap
swap は現在使用可能なスワップ領域のサイズ (Kilo-Bytes) です。ディスク上のスワップ領域とメモリ上のスワップ領域を合わせた大きさになります。
swap の値は kstat の unix:0:vminfo:swap_avail をページ数単位から KB 単位に直した物です。"kstat -p 'unix:0:vminfo:swap_avail' 1" を実行すると同じ値を取得する事が可能です。kstat コマンドの結果は累積値で出ますので差分を取り、ページサイズを掛けて 1024 で割って下さい。ページサイズは pagesize コマンドで取得出来ます。
kstat の unix:0:vminfo:swap_avail は /usr/src/uts/common/os/clock.c 内で計算されています。計算式は k_anoninfo.ani_max - k_anoninfo.ani_phys_resv + MAX((spgcnt_t)(availrmem - swapfs_minfree), 0) で、これは /usr/src/uts/common/vm/anon.h にも CURRENT_TOTAL_AVAILABLE_SWAP として定義されています。この計算式は、ディスクスワップ領域からリザーブ済み領域のサイズを引き、利用可能なメモリ量から swapfs_minfree の値を引いた結果が正数だった場合はその値を足して、使用可能なスワップ領域のサイズとしています。
k_anoninfo は /usr/include/vm/anon.h に定義されており、ani_max や ani_phys_resv を含んでいます。
k_anoninfo.ani_max は ディスクスワップ領域を表しており /usr/src/uts/common/vm/vm_swap.c の swapadd() 関数で加算され、swapdel() 関数で減算されています。
k_anoninfo.ani_phys_resv はディスクスワップの内、リザーブ済みの領域を表しており、 /usr/src/uts/common/vm/vm_swap.c や /usr/src/uts/common/vm/vm_anon.c の中で更新されています。
availrmem(available real memory) は利用可能なメモリの量を表しています。/usr/src/uts/common/vm/vm_page.c 等で更新されています。現在の availrmem の値は "kstat 'unix:0:system_pages:availrmem' 1" で取得する事が出来ます。
swapfs_minfree は swapfs の上限を決める為の変数です。swapfs は availrmem - swapfs_minfree 以上大きくはなりません。swapfs_minfree の値は /usr/src/uts/common/fs/swapfs/swap_subr.c の swapfs_recalc() 関数で更新されています。現在の swapfs_minfree の値は "echo swapfs_minfree/D | mdb -k" を実行する事で確認する事が出来ます。
free
free は空きメモリのサイズ (Kilo-Bytes) です。この値が小さくなったらメモリが圧迫されている状態です。UFS のキャッシュは free から取られますが、その場合は free の値は減りません。一方、ZFS のキャッシュは free の値を減らすので、使用しているファイルシステムによって注意して読む必要があります。メモリの統計情報は "echo '::memstat' | mdb -k" でも取得する事が可能です。
free の値は kstat の unix:0:vminfo:freemem をページサイズ単位から KB 単位に直した数値です。"kstat -p 'unix:0:vminfo:freemem' 1" を実行すると同じ値を取得する事が可能です。kstat コマンドの結果は累積値で出ますので差分を取って、その値にページサイズを掛けて 1024 で割って下さい。ページサイズは pagesize コマンドで取得出来ます。
kstat の unix:0:vminfo:freemem は /usr/src/uts/common/os/clock.c 内で freemem の値が代入されています。freemem は /usr/src/uts/common/vm/vm_page.c 等で更新されています。
re
re(page reclaims) は一旦 free list に入れられた後に、そのページ上のデータが再び必要になって復帰したページ数です。
re の値は kstat の cpu::vm:pgrec から取られています。"kstat -p 'cpu::vm:pgrec' 1" を実行すると CPU 毎の値を取得する事が出来ます。free list からの reclaim のみをカウントする場合は kstat の cpu:0:vm:pgfrec を参照して下さい。
kstat の cpu::vm:pgrec は /usr/src/uts/common/vm/vm_page.c の page_reclaim() 関数の中の CPU_STATS_ADDQ(cpup, vm, pgrec, 1); と /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の中の CPU_STATS_ADDQ(cpup, vm, pgrec, pgrec); で計算されています。pvn_write_done() 関数は仮想メモリのページアウト終了時に呼び出される関数です。
mf
mf は minor fault です。minor fault は本来 I/O が発生しない fault の事ですが、HAT fault と Address Space fault を足した数値をカウントしています。
mf の値は kstat の cpu::vm:hat_fault + cpu::vm:as_fault から取られています。"kstat -p 'cpu::vm:hat_fault' 1" と "kstat -p 'cpu::vm:as_fault' 1" を実行し、両者の値を足し合わせる事で mf の値を取得する事が出来ます。ただし hat_fault は現在は全く更新されていない様です。また、kstat の値は累積値が出ますので、差分を取る必要があります。
kstat の cpu::vm:as_fault は /usr/src/uts/common/vm/vm_as.c の as_fault() 関数で計算されています。
pi
pi はページインされたメモリサイズ (Kilo-Bytes) です。
pi の値は kstat の cpu::vm:pgpgin から取られています。"kstat -p 'cpu::vm:pgpgin' 1" を実行する事で pi 同じ値を取得する事が出来ます。kstat の値は累積値なので差分を取って下さい。
kstat の cpu::vm:pgpgin の値は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中の CPU_STATS_ADDQ(cpup, vm, pgpgin, btopr(len)); で加算されています。pageio_setup() 関数はメモリページング用にバッファを用意する関数です。
po
po はページアウトされたメモリサイズ (Kilo-Bytes) です。
po の値は kstat の cpu::vm:pgpgout から取られています。"kstat -p 'cpu::vm:pgpgout' 1" を実行すると同じ値を取得する事が可能です。なお、kstat の値は累積値ですので、差分を取ってあげる必要があります。
kstat の cpu::vm:pgpgout の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の CPU_STATS_ADDQ(cpup, vm, pgpgout, pgpgout); で加算されています。
fr
fr は free されたメモリサイズ (Kilo-Bytes) です。
fr の値は kstat の cpu::vm:dfree から取られています。"kstat -p 'cpu::vm:dfree' 1" を実行する事で同じ値を取得する事が可能です。
kstat の cpu::vm:dfree の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の CPU_STATS_ADDQ(cpup, vm, dfree, dfree); や /usr/src/uts/common/os/vm_pageout.c の checkpage() 関数の CPU_STATS_ADD_K(vm, dfree, 1); で加算されています。
de
de(deficit) は沢山のメモリ要求が予想される様な状況で、Solaris の仮想メモリが予備として確保するバッファのサイズです。de の値が増えている場合はメモリ不足が疑われます。
de の値は kstat の unix:0:system_misc:deficit から取られています。"kstat -p 'unix:0:system_misc:deficit' 1" を実行すると同じ値を取得する事が可能です。
kstat の unix:0:system_misc:deficit の値は /usr/src/uts/common/os/exec.c, /usr/src/uts/common/os/vm_meter.c, /usr/src/uts/common/os/sched.c, /usr/src/uts/common/os/mmapobj.c の中で計算されています。
sr
sr はページアウトスキャナによってスキャンされたメモリページ数です。ページスキャンが頻発している場合はメモリ不足の可能性があります。ページスキャンは CPU を消費しますので、sr は発生しない事が望ましいです。
sr の値は kstat の cpu::vm:scan から取られています。"kstat -p 'cpu::vm:scan' 1" を実行する事で CPU 毎の sr の値を取得する事が出来ます。kstat の値は累積値なので数秒実行して差分を取って下さい。
kstat の cpu::vm:scan の値は /usr/src/uts/common/os/vm_pageout.c の pageout_scanner() 関数中の CPU_STATS_ADDQ(CPU, vm, scan, 1); で加算されています。
disk
disk はディスクを読み書きした回数です。ディスクの I/O を調べたい場合は iostat コマンドを使用して下さい。
disk の値は kstat のディスクの reads と writes を足した物です。"kstat -p ':::reads' 1" と "kstat -p ':::writes' 1" の出力のうち、ディスクに関する物 (sd など) を集計する事で同じ値を求める事が出来ます。
in
in はインタラプトの回数です。
in の値は kstat の cpu::sys:intr から取られています。"kstat -p 'cpu::sys:intr' 1" を実行する事で CPU 毎のインタラプト回数を取得する事が可能です。インタラプトを調べる場合は mpstat や intrstat コマンドを使用して下さい。
kstat の cpu::sys:intr の値は /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) や /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) で計算されている様です。
sy
faults の下にある sy はシステムコールの回数です。
sy の値は kstat の cpu::sys:syscall から取られています。"kstat -p 'cpu::sys:syscall' 1" を実行する事で CPU 毎のシステムコールの回数を取得する事が可能です。kstat の値は累積値ですので、差分を取って下さい。
kstat の cpu::sys:syscall の値は /usr/src/uts/sparc/v9/ml/syscall_trap.s の CPU_STATS_SYS_SYSCALL (SPARC) や /usr/src/uts/intel/ia32/os/syscall.c の dosyscall() 関数の中の 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) 等で計算されています。
cs
cs(CPU context switches) はコンテクストスイッチが発生した回数です。多すぎるコンテクストスイッチは CPU を無駄に消費します。スレッド数を減らしたり、プロセッサセットを作って対処して下さい。
cs の値は kstat の cpu::sys:pswitch から取られています。"kstat -p 'cpu::sys:pswitch' 1" を実行すると CPU 毎のコンテクストスイッチの回数を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::sys:pswitch の値は /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); で更新されています。
us
us はユーザモードで使用した CPU 時間の割合です。
us の値は kstat の cpu::sys:cpu_ticks_user から取られています。"kstat -p 'cpu::sys:cpu_ticks_user' 1" で CPU 毎の us の値を取得出来ます。kstat の値は累積です。
kstat の cpu::sys:cpu_ticks_user は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数の中で cpu::sys:nsec_user の値から計算されています。cpu::sys:nsec_user の値は /usr/src/uts/i86pc/os/machdep.c (x86) や /usr/src/uts/sun4/os/machdep.c (SPARC) の中の get_cpu_mstate() 関数の中で計算されています。
sy
cpu の下に表示される sy はカーネルサービスやシステムコールなど、システムモードで使用した CPU 時間の割合です。
sy の値は kstat の cpu::sys:cpu_ticks_kernel から取られています。"kstat -p 'cpu::sys:cpu_ticks_kernel' 1" を実行すると CPU 毎の sy の値を取得する事が可能です。kstat の値は累積です。
kstat の cpu::sys:cpu_ticks_kernel は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数の中で cpu::sys:cpu_nsec_kernel から計算されています。cpu::sys:cpu_nsec_kernel の値は /usr/src/uts/i86pc/os/machdep.c (x86) や /usr/src/uts/sun4/os/machdep.c (SPARC) の中の get_cpu_mstate() 関数の中で計算されています。
id
id は CPU が使用されていなかった時間の割合です。
id の値は kstat の cpu::sys:cpu_ticks_idle から取られています。"kstat -p 'cpu::sys:cpu_ticks_idle' 1" を実行する事で CPU 毎の id の値を取得する事が可能です。kstat の値は累積です。
kstat の cpu::sys:cpu_ticks_idle は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数の中で cpu::sys:cpu_nsec_idle から計算されています。cpu::sys:cpu_nsec_idle の値は /usr/src/uts/i86pc/os/machdep.c (x86) や /usr/src/uts/sun4/os/machdep.c (SPARC) の中の get_cpu_mstate() 関数の中で計算されています。
epi
epi(executable page-ins) は実行ファイルかライブラリであると思われるデータがページインしたページ数です。具体的には VVMEXEC フラグが立っているページをカウントしています。
epi の値は kstat の cpu::vm:execpgin から取られています。"kstat -p 'cpu::vm:execpgin' 1" を実行する事で CPU 毎の epi の値を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::vm:execpgin の値は /src/uts/common/os/bio.c の pageio_setup() 関数の CPU_STATS_ADDQ(cpup, vm, execpgin, btopr(len)); で加算されています。
epo
epo(executable page-outs) は VVMEXEC フラグが立っているメモリがページアウトしたページ数です。
epo の値は kstat の cpu::vm:execpgout から取られています。"kstat -p 'cpu::vm:execpgout' 1" を実行する事で CPU 毎の epo を取得する事が可能です。kstat の値は累積です。
kstat の cpu::vm:execpgout の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の中の CPU_STATS_ADDQ(cpup, vm, execpgout, execpgout); で加算されています。
epf
epf(executable page-frees) は VVMEXEC フラグが立っているページが解放されたページ数です。
epf の値は kstat の cpu::vm:execfree から取られています。"kstat -p 'cpu::vm:execfree' 1" を実行する事で CPU 毎の epf の値を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::vm:execfree の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数中の CPU_STATS_ADDQ(cpup, vm, execfree, execfree); や /usr/src/uts/common/os/vm_pageout.c の checkpage() 関数の中の CPU_STATS_ADD_K(vm, execfree, 1); で加算されています。
api
api(anonymous page-ins) は anonymous メモリのページインしたページ数です。
api の値は kstat の cpu::vm:anonpgin から取られています。"kstat -p 'cpu::vm:anonpgin' 1" を実行すると CPU 毎の anonpgin の値を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::vm:anonpgin は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中で B_READ フラグと VISSWAPFS フラグが立っている場合に CPU_STATS_ADDQ(cpup, vm, anonpgin, btopr(len)); で加算されています。
apo
apo は anonymous メモリがページアウトされたページ数です。
apo の値は kstat の cpu::vm:anonpgout から取られています。"kstat -p 'cpu::vm:anonpgout' 1" を実行すると CPU 毎の apo の値を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::vm:anonpgout の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の中で VISSWAPFS フラグが立っている場合に CPU_STATS_ADDQ(cpup, vm, anonpgout, anonpgout); で加算されています。
apf
apf は anonymous メモリが解放されたページ数です。
apf の値は kstat の cpu::vm:anonfree から取られています。"kstat -p 'cpu::vm:anonfree' 1" を実行すると CPU 毎の apf の値が取得出来ます。kstat の値は累積値です。
kstat の cpu::vm:anonfree の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の中で VISSWAPFS フラグが立っている場合に CPU_STATS_ADDQ(cpup, vm, anonfree, anonfree); で加算されています。また /usr/src/uts/common/os/vm_pageout.c の checkpage() 関数の中の CPU_STATS_ADD_K(vm, anonfree, 1); でも加算されています。
fpi
fpi はファイルシステムページのページインしたページ数です。
fpi の値は kstat の cpu::vm:fspgin から取られています。"kstat -p 'cpu::vm:fspgin' 1" を実行すると CPU 毎の fpi の値を取得する事が可能です。
- kstat の cpu::vm:fspgin の値は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中の CPU_STATS_ADDQ(cpup, vm, fspgin, btopr(len)); で加算されています。
fpo
fpo はファイルシステムページのページアウトしたページ数です。
fpo の値は kstat の cpu::vm:fspgout から取られています。"kstat -p 'cpu::vm:fspgout' 1" を実行すると CPU 毎の fpo の値を取得する事が可能です。kstat の値は累積値です。
kstat の cpu::vm:fspgout の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の CPU_STATS_ADDQ(cpup, vm, fspgout, fspgout); で加算されています。
fpf
fpf はファイルシステムページの解放されたページ数です。
fpf の値は kstat の cpu::vm:fsfree から取られています。"kstat -p 'cpu::vm:fsfree' 1" を実行すると CPU 毎の fpf の値を取得する事が出来ます。kstat の値は累積値です。
kstat の cpu::vm:fsfree の値は /usr/src/uts/common/vm/vm_pvn.c の pvn_write_done() 関数の中の CPU_STATS_ADDQ(cpup, vm, fsfree, fsfree); や /usr/src/uts/common/os/vm_pageout.c の checkpage() 関数の中の CPU_STATS_ADD_K(vm, fsfree, 1); で加算されています。
vmstat のソースコード
/usr/src/cmd/stat/vmstat/vmstat.c
vmstat のソースコードは 500 行程度と非常に短く、簡単に読む事が出来ます。何故これほど短いかというと、vmstat コマンドが行っているのはカーネル内に蓄積された統計情報を取得して整形しているだけだからです。カーネルから情報を取得する部分はライブラリ化されており、幾つかの関数を呼び出すだけで簡単に必要なデータを入手する事が出来ます。このライブラリは libkstat という名前で、どんなプログラムからも使用する事が可能です。libkstat を使えば vmstat に限らず、カーネルの統計情報を処理するプログラムを簡単に作成出来ます。libkstat の使い方は http://blogs.sun.com/solairo/entry/libkstat にまとめてありますので、宜しければご参照下さい。NIC の統計情報を読み出すコマンドを作る例を元に解説しています。
終わりに
vmstat の各カラムの意味を解説しました。vmstat は Solaris の性能解析やトラブルシュートを行う際に最も基本的なコマンドです。是非使いこなして下さい。また、vmstat が kstat の情報を使用している事をご紹介しました。kstat は vmstat に限らず、mpstat や iostat でも使用されています。kstat コマンドも libkstat も使用方法は非常に簡単です。こちらも是非お試し下さい。
参考文献
- The memory go round
- Clearing up swap space confusion
- The Solaris Memory System
- http://opensolaris.org/os/community/edu/3.4.3.pdf
Posted at 11:45午前 3 24, 2009 by Daisuke Homma in Sun | 投稿されたコメント[0]
Solaris Zone 毎に default router を設定する方法
今回は、Solaris コンテナの Shared IP Zone 内に default router を設定 する方法を紹介します。
今まで、Shared IP Zone に対しては、個別でルーティング情報の設定ができません でしたが、Solaris 10 10/08 以降では Zone を定義する際、 default router の プロパティが追加されました。
それでは実際に設定してみましょう。具体的には zonecfg コマンドの "set defrouter=" で指定します。
今回は、ゾーン名 test-zone に default router 192.168.200.1 の設定を行ってみました。
global# zonecfg -z test-zone test-zone: そのような構成済みゾーンはありません 'create' を使用して、新しいゾーンの構成を開始してください。 zonecfg:test-zone> create zonecfg:test-zone> set zonepath=/export/zone/test-zone zonecfg:test-zone> add net zonecfg:test-zone:net> set physical=rtls0 zonecfg:test-zone:net> set address=192.168.200.62 zonecfg:test-zone:net> set defrouter=192.168.200.1 zonecfg:test-zone:net> end設定した default router を確認してみます。
zonecfg:test-zone> info
zonename: test-zone
zonepath: /export/zone/test-zone
brand: native
autoboot: false
ip-type: shared
....(省略)....
net:
address: 192.168.200.62
physical: rtls0
defrouter: 192.168.200.1
....(省略)....
ネットワークの設定項目に defrouter プロパティが追加された事が確認できます。早速 test-zone を立ち上げてルーティングテーブルを確認してみます。
test-zone# netstat -rn Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 192.168.200.1 UG 1 0 rtls0 192.168.200.0 192.168.200.62 U 1 0 rtls0:1 224.0.0.0 192.168.200.62 U 1 0 rtls0:1 127.0.0.1 127.0.0.1 UH 7 126 lo0:1netstat -rn で確認すると、default router の設定が反映されています。
また、global zone 上でルーティングテーブルを確認すると当然ながら test-zone で 設定した default router が追加されました。
global# netstat -rn Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 192.168.200.1 UG 1 0 rtls0 192.168.100.0 192.168.100.60 U 1 0 rtls0 224.0.0.0 192.168.100.60 U 1 0 rtls0 127.0.0.1 127.0.0.1 UH 4 145 lo0
これでまた一つ Solaris コンテナの制限が無くなり使いやすくなりました。 今まで default router の設定を行いたい為だけに Exclusive IP Zone を 使用していた方には朗報ですね。
(参考情報)
過去の 「やっぱり Sun がスキ!」blog 記事一覧はこちらを参照下さい。 http://wikis.sun.com/display/yappri/Home
Posted at 09:07午後 2 25, 2009 by Naoyuki Yamada in Sun | 投稿されたコメント[0]
Sun Storage 7000 は実際どれだけ速いのか?
大好評の Sun Storage 7000 ですが、ZFS の機能・管理性・信頼性、SSD のパフォー マンス、さらに Real-Time Visibility と、いいこと尽くめですが、やっぱり実際の 最高パフォーマンスを知りたいですよね。ということで Sun Engineer の Brendan Gregg がいろいろと試してくれました。 彼のブログで オンキャッシュデータの NFS Read と、 HDD からストリーミングしたときの NFS Read/Write の結果が紹介されています。
まずはオンキャッシュでの NFS read です。
2.07 GB/s NFS cache streaming read - SS7410 single head (128GB DRAM, AMD 4C Opteron 2.3GHz), 2x 2x10GbE interface - 20 clients, each with 2x 1GbE ports and running 10 processes - NFSv3/TCP, jumbo frame - 100GB of working set, cached on 128GB RAM of SS7410
いかがでしょうか。2GB/s ということは 2x10GbE の network port を目一杯使って いることになり、オンキャッシュの送信だとしても、わずか 2U ラックサイズ のシャシ1台としては驚異的です。しかも CPU 使用率は 70% 程度とまだ余裕があり ます。さすがクアッドコア CPU を4基も搭載しているだけのことはあります。 さらに、この 16 コアのパワーを引き出すマルチスレッド・カーネルと Sun 独自 の 10 GbE マルチ DMA ネットワークインターフェースの効果も見逃せません。
では、Disk I/O のある場合はどうでしょうか。
1.10 GB/s NFS streaming from disk - SS7410 single head (128GB DRAM, no SSDs) with 2x 10GbE interface - 6 JBODs each with 24 HDDs (ZFS, mirroring) - 10 clients each with 2 threads with iosize 128KB - 1.07 GB/s HDD read
577 MB/s NFS streaming write to disk - SS7410 single head (128GB DRAM, no SSDs) with 2x 10GbE interface - 5 JBODs each with 24 HDDs (ZFS, mirroring) - 20 clients each with 2 threads with iosize 32KB - 1.38 GB/s HDD write (563 MB/s x 2)
ほぼ全てのデータを HDD から NFS クライアントへ転送しているため、性能は落ちて しまいますが、それでも従来と比較すると驚異的な性能といえます。Write の性能が 低いのは、ミラー化された2つの HDD へ書き込むため2倍のオペレーションが発生 するためです。ちなみに、RAID 構成を mirroring ではなく、デュアルパリティ の RAID-Z2 とすると、若干性能が低下し 535 MB/s となります。
いずれにせよ、従来の常識とは一線を画す製品であることは間違いなさそうです。 ちなみに、今回の測定環境が少々極端だと思われた方は、 こちらのページに性能見積りの目安として使えそうなデータがありますので ご参考まで。
ストリーミングの帯域 : 1 GB/s on server and 110 MB/sec on client Random Read IOPS(HDD) : 150 random read IOPS per mirrored disks Random Read IOPS(SSD) : 3100 Read IOPS per Read Optimized SSD Synchronous write IOPS : 5000-9000 Synchronous write per Write Optimized SSD 1byte 当たり CPU サイクル: 30-40 cycles per byte for NFS and CIFS 1 client 当たり NFS 帯域 : 1 TCP Window per round trip latency.
(ご注意)... なお、これらご紹介した数値はサンの公式データではありません。 参考値としてお取り扱いください。
Posted at 05:07午後 2 24, 2009 by masahiko in Sun | 投稿されたコメント[0]