FreeBSDマシンが遅すぎる!と思ったらZFSデバイスが壊れてたでごんす

まとめ

  • ZFSの中のディスクはログを残さずひっそり壊れてることがあります。注意!!!
  • 個別のディスクの状態を確かめたい時は "/usr/local/sbin/smartctl -a /dev/[ディスク名]"を使いましょう。
  • (全部を横断的に眺めるときは、裏でディスクに負荷をかけつつ"zpool iostat -v [プール名] 1"しましょう。)
  • FreeBSDでバイナリパッケージを使いたい時はpkg_add -rを使いましょう。)

そんなわけで以下経緯:
(以上2013/4/3 追記)


以前ZFSについてごちゃごちゃ試してたサーバ、まだまだ現役です。
構成:

最初のトラブルはNetatalkのドライブが読み書き可能でマウントできなくなったことでした。まだこれは直してないけど、CNID DBが使えないからテンポラリなのを使うよ、リードオンリーマウントだよ、と言われてました。CNID DBを削除しても治らない。

しかし最近はそれだけでなく、sshで入ったときの日々の操作なども、ものすごく遅くなってきました。

  • sshで入るときに1分くらい待たされる
  • lsと打っただけでまた30秒くらい…
  • vimとか起動しようものなら2分くらいプロンプトが返ってこない。
  • コマンドライン補完しようとtabを打つたびに30秒は待たされるので非常なストレスが…

なんだこれは!
ディスクやファイルシステムに見えるんだけど、zpool statusしてもエラーはいっこも出てません。dmesgにも異常がないし、コンソールの画面を見ても何も出てません。これって何だろう。起動用のUSBメモリ?CPUのライトキャッシュとか?マザボ死にかけ?

いろいろおかしいんだけど、パフォーマンスが全体的に落ちてるわけではありません。ルータとしての機能にはまったく問題なかったりする。操作の異様な重さからすれば、このマシンを通した通信はもっと物凄く遅いはず。

twitterでつぶやきながら考えることにしました。

USBメモリの状態がおかしくなってないか、あとZFSも個別のドライブ状態とか、もうちょっと詳しく調べたい。

これまで「何が課題であるか」すらよくわかってない感じでしたが、言語化してみることでキーワードを考えついたというか、探す気になりました。ググってみると、hdparmに当たると思われるのはdiskinfoというコマンドらしい。そんなわけでUSBメモリをdiskinfoしてみたところ、10MB/sくらい出ています。むむ。これは現代のHDDに比べると遅いですが、今のひどい状態を説明することはできないよなあ…。

困っていたら、[twitter:@dankogai]がいろいろアドバイスを下さいました。

仰せのとおりに!このzpool iostat -v [pool名] 1というコマンドは、毎秒の転送レートを表示してくれます。

heliopora# zpool iostat -v tank 1
               capacity     operations    bandwidth
pool         used  avail   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        3.43T  5.63T      5     14  16.1K  44.0K
  raidz1    3.43T  5.63T      5     14  16.1K  44.0K
    ada0        -      -      0     11  43.8K  12.0K
    ada1        -      -      0     11  43.9K  12.0K
    ada2        -      -      0     11  43.0K  12.0K
    ada3        -      -      0     10  43.0K  12.0K
    ada4        -      -      0     11  44.0K  12.0K
----------  -----  -----  -----  -----  -----  -----
 
               capacity     operations    bandwidth
pool         used  avail   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        3.43T  5.63T     57      0  7.23M      0
  raidz1    3.43T  5.63T     57      0  7.23M      0
    ada0        -      -      0      0      0      0
    ada1        -      -      0      0      0      0
    ada2        -      -      0      0      0      0
    ada3        -      -     14      0  1.81M      0
    ada4        -      -      0      0      0      0
----------  -----  -----  -----  -----  -----  -----
 
               capacity     operations    bandwidth
pool         used  avail   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        3.43T  5.63T      0      0      0      0
  raidz1    3.43T  5.63T      0      0      0      0
    ada0        -      -      0      0      0      0
    ada1        -      -      0      0      0      0
    ada2        -      -      0      0      0      0
    ada3        -      -      0      0      0      0
    ada4        -      -      0      0      0      0
----------  -----  -----  -----  -----  -----  -----

って感じ。裏で dd if=FreeBSD8.2R_DVD.img of=/dev/null とかやりながら実行すると、数K〜数Mバイトが転送されてる様子が見える。でも遅いだけですごく異常な感じはしない。gistに貼って[twitter:@dankogai]にご報告。

ところが、ひと目で返事が返ってきました。

なぬ!?と自分でもgistを見返してみると、たしかに1台だけ挙動が違う! 貼って眺めるのが大事だった…!!

そんなわけで、smartctlを実行…いや、このコマンドは入ってませんでした。portsから入れなければ。

cd /usr/ports/sysutils/smartmontools/
make clean ; make install

なんも考えずにコンパイルに掛かったら、make installにおそろしい時間が。ディスクのおかしいマシンでコンパイルとかありえんよなー。これもFreeBSDまともに使ってない証拠でした。コンパイル済みのパッケージを入れるべきでした。

とのこと。次からそうします!

で、2時間ほど経って、ようやくインストールの済んだsmartctlコマンドを使って/dev/ada3を調べてみると、こんな具合に。(そうか。デバイスを一台ずつ見たい時に使うコマンドはこれだったのか!)

/dev/ada3は完全におかしくなってました。まずsmartctlコマンドになかなかレスポンスが返ってこないのはこのデバイスだけ。そしてsmartctlの出力から、おかしなところだけ抜き出すと:

  1 Raw_Read_Error_Rate     0x002f   197   197   051    Pre-fail  Always       -       8305 Reallocated_Sector_Ct   0x0033   188   188   140    Pre-fail  Always       -       234196 Reallocated_Event_Count 0x0032   001   001   000    Old_age   Always       -       218200 Multi_Zone_Error_Rate   0x0008   090   001   000    Old_age   Offline      -       29448

という具合に山ほどのエラーが。健全な/dev/ada2の同じ部分と比べると明白です:

  1 Raw_Read_Error_Rate     0x002f   200   200   051    Pre-fail  Always       -       05 Reallocated_Sector_Ct   0x0033   200   200   140    Pre-fail  Always       -       0196 Reallocated_Event_Count 0x0032   200   200   000    Old_age   Always       -       0200 Multi_Zone_Error_Rate   0x0008   200   200   000    Old_age   Offline      -       16

その他の/dev/ada[0,1,4]も健全で、レスポンスも即時でした。

もうada3の異常で決定な感じなので、一度シャットダウンして、予備のSeagate ST32000542ASと交換することにしました。(ホットスワップせずに一度止めたのは、どのドライブがどのデバイス番号だったか、ちょっとあやふやだったため…。向かって左からada0,1,2,3、光学ドライブベイに入ってるのがada4でした。)

このアレイは4台がWD20EARXで、トラブった1台だけがWD20EARS。Seagateのドライブは、たしかセクターサイズが512BytesだったりSATA2だったりして色々違うディスクだったけど、以前テストしてリプレースに使えることは確認済みのもの。

不安だったディスク交換後の起動にもちゃんと成功したので、zfsが認識してるデバイスのリプレースを行います。

# zpool replace -f tank ada3

このSeagateのドライブは、以前このtankというpoolに繋いでテストしたことがあり、メタ情報が残っているため、-f(force)を付けなければなりませんでした。デフォルトで実行されない操作って少しストレスありますね。
でもコマンドはちゃんと通り、自動的にresilverが開始されました。

heliopora# zpool status
  pool: tank
 state: DEGRADED
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress for 0h7m, 2.14% done, 5h23m to go
config:

        NAME            STATE     READ WRITE CKSUM
        tank            DEGRADED     0     0     0
          raidz1        DEGRADED     0     0     0
            ada0        ONLINE       0     0     0
            ada1        ONLINE       0     0     0
            ada2        ONLINE       0     0     0
            replacing   DEGRADED     0     0     0
              ada3/old  UNAVAIL      0     0     0  cannot open
              ada3      ONLINE       0     0     0  15.0G resilvered
            ada4        ONLINE       0     0     0

errors: No known data errors
heliopora#

ようやく解決!(たぶん!)
[twitter:@dankogai]さんありがとうございました!

それにしても、zpool statusだけじゃエラーが検出できないとは思ってなかったです。ディスクの健全性を検査するスクリプトを書きなおさないと。