FreeBSDサーバーのディスクを壊れてないけど交換...と思ったら別のところが壊れた

こういうことです

A post shared by Kota UENISHI (@kuenishi) on

まとめると…

  • 2TBx4 の構成だったけど年末セールで安いゾってので 4TBx4 に換装するかーと思ってハードディスクを手配
  • 一枚ずつ zpool replace していく作戦
  • メーカーによって replace の性能が全然違う
  • そうこうしているうちに zroot に使っていたSSDがREAD_ERRORを吐きはじめてピンチ
  • そっちを対処
  • なんとか時間をかけて 4TB x4 にアップグレード


これまでの構成は

  • ada0 - SSD 128TB
  • ada1 - SG 3TB ada1 as 予備
  • ada2 - WD 2TB diskid/DISK-WD-WMC4M0F82E9F
  • ada3 - WD 2TB diskid/DISK-WD-WMC4M0E8R6PS
  • ada4 - TSB 2TB diskid/DISK-25RE667AS
  • ada5 - TSB 2TB diskid/DISK-25RE65JAS

で、

# zpool create data mirror ada2 ada3 mirror ada4 ada5 

という感じで作ってある(実際の名前は何か知らんけど再起動のときに変わった)。ところが、2017年の写真をアーカイブして保存して、いろいろやっていたら残り容量が330GBほどになってしまって、あと2年以内に一杯になることがわかった。

%> df -h | grep data
data                  918G    587G    332G    64%    /data
data/user             2.6T    2.3T    332G    88%    /data/user
%> zpool list
NAME    SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
data   3.62T  3.19T   448G         -    30%    87%  1.00x  ONLINE  -
zroot   109G  18.8G  90.2G         -    19%    17%  1.00x  ONLINE  -

やはり空き容量は3〜4割程度に維持しておきたい。ちょうどいいことに、手元にうっかり買ってしまったSeaGateの4TB HDD2枚と、WDの4TB HDDが3枚あるので全部リプレースする。最終的には

# zpool create mirror ada2 (SG) ada3 (WD) mirror ada4 (SG) ada5 (WD)

といった感じにしたい。WDの4TB玉がひとつ余るが、それは予備の遊び場として ada1 あたりにつけておく。

初日 (1/8夜)

リプレース作業開始。まず箱を開けないで、試しに予め ada2 に刺さっている予備の 3TB 玉で gpt/system とかいう変な名前(こういう名前は zpool status で確認しておく)の2TB玉を交換。

%> sudo zpool replace data gpt/system ada1 

これの完了にだいたい1日くらいかかった。これで一日一発という交換ペースが確立。

二日目 (1/9夜)

前日のresilveringが完了していることを完了して、箱をあけて gpt/system とかいうふざけた名前(今はどこにもマウントされないはず)の ada2 を SeaGate の 4TB 玉に換装。マザーボードのどのSATAポートがどの玉に繋がっているのか、KKDで当てるのが醍醐味。無事に交換できたら、 まずは試しに

%> sudo zpool create tank ada2
%> ls /tank
%> sudo zpool destroy tank

などとやってちゃんと使えること ( /tank にマウントされていること ) を確認する。確認できたら壊す。壊したら

%> sudo zpool replace data diskid/DISK-WD-WMC4M0E8R6PSp1 ada2

で交換。 zpool status の結果は

  pool: data
 state: ONLINE
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.
  scan: resilver in progress since Tue Jan  9 22:29:28 2018
        28.8G scanned out of 3.19T at 168M/s, 5h29m to go
        14.2G resilvered, 0.88% done
config:

        NAME                                 STATE     READ WRITE CKSUM
        data                                 ONLINE       0     0     0
          mirror-0                           ONLINE       0     0     0
            diskid/DISK-25RE667ASp1          ONLINE       0     0     0
            diskid/DISK-25RE65JASp1          ONLINE       0     0     0
          mirror-1                           ONLINE       0     0     0
            ada1                             ONLINE       0     0     0
            replacing-1                      ONLINE       0     0     0
              diskid/DISK-WD-WMC4M0E8R6PSp1  ONLINE       0     0     0
              ada2                           ONLINE       0     0     0  (resilvering)

となり、ディスク交換が始まったことがわかる。

三日目朝 (1/10)

さてさて終わってるかな、と思ってサーバー覗きにいったらそもそもつながらない。再起動してもダメ。あわてて押入れからディスプレイ出してさしてみるも正常稼働していたので、インターネットつながらないしこりゃルーターがダメなんかなと思って再起動したらつながってホッとした。慌てている状況でも冷静に切り分けすることが重要です。そろそろフレッツのルーターも換え時っぽい…

さて replace の進捗はどうかなと思って見にいったら予想に反して全然進んでいない。zpoolでresilveringの様子をみても 15M/s くらいか出ていなくて、このままだと35時間くらいかかるとかいう。はて…( ゚д゚)ハッ!この新しいディスクはあのメーカーのやつだ!ということで確信めいた状態で smartctl する。smartctlの結果そのものは正直分からないし、ベンダーにとって意味があるんだろうけど、かかった時間が非常に示唆的でありまして…

%> for n in `seq 0 5`; do time sudo smartctl -a /dev/ada$n > ada$n.txt; done
sudo smartctl -a /dev/ada$n > ada$n.txt  0.02s user 0.02s system 87% cpu 0.047 total
sudo smartctl -a /dev/ada$n > ada$n.txt  0.03s user 0.02s system 23% cpu 0.192 total
sudo smartctl -a /dev/ada$n > ada$n.txt  0.03s user 0.01s system 0% cpu 5.412 total
sudo smartctl -a /dev/ada$n > ada$n.txt  0.03s user 0.01s system 40% cpu 0.090 total
sudo smartctl -a /dev/ada$n > ada$n.txt  0.03s user 0.01s system 3% cpu 1.269 total
sudo smartctl -a /dev/ada$n > ada$n.txt  0.02s user 0.02s system 3% cpu 1.277 total

というわけで、 ada2 の再交換決定。昨夜 iostat 流したらどうもスループットがでてなくて怪しいなと思っていたんだが、道理でダメなわけだ。とりあえず、 ada2 をreplaceから外す。

%> sudo zpool detach data ada2

これだけでmirror-1のreplaceのタスクがキャンセルされたらしく、無事に前の状態にもどってscrub (resilvering) が再開されたようだった。"zfs disk failure during replace" とかで検索しても何もみつからなくて不安だったけど、ドキュメントから類推したらバッチリだった。また筐をあけて玉を交換して、試してみる。

%> for n in `seq 0 5`; do time sudo smartctl -a /dev/ada$n > /dev/null ; done
sudo smartctl -a /dev/ada$n > /dev/null  0.03s user 0.01s system 91% cpu 0.042 total
sudo smartctl -a /dev/ada$n > /dev/null  0.03s user 0.01s system 12% cpu 0.344 total
sudo smartctl -a /dev/ada$n > /dev/null  0.04s user 0.00s system 14% cpu 0.332 total
sudo smartctl -a /dev/ada$n > /dev/null  0.03s user 0.01s system 26% cpu 0.163 total
sudo smartctl -a /dev/ada$n > /dev/null  0.04s user 0.00s system 3% cpu 1.393 total
sudo smartctl -a /dev/ada$n > /dev/null  0.02s user 0.02s system 2% cpu 1.509 total

これなら大丈夫でしょう、ということで再度同じものを replace する。

%> sudo zpool replace data diskid/DISK-WD-WMC4M0E8R6PSp1 ada2

流れているかウォッチ。

%> iostat  -n 6 1                                                            
       tty            ada0             ada1             ada2             ada3             ada4             ada5             cpu
 tin  tout  KB/t tps  MB/s   KB/t tps  MB/s   KB/t tps  MB/s   KB/t tps  MB/s   KB/t tps  MB/s   KB/t tps  MB/s  us ni sy in id
   1   290 17.14   4  0.06  111.99 171 18.72  120.54 590 69.49  118.04 442 50.95   7.82  28  0.21   7.91  28  0.21   0  0  3  0 97
   0   848  0.00   0  0.00  48.00  28  1.30  101.37 130 12.89  102.61 117 11.76  12.41  29  0.35  13.54  26  0.34   0  0  1  0 99
   0   513  0.00   0  0.00  123.09 101 12.12  122.53 339 40.60  122.81 239 28.61   4.00   2  0.01   4.00   1  0.00   0  0  1  0 99
   0   302  0.00   0  0.00  125.15  88 10.72  118.76 351 40.67  117.56 261 29.97   4.00   5  0.02   4.00   6  0.02   0  0  2  0 98
   0   300  0.00   0  0.00  125.43 145 17.76  122.88 433 51.97  122.43 286 34.20   4.00  12  0.05   4.00   9  0.04   0  0  2  0 98
   0   298  0.00   0  0.00  125.42 143 17.49  124.64 476 57.96  123.96 334 40.47   4.00   4  0.02   4.00   5  0.02   0  0  2  0 98
^C
%> zpool status data
   pool: data
 state: ONLINE
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.
  scan: resilver in progress since Wed Jan 10 08:05:23 2018
        150G scanned out of 3.19T at 150M/s, 5h53m to go
        74.7G resilvered, 4.59% done
(snip)

よさそう。とりあえず件の玉は購入したドスパラに交換を要請した。

三日目夜

無事に replace は完了していた。

%> zpool status data
  pool: data
 state: ONLINE
  scan: resilvered 1.60T in 5h3m with 0 errors on Wed Jan 10 13:08:41 2018
config:

        NAME                         STATE     READ WRITE CKSUM
        data                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            diskid/DISK-25RE667ASp1  ONLINE       0     0     0
            diskid/DISK-25RE65JASp1  ONLINE       0     0     0
          mirror-1                   ONLINE       0     0     0
            ada1                     ONLINE       0     0     0
            ada2                     ONLINE       0     0     0

errors: No known data errors
%> zpool list              
NAME    SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
data   4.53T  3.19T  1.34T         -    23%    70%  1.00x  ONLINE  -
zroot   109G  18.8G  90.2G         -    19%    17%  1.00x  ONLINE  -

サイズも4.5TBになって無事 autoexpand が働いていることがわかる。ZFS素晴らしい

ここで、いま宙ぶらりんになっている 2TB 玉を外して、 4TB 玉(SG)に入れ替える。

%> dmesg | grep ada3 
...
ada3 at ahcich3 bus 0 scbus3 target 0 lun 0
ada3: <ST4000DM004-2CV104 0001> ACS-3 ATA SATA 3.x device
ada3: Serial Number ZFN0FBG6
ada3: 600.000MB/s transfers (SATA 3.x, UDMA6, PIO 8192bytes)
ada3: Command Queueing enabled
ada3: 3815447MB (7814037168 512 byte sectors)
ada3: quirks=0x1<4K>
...
%> sudo zpool create tank ada3

で、 /tank が作成される。昨日のこともあるのでスループットをみながら、ちょっと小一時間ほどファイルを書いてみることにする。
1時間ほどcpを回して全然スループットが落ちなかったので replace 開始。

%> sudo zpool replace data ada1 ada3
%> zpool status data
  pool: data
 state: ONLINE
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.
  scan: resilver in progress since Wed Jan 10 21:59:14 2018
        498M scanned out of 3.19T at 33.2M/s, 27h56m to go
        234M resilvered, 0.01% done
config:

        NAME                         STATE     READ WRITE CKSUM
        data                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            diskid/DISK-25RE667ASp1  ONLINE       0     0     0
            diskid/DISK-25RE65JASp1  ONLINE       0     0     0
          mirror-1                   ONLINE       0     0     0
            replacing-0              ONLINE       0     0     0
              ada1                   ONLINE       0     0     0
              ada3                   ONLINE       0     0     0  (resilvering)
            ada2                     ONLINE       0     0     0

errors: No known data errors

無事始まった。ひと晩で終わるはず。

... 小一時間でスループット下がってしまった。

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.
  scan: resilver in progress since Wed Jan 10 21:59:14 2018
        95.7G scanned out of 3.19T at 36.5M/s, 24h42m to go
        48.1G resilvered, 2.93% done

これはハードウェアの故障じゃない感じがする。ぃゃそれともまさかのダブル故障?!
と思って、昨日諦めた方のディスクをLinuxマシンに差して500GBほど書いてみたんだけどおかしなこともない。
FreeBSD側も頑張ってもういちどreplace してみる。

%> sudo zpool replace data ada1 ada3
%> zpool status data
 ...
          29.5G scanned out of 3.19T at 96.5M/s, 9h32m to go
 ...

帰宅、夕食後にチェックしたら無事replaceが終わっていた。OK。そのまま今度は ada1 を交換する。これで ada1 もWDの 4TB HDD になった。

四日目

…さて、と思ったが、どうも様子がおかしい。 pkg update などが度々コケるのである。どうもおかしいと思って dmesg してみると ada0 が今度はおかしい。当時のログをみてみると

Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): CAM status: ATA Status Error
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): ATA status: 41 (DRDY ERR), error: 40 (UNC )
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): RES: 41 40 e8 39 1b 40 01 00 00 08 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): Retrying command
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): READ_FPDMA_QUEUED. ACB: 60 08 e2 39 1b 40 01 00 00 00 00 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): CAM status: ATA Status Error
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): ATA status: 41 (DRDY ERR), error: 40 (UNC )
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): RES: 41 40 e8 39 1b 40 01 00 00 08 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): Retrying command
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): READ_FPDMA_QUEUED. ACB: 60 08 e2 39 1b 40 01 00 00 00 00 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): CAM status: ATA Status Error
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): ATA status: 41 (DRDY ERR), error: 40 (UNC )
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): RES: 41 40 e8 39 1b 40 01 00 00 08 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): Retrying command
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): READ_FPDMA_QUEUED. ACB: 60 08 e2 39 1b 40 01 00 00 00 00 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): CAM status: ATA Status Error
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): ATA status: 41 (DRDY ERR), error: 40 (UNC )
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): RES: 41 40 e8 39 1b 40 01 00 00 08 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): Retrying command
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): READ_FPDMA_QUEUED. ACB: 60 08 e2 39 1b 40 01 00 00 00 00 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): CAM status: ATA Status Error
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): ATA status: 41 (DRDY ERR), error: 40 (UNC )
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): RES: 41 40 e8 39 1b 40 01 00 00 08 00
Jan 10 07:16:10 kushana kernel: (ada0:ahcich0:0:0:0): Error 5, Retries exhausted

といった具合にファイルを読めていない。このままではそもそもOSが危ういと判断して急遽SSDを追加発注。全ての作業をストップさせる。それで、遊んでいる ada1 を急遽ブートディスクに仕立てて、いつでもブートできるようにしておく。

%> sudo gpart add -i 1 -t freebsd-boot -s 1024 ada1                                                                                                                       
ada1p1 added   
%> sudo gpart add -i 2 -t freebsd-swap -s 4194304 ada1
ada1p2 added
kuenishi@kushana:~
%> sudo gpart add -i 3 -t freebsd-zfs ada1
ada1p3 added

=>        40  7814037088  ada1  GPT  (3.6T)
          40        1024     1  freebsd-boot  (512K)
        1064     4194304     2  freebsd-swap  (2.0G)
     4195368  7809841752     3  freebsd-zfs  (3.6T)
  7814037120           8        - free -  (4.0K)
%> sudo zpool attach zroot  diskid/DISK-150315401930p3 ada1p3
Make sure to wait until resilver is done before rebooting.

If you boot from pool 'zroot', you may need to update
boot code on newly attached disk 'ada1p3'.

Assuming you use GPT partitioning and 'da0' is your new boot disk
you may use the following command:

        gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0

%> sudo gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
partcode written to ada1p1
bootcode written to ada1

これで本当に出来たのかどうか知らないが、とりあえず ada1 からブートできるようになったはずだ。いつ ada0 (最初から刺さっていたSSD)が壊れても問題ないはず。

day 5 (1/12)

SSDが届いて、妻に受け取ってもらった。土曜日に作業をする。

day 6 (1/13)

子供達を放置して鯖管作業です

A post shared by Kota UENISHI (@kuenishi) on

さてここからが本番。 resilvering が完了していることを確認して、電源を落としてSSDを交換する。それで起動すると

%> zpool status zroot
  pool: zroot
 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.
  scan: resilver in progress since Sat Jan 13 10:51:50 2018
        5.30G scanned out of 18.8G at 1/s, (scan is slow, no estimated time)
        59.1M resilvered, 28.25% done
config:

        NAME                               STATE     READ WRITE CKSUM
        zroot                              DEGRADED     2     0     0
          mirror-0                         DEGRADED     4     0     0
            5134801585683106761            UNAVAIL      0     0     0  was /dev/diskid/DISK-150315401930p3
            diskid/DISK-WD-WCC7K5CCC1X0p3  ONLINE       0     0     4  (resilvering)

となっており、diskid/DISK-150315401930p3 が取り除かれていることがわかる。かわりに ada0 には新しく 240GB のSSDが刺さっているので、これも同様にブートディスク用にセットアップする。

%> sudo gpart create -s GPT ada0                                                      
Password:
ada0 created
%> sudo gpart add -i 1 -t freebsd-boot -s 1024 ada0 
ada0p1 added
kuenishi@kushana:~
%> sudo gpart add -i 2 -t freebsd-swap -s 4194304 ada0 
ada0p2 added
kuenishi@kushana:~
%> sudo gpart add -i 3 -t freebsd-zfs ada0            
ada0p3 added

セットアップができたらさっそく zroot に追加する。起動できるように bootcode も書き込んでおく。

%> sudo zpool attach zroot diskid/DISK-WD-WCC7K5CCC1X0p3 ada0p3
Make sure to wait until resilver is done before rebooting.

If you boot from pool 'zroot', you may need to update
boot code on newly attached disk 'ada0p3'.

Assuming you use GPT partitioning and 'da0' is your new boot disk
you may use the following command:

        gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0

%> sudo gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0                    
partcode written to ada0p1
bootcode written to ada0

もうそもそも存在しないやつなので、古いやつを外そうとすると叱られる。こいつを外すのに結構苦戦した。

%> sudo zpool detach  zroot  5134801585683106761 
cannot detach 5134801585683106761: no valid replicas
kuenishi@kushana:~
%> sudo zpool detach  zroot /dev/diskid/DISK-150315401930p3
cannot detach /dev/diskid/DISK-150315401930p3: no valid replicas

zpool status で様子をみると

  pool: zroot
 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.
  scan: resilver in progress since Sat Jan 13 10:59:30 2018
        8.28G scanned out of 18.8G at 49.9M/s, 0h3m to go
        8.46G resilvered, 44.15% done
config:

        NAME                               STATE     READ WRITE CKSUM
        zroot                              DEGRADED    34     0     0
          mirror-0                         DEGRADED    68     0     0
            5134801585683106761            UNAVAIL      0     0     0  was /dev/diskid/DISK-150315401930p3
            diskid/DISK-WD-WCC7K5CCC1X0p3  ONLINE       0     0    68  (resilvering)
            ada0p3                         ONLINE       0     0    16  (resilvering)

errors: 40 data errors, use '-v' for a list

となっていて、40ほど壊れたファイルがあるのでまず '-v' をつけて確認して、それを何とかしろといわれる。 -v して出て来るファイルはほとんどが pkg で入るやつで、基本的には無害なので全部 rm で消していく。ファイルを直接消すと引っかかって固まるので、ディレクトリごと消すか、上書きをする。

%> sudo echo "" > /path/to/broken/file

などとやっていくと、

  pool: zroot
 state: DEGRADED
status: One or more devices has experienced an error resulting in data
        corruption.  Applications may be affected.
action: Restore the file in question if possible.  Otherwise restore the
        entire pool from backup.
   see: http://illumos.org/msg/ZFS-8000-8A
  scan: scrub in progress since Sat Jan 13 12:48:39 2018
        3.98G scanned out of 15.3G at 41.2M/s, 0h4m to go
        0 repaired, 25.94% done
config:

        NAME                               STATE     READ WRITE CKSUM
        zroot                              DEGRADED     4     0     0
          mirror-0                         DEGRADED     8     0     0
            5134801585683106761            UNAVAIL      0     0     0  was /dev/diskid/DISK-150315401930p3
            diskid/DISK-WD-WCC7K5CCC1X0p3  ONLINE       0     0     8
            ada0p3                         ONLINE       0     0     8

errors: Permanent errors have been detected in the following files:

        zroot/ROOT/default:<0xb6c01>
        zroot/ROOT/default:<0x6309>
        zroot/ROOT/default:<0x14263>

という風に減っていく。 resilvering が終わってしまっている場合はファイルを消してもういちど "zpool scrub zroot" だ。ちなみにこのとき用事されている
ZFS-8000-8A のURLを見に行くと「プールを再作成する他生き残る道はない」みたいなことが書かれているが、ファイルを諦めるなり自分で作り直せるはずなので特に気にしなくてよい。システムがダメな場合はSSDが壊れた時点でOSが起動しないはずだから。 "zpool status zroot" して

%> sudo zpool status -v zroot   
Password:
  pool: zroot
 state: DEGRADED
status: One or more devices could not be opened.  Sufficient replicas exist for
        the pool to continue functioning in a degraded state.
action: Attach the missing device and online it using 'zpool online'.
   see: http://illumos.org/msg/ZFS-8000-2Q
  scan: scrub repaired 0 in 0h3m with 0 errors on Sat Jan 13 12:52:35 2018
config:

        NAME                               STATE     READ WRITE CKSUM
        zroot                              DEGRADED     4     0     0
          mirror-0                         DEGRADED     8     0     0
            5134801585683106761            UNAVAIL      0     0     0  was /dev/diskid/DISK-150315401930p3
            diskid/DISK-WD-WCC7K5CCC1X0p3  ONLINE       0     0     8
            ada0p3                         ONLINE       0     0     8

errors: No known data errors

となるまでこれを繰り返す。ここまできたらやっともとのSSDを消すことができる。

%> sudo zpool detach zroot /dev/diskid/DISK-150315401930p3
%> sudo zpool status  zroot
  pool: zroot
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://illumos.org/msg/ZFS-8000-9P
  scan: scrub repaired 0 in 0h3m with 0 errors on Sat Jan 13 12:52:35 2018
config:

        NAME                               STATE     READ WRITE CKSUM
        zroot                              ONLINE       4     0     0
          mirror-0                         ONLINE       8     0     0
            diskid/DISK-WD-WCC7K5CCC1X0p3  ONLINE       0     0     8
            ada0p3                         ONLINE       0     0     8

errors: No known data errors

ここまできたら、一時的に使ったHDDも不要なので detach して、新しく追加したSSDだけで起動できるように bootcode をかきなおす。

%> sudo gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0                    
partcode written to ada0p1
bootcode written to ada0

%> sudo zpool detach zroot diskid/DISK-WD-WCC7K5CCC1X0p3          
%> zpool status zroot

  pool: zroot
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.  An
        attempt was made to correct the error.  Applications are unaffected.
action: Determine if the device needs to be replaced, and clear the errors
        using 'zpool clear' or replace the device with 'zpool replace'.
   see: http://illumos.org/msg/ZFS-8000-9P
  scan: scrub repaired 0 in 0h3m with 0 errors on Sat Jan 13 12:52:35 2018
config:

        NAME        STATE     READ WRITE CKSUM
        zroot       ONLINE       4     0     0
          ada0p3    ONLINE       0     0     8

errors: No known data errors

ここで一旦再起動してみて、ちゃんと上がってくることを確認する。いちばんハラハラした瞬間だ。ディスプレイなしで再起動したら上がってこないんだけど、なぜかディスプレイをつなぐと必ず上がってくるという事件に遭遇した。原因は分からないが、上がってきたからよしとするか…。

さてもとのHDD交換作業に戻る。 ada1 にブート用のパーティションを作っているので、まずはそれを作り直す。

%> sudo gpart delete -i 3 ada1
ada1p3 deleted
kuenishi@kushana:~
%> sudo gpart delete -i 2 ada1
ada1p2 deleted
kuenishi@kushana:~
%> sudo gpart delete -i 1 ada1
ada1p1 deleted
kuenishi@kushana:~
%> sudo gpart show ada1       
=>        40  7814037088  ada1  GPT  (3.6T)
          40  7814037088        - free -  (3.6T)

kuenishi@kushana:~
%> sudo gpart add -i 1 
kuenishi@kushana:~
%> sudo gpart add -i 1 -t freebsd-zfs ada1                       
ada1p1 added
kuenishi@kushana:~
%> sudo gpart show ada1                   
=>        40  7814037088  ada1  GPT  (3.6T)
          40  7814037080     1  freebsd-zfs  (3.6T)
  7814037120           8        - free -  (4.0K)

で、これを mirror-0 の 2TB 玉と交換する

%> sudo zpool replace data diskid/DISK-25RE667ASp1 ada1p1


夕食やらなんやらを済ませてジムから帰ってきたら ada1 が無事に入っていた。

%> zpool status data

  pool: data
 state: ONLINE
  scan: resilvered 1.41T in 4h9m with 0 errors on Sat Jan 13 17:13:33 2018
config:

        NAME                         STATE     READ WRITE CKSUM
        data                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            ada1p1                   ONLINE       0     0     0
            diskid/DISK-25RE65JASp1  ONLINE       0     0     0
          mirror-1                   ONLINE       0     0     0
            ada3                     ONLINE       0     0     0
            ada2                     ONLINE       0     0     0

errors: No known data errors

で、こんどは電源を落として、まだ筐体に残っている diskid/DISK-25RE667ASp1 を別の4TB 玉に交換する。

%> sudo gpart show ada4                   
=>        40  7814037088  ada4  GPT  (3.6T)
          40  7814037080     1  freebsd-zfs  (3.6T)
  7814037120           8        - free -  (4.0K)

パーティションつくったのでリプレース

%> sudo zpool replace data diskid/DISK-25RE65JASp1 ada4p1
%> zpool status data                                     
  pool: data
 state: ONLINE
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.
  scan: resilver in progress since Sat Jan 13 17:57:08 2018
        22.2M scanned out of 2.86T at 2.47M/s, 337h21m to go
        11.7M resilvered, 0.00% done
config:

        NAME                           STATE     READ WRITE CKSUM
        data                           ONLINE       0     0     0
          mirror-0                     ONLINE       0     0     0
            ada1p1                     ONLINE       0     0     0
            replacing-1                ONLINE       0     0     0
              diskid/DISK-25RE65JASp1  ONLINE       0     0     0
              ada4p1                   ONLINE       0     0     0  (resilvering)
          mirror-1                     ONLINE       0     0     0
            ada3                       ONLINE       0     0     0
            ada2                       ONLINE       0     0     0

夕方には完了していたので、 diskid/DISK-25RE65JASp1 を最後の一玉と交換。

%> zpool list
NAME    SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
data   7.25T  2.86T  4.39T         -    12%    39%  1.00x  ONLINE  -
zroot   221G  15.3G   206G         -     9%     6%  1.00x  ONLINE  -

さてここで気づいたのだが、なんと ada2 と ada3 はGPTを作らずにそのまま attach してしまっていた。このままでは gpart で一切いじれなくなって、 "No such geom." みたいなエラーが事あるごとに出てくるので、それを是正するためにまた作業をする。また、 mirror-0とmirror-1 はどちらのペアも別ベンダーのディスクにするようにこれから作業していく。まず差し替えた ada5 を ada3 と交換する方向で。

%> dmesg | grep ada5
ada5 at ahcich5 bus 0 scbus5 target 0 lun 0
ada5: <ST4000DM004-2CV104 0001> ACS-3 ATA SATA 3.x device
ada5: Serial Number ZFN0FKPR
ada5: 600.000MB/s transfers (SATA 3.x, UDMA6, PIO 8192bytes)
ada5: Command Queueing enabled
ada5: 3815447MB (7814037168 512 byte sectors)
ada5: quirks=0x1<4K>
%> sudo gpart create -s GPT ada5
gpart: geom 'ada5': Operation not permitted

パーティション作ろうと思ったらとりつくしまもない。

%> ls /dev/diskid
DISK-WD-WCC7K5ZPD3D3    DISK-WD-WCC7K5ZPD3D3p1  DISK-ZFN0FBG6           DISK-ZFN0FKPR           DISK-ZFN0FKPRp1

デバイスがあったのでこっちを使う。

%> sudo gpart create -s GPT diskid/DISK-ZFN0FBG6       
diskid/DISK-ZFN0FBG6 created
%> sudo gpart add -i 1 -t freebsd-zfs diskid/DISK-ZFN0FBG6
diskid/DISK-ZFN0FBG6p1 added
%> gpart show diskid/DISK-ZFN0FBG6                        
=>        40  7814037088  diskid/DISK-ZFN0FBG6  GPT  (3.6T)
          40  7814037080                     1  freebsd-zfs  (3.6T)
  7814037120           8                        - free -  (4.0K)
%> sudo zpool replace data ada1p1 diskid/DISK-ZFN0FBG6p1
%> sudo zpool replace data ada3 diskid/DISK-ZFN0FKPRp1 ##こんな操作もやったはず…
%> zpool status data                         
  pool: data
 state: ONLINE
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.
  scan: resilver in progress since Sat Jan 13 22:29:17 2018
        2.45G scanned out of 2.86T at 18.1M/s, 46h1m to go
        2.45G resilvered, 0.08% done
config:

        NAME                               STATE     READ WRITE CKSUM
        data                               ONLINE       0     0     0
          mirror-0                         ONLINE       0     0     0
            replacing-0                    ONLINE       0     0     0
              ada1p1                       ONLINE       0     0     0
              diskid/DISK-ZFN0FBG6p1       ONLINE       0     0     0  (resilvering)
            diskid/DISK-WD-WCC7K5ZPD3D3p1  ONLINE       0     0     0
          mirror-1                         ONLINE       0     0     0
            ada2                           ONLINE       0     0     0
            diskid/DISK-ZFN0FKPRp1         ONLINE       0     0     0  (resilvering)

errors: No known data errors

day 7 (1/14)

じーっと見てるだけでほとんど何もなかった。

day 8 朝 (1/15)

ふたつの resilvering が夜に終わったので、 ada2 を更にリプレースする。

%> sudo zpool replace data ada2 ada1p1
%> zpool status data                  
  pool: data
 state: ONLINE
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.
  scan: resilver in progress since Mon Jan 15 08:42:30 2018
        11.2G scanned out of 2.86T at 197M/s, 4h12m to go
        9.19M resilvered, 0.00% done
config:

        NAME                               STATE     READ WRITE CKSUM
        data                               ONLINE       0     0     0
          mirror-0                         ONLINE       0     0     0
            diskid/DISK-ZFN0FBG6p1         ONLINE       0     0     0
            diskid/DISK-WD-WCC7K5ZPD3D3p1  ONLINE       0     0     0
          mirror-1                         ONLINE       0     0     0
            replacing-0                    ONLINE       0     0     0
              ada2                         ONLINE       0     0     0
              ada1p1                       ONLINE       0     0     0  (resilvering)
            diskid/DISK-ZFN0FKPRp1         ONLINE       0     0     0

errors: No known data errors

day 8 夜 (1/15)

完了してた。

%> zpool status data           
  pool: data
 state: ONLINE
  scan: resilvered 1.45T in 3h50m with 0 errors on Mon Jan 15 12:32:58 2018
config:

        NAME                               STATE     READ WRITE CKSUM
        data                               ONLINE       0     0     0
          mirror-0                         ONLINE       0     0     0
            diskid/DISK-ZFN0FBG6p1         ONLINE       0     0     0
            diskid/DISK-WD-WCC7K5ZPD3D3p1  ONLINE       0     0     0
          mirror-1                         ONLINE       0     0     0
            ada1p1                         ONLINE       0     0     0
            diskid/DISK-ZFN0FKPRp1         ONLINE       0     0     0

errors: No known data errors

なっがい道のりでした。予備のディスクも遊べるようにとっておく。

%> sudo gpart create -s GPT ada2
(中略)
%> sudo zpool create attic ada2p1

できあがり。

%> zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
attic                256K  3.51T    88K  /attic
data                2.86T  4.16T   593G  /data
data/user           2.28T  4.16T  2.28T  /data/user
zroot               15.3G   199G    96K  none
zroot/ROOT          13.1G   199G    96K  none
(snip)
%> zpool list
NAME    SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
attic  3.62T   304K  3.62T         -     0%     0%  1.00x  ONLINE  -
data   7.25T  2.86T  4.39T         -    12%    39%  1.00x  ONLINE  -
zroot   221G  15.3G   206G         -     9%     6%  1.00x  ONLINE  -

番外編 壊れたっぽいHDD

ドスパラに連絡したところ、FreeBSD上で見えた状況だけで交換はしてもらえそう。
しかし問い合わせに書いてしまったので、別のLinux箱に挿してもういちど✔してみる。

翌日丁寧な回答が来て、とりあえず送付して調査してもらえそうな感じだった。非常によい対応でした。
Linuxに挿したらふつうに使えたので、 replace のときだけちょっと遅いらしくそのまま使うことにした。なので壊れてはいなかった。なので、修理は依頼しないことにした。

壊れたのは2年ちょい使ったSSDの方だった。

まとめ

  • ブートディスクになっていた 120GB SSDをOSの再インストールなしに240 GB SSDにリプレースした
  • 2TB x4 + 3TB のHDD構成を 4TB x5 にバックアップサーバーもプール再作成もなしで交換した(ダウンタイムはまあそれなりにあった)
  • ZFSは本当にすごい

まあしかしこんなにHDD買ってストレージサーバー回してたら、いったいGCSにどんだけデータ置けるんだよっていう話だわな。

2017年を振り返る

まあ特になんもなかったんですが。いやいろいろあったし特に遠い昔のことのようで上半期の記憶はほとんどありませんが。写真は夏に下鴨神社に行ったときのもので、TVアニメ 有頂天家族の聖地的なやつです。

この写真を見て「(アニメの)あ、あそこだな」と分かった皆さん、さすがです。写真はあまり撮っていなくて、いまみたら100GBちょっとでした。2016年の170GBに比べると大幅減です。改めて振り返ってみると書くことがあまりになくて、ああ2017年はプライベートの時間でほとんどプログラミングも勉強もやってないんだな(スプラトゥーンばっかりやってたんだな)って思いました。

発表など

実はエンジニアリングという意味で費やしていた時間はあまり多くなかったのですが、Apache Mesos(と、拙作Retz)のことを対外的にはやっていました。家でパソコン開いてやってたのは、スプラトゥーンの録画とかだった気がします。

トレーニングをしました

夏頃に減量を始めました。目標は6kg減らすことだったのですが、3kgくらい減らしたところで停滞中です。冬休みがよくない。家でプロテインを飲むときはシェイカーよりもハンドミキサー(ブレンダー)を使った方がいいです。

本をレビューしました

転職時に時間の余裕をつくったので10月はまるまる自分のために時間を使うことができました。収入なかったけど時間はあったので、「仕事ではじめる機械学習」と「Goならわかるシステムプログラミング」のレビューをしました。

仕事ではじめる機械学習

仕事ではじめる機械学習

Goならわかるシステムプログラミング

Goならわかるシステムプログラミング

これで 7つのデータベース 7つの世界すごいErlangゆかいに学ぼう! に続き4冊目です。とても勉強になりました。〆切直前なのにちゃぶ台返して議論を巻き戻すようなコメントばっかりつけてしまってごめんなさい。

転職してPythonを書いています

11月からプリファードネットワークスというところで分散深層学習のフレームワークを作る仕事をしています。本来の目標にはまだ遠いですが、とりあえず何とかして2ヶ月で成果らしいものを出せたのでよかったです。PythonとかOpenCVとか何度もビルドしています。このジャンルはレッドオーシャンとはいっても、まだまだやることできることが沢山あって課題は山積しているし、ソフトウェアエンジニアリング、それも分散システムや分散処理で世界を相手にする職場は東京には少ないのでとてもやりがいがあります。前職のプロダクトも使っているので当面はなんとか仕事がありそうです。

仕事用のOSはArch Linuxにしました。これまでのキャリアで初めてフリーなOSをラップトップで使用しています。マイナーな問題にはいくつか遭遇していますが、他のプロプライエタリなOSのようにどうにもできなくて窓から投げ捨てたくなるようなことはありません。しいていえばNVIDIAのGPUが刺さっていないのでCUDAやCuDNNが使えなくてちょっと困るくらいですかね。まだ外部向けにプレゼンテーションする機会がないのでそちらは未知数ですが、社内で外部ディスプレイに接続するのは支障なくできているので、多分大丈夫そうです。

2018年

4月から下の子が幼稚園に入って初めての社会生活を経験するのでその不安が非常に大きいですが、一方でここ数年で最もエキサイティングな仕事でもあります。論文も一般書も積読はたまる一方で子供は大きくなって家は狭くなるばかりでしょう。身体はますます下り坂の重力加速度にどれだけトレーニングで抗えるかがポイントになるでしょう。一方で人生の経験値もたまってきているのでうまく立ち回れるようにしたいです。もっとも重要な目標はガチアサリでS+にまで上がることです。

最近のトレなど

どうもこんにちはダボハゼことkuenishiです。これは Pyspa アドベントカレンダー 2017 の記事です。主にトレーニングと減量について、近況の変化と共に書くつもりです。結論からいうと想定外の事態はあったものの、減量のマイルストーンを順調にこなしている状態で、このままいけば来年の4月には70kgを切る予定です。

f:id:kuenishi:20171212233052p:plain
減量計画、予定と実績

昨年のアドベントカレンダーの記事をみると2015年末に70kg, 2016年末に73kgほどだった体重が、今年の夏頃には 76kg 超まで増えてしまっていた。これは由々しき事態で、なぜなら週1〜2回のトレーニングは仕事がだるいながらも何とか続けていたからだ。当時のトレーニング内容は毎回同じメニューで、記録をみるに典型的なのは

7/10
Chinning Y6 6 5 4 順手 6 53 パラ 4 3
Hanging raise 15x3
One hand cable over row l/r 5kg 10x2 7.5kg 15x2 10kg 10x2
Shoulder press 10kg 10x2 25kg 8x2
Bench press 40kg->60kg Δ5kg x5 60kg 6x0
Deadlift 60kg 5x2 80kg 5x3
Low row 50kg 10x3

といった具合に、強くもなく弱くもなく、ダラダラと続けていた。微弱な運動量に対して食事量はむしろ増え気味だったので、体重が順調に増え続けていたのは当然ともいえる。10月までは毎月体重と体脂肪率を機械で測定していたが、なかなか図にせずに特に記録もまとめていなかったせいで体重の増加傾向にも気づけなかった。いや気付いていたのだけど、精神的にも少し弱っていたので遅れたのだった。

これではいかんと決心し師匠に相談しながら、自分の方針と計画を固めていった。大前提としては

  • カロリー収支を必ず赤字にすること(アンダーカロリーをキープする)
  • インシュリン濃度を制するものが減量を制する
  • 目的のない脂肪の摂取は厳禁
  • 減量中は筋肉は増えないので、減らさないためにトレーニングをする(あと、トレーニングで一日の消費カロリーを稼ぐ、代謝量を維持することも目的)
  • 腹の減らない減量なんてウソ

などがある。その上で、個人の体質なり性格に合わせて具体的な手段を詰めて計画を立てるわけだが、

  • カーボはなるべくトレーニング後に摂るようにする。これは、トレーニング後の筋グリコーゲンを消費した状態であればインシュリンが分泌されても筋肉に入りやすい(≒相対的に脂肪細胞に入りにくい)ため
  • 付き合いなどで酒を飲む場合はなるべく昼間にトレーニングをしておく。食事で摂取した余剰な炭水化物をなるべく筋肉にいかせるのが目的だが、アセトアルデヒドを分解して得られる酢酸のうち、肝臓で分解しきれないものは筋肉にまわってしまうせいだ。個人的な感覚であるが、酢酸を筋肉で分解するときに筋肉も一緒に分解してしまうためだ。
  • 痛飲してはいけない。前述の理由と同じだが、トレーニングしてもカバーしきれないレベルになるし、二日酔いになるとそれだけ減量が遅れる。
  • アンダーカロリーをキープできない日があってもよいが、それは純粋に計画の遅れになって返ってくるだけだ。減量期間が予定よりも延びてしまい、継続性やモチベーションに問題がでるだろう。
  • チートデイは特に役に立たない。アンダーカロリーを計画通りにキープしていれば身体が勝手に代謝量を下げることはない。
  • アンダーカロリー状態になっているとき、特にトレーニング直後は抵抗力が大きく下がるのでMVMなどをきちんと摂取して(増やしはしない)風邪などの病気を防ぐ。風邪を引くとトレーニングにも減量にも悪影響がでる。
  • ケトジェニックはやらない。個人的な体質だと思うが、血糖値が低下した状態でも脂肪からエネルギーが代謝されにくいようだし、頭がぼーっとして身体全体がだるくなって行動不能になるので、日中はある程度血糖値を維持することを心がける。

といったあたりを基本方針にして、計画を立てる。

食事

人間の脂肪細胞はおよそ 7000kcal / kg なので、体脂肪を 1kg 減らすためには、たとえば 100kcal のアンダーカロリー生活を70日続ければよさそうだ。200kcalなら35日だ。実際にはアンダーカロリー分が100%脂肪から供出されるわけではないが、まあそれを仮定して計算を進める。例えば、一日で可能なアンダーカロリーを200kcal、除脂肪体重60kgとすると基礎代謝量がせいぜい1600kcalになる。通勤など日常生活でのカロリー消費が400kcalと見積もるとざっくり2000kcalくらいになる。200kcalのアンダーカロリーを達成するためには1800kcalを摂取することにして、さらにマージンを400kcalほどに設定する(マージンについてはあとで説明する)と、1400kcalが一日で食事から計画的に摂取するカロリーになる。そのうち25%を脂肪から摂取するとして、350kcal / 9.0 = 38.9 g (純粋な脂肪は 9kcal/g)程度の脂肪分を一日を摂取する。これは思ったより少なくて、たとえば鶏肉についている皮とか、ハンバーグに入っている肉汁に含まれる脂肪とかですぐにいってしまう。

また、炭水化物は目安があって、これは体重の 1 / 500 程度にすると血糖値を維持できる(本当は除脂肪体重で計算しなければならない)。75kg であれば150gだ(白米や小麦なら調理前の重さでよい)。一日3食であれば50gずつ、2食であれば75gずつだ。これで600kcalくらいになる。特に好き嫌いがないのであれば全粒粉パンかオートミール、もしくは蕎麦がよいだろう。うどんやパン、白米はGI値が高い(アミロペクチンが多い)ので積極的に選ぶことはない。なるべくアミロース系でGI値が低いもので摂取カロリーを満たしていきたいところだ。

最後に蛋白質であるが、この時点で残り 450kcal 程度になる。これは 450kcal / 4.0 = 112.5g (純粋な蛋白質は 4kcal/g)程度である。この量の蛋白質をとるのは案外難しくて、Mサイズの卵ひとつが蛋白質7.5g(ただし黄身の脂肪分に注意)だし、肉のなかで最も効率のよい鶏ささみであれば 489g (87.5 * 43 / 9.89 ≒ 489 参考)ほどになる。肉に付随する余分な脂肪や、肉料理に付随する余分なカーボのリスクを考えると結局これはプロテインで摂取するのがよくて、たとえば 1杯に 27g 蛋白質が含まれるようなものであれば 3杯、朝昼晩1杯ずつ+食事中の蛋白質30gくらいでほぼ用が済む。30gくらいであれば、全卵と肉100g程度で十分にとれるもちろん料理に入っている肉からより多くの蛋白質を摂れるとよいが、自炊でもしない限りきちんとコントロールされた状態で天然の蛋白質を摂取するのは難しい。つまり外食は全くもってダメだし、付属してくる脂肪を避けられないのだからプロテインの粉だけ一日4杯の方が全然よいということだ。ちなみに、我が家ではGold Standardのダブルリッチチョコレート味を定番にしている。下記はミルクチョコレート味だが、 https://1protein.com/ に行けば全ての味のものが手に入る。

【国内正規品】Gold Standard 100% ホエイ エクストリーム ミルクチョコレート 2.27kg (5lb)

【国内正規品】Gold Standard 100% ホエイ エクストリーム ミルクチョコレート 2.27kg (5lb)

簡単にまとめると

  • 脂肪で +350kcal ~ 39g
  • 炭水化物で +600kcal ~ 150g
  • 蛋白質で +450kcal ~ 112.5g
  • マージンで +400kcal
  • 代謝などで - 2000kcal
  • 毎日の赤字: -200kcal

という具合にカロリー収支を制御する。

マージンは、これは食事に混入する、避けられないかつ防御不可能な炭水化物や脂肪分だ。醤油、ソース、ラー油、味噌など、調味料に含まれるカロリーや、肉に付属する脂肪、タレに含まれる糖分からも防御しなければならない。我々は水を飲んで空気を吸っていても太るような人種なのだから。

サプリメントは、これも特に日常のものと変えることはしない。基本的にはMVM(エランバイタル、OPTI-MEN)とメラトニンだ。メラトニンは睡眠導入と、抵抗力強化の効果があり副作用がないので飲まない理由がない。他にもBCAAを必要に応じて、グルタミンとクレアチンを一日に適量ずつ。

また、トレーニング中はグリコのCCDとBCAAの混ぜものを自分で水に溶かして持ち込んでいる。これをトレーニング中に飲むと血糖値の低下を避けられるので集中力を維持することができる。ただしコツがあって、トレーニング開始前に飲み始めてしまうとインシュリンが分泌されて脂肪細胞にまわってしまう可能性がるので、トレーニング開始前後は給水器かなにかの水だけにしておいて、開始10〜20分くらいしてから飲み始めるのがよい。これはいつも600~700ccほど作ってもっていく。 1000ccで340kcalなので700ccだと238kcal程度だ。トレーニング直後ということでまあ少し甘めにみる。間違っても自販機でスポーツ飲料を買って飲んだりなどしないように。あれはただの砂糖水だ。インシュリンが出すぎてしまう。

コンディショニング

昨年はあれだけ自慢したが、春頃からほとんど家やっていない。次男が邪魔するというのが大きいが、日常的に肩甲骨を動かし続けたりストレッチすることを意識できるようになってきたので、背中や肩が激しく凝ることが減った。それでも少し凝ることがあったら妻に頼んで揉んでもらうことにしている(私も妻のバキバキの背中を揉む)。しかし下半身は全くといっていいほど何もできていないのでお粗末である。これは要改善の課題。

トレーニング

パワーアップではなく代謝とパワー維持が目的になる。アンダーカロリーの状態だと基本的にパワーが出ないので、あまり重いウェイトは狙わずに、正しいフォームで狙ったところにきちんと入れるようにする。時間があればマシンを使ってアイソレーション系の種目を中心にすると怪我のリスクが少ない。時間がない場合は種目を絞って、落としたくない部分をいくつかやりつつ、複数の協働筋が巻き込まれる種目をやっていこう。大きい筋肉を狙うならベンチプレス、デッドリフト、バーベルスクワットがよいだろうが、いずれも正しいフォームで行うのが難しいので減量前にフォームをある程度固めて慣れておくのがよいだろう。少しパワーをつけてからの方が神経系に余裕を持って対応できるかも。ただし怪我のリスクが多少なりともあるので、慣れていないなら懸垂から始めるのがよいだろう。慣れている人なら懸垂の良さを分かっているだろうから解説は不要だろう。懸垂がいくつかある種目の中でも最も怪我のリスクが低く身体への負担も少ない、それでいて最も効率のよい種目の一つでもある。順手、逆手、ワイド、片手など様々なフォームがある。全くあがらない状態でも、毎日ぶら下がっていれば誰でも上がるようになるのがまた懸垂の素晴らしいところだ。できれば職場にチンニングスタンドを持ち込んで仕事中に1時間毎に懸垂をするのがよい。

有酸素運動は基本的にはやっていない。私自身があまり好きでも得意でもないということが一番大きな理由だが、140bbmを維持するほどのマシンがジムにないこと、退屈なことも理由にある。また時間をかけた割に100~150kcal程度しか効かないので、食事を減らした方が楽なのではと思う。まあとにかくトレーニングに関しての情報収集はアイアンマンの鈴木雅の連載を読めばよい。

IRONMAN(アイアンマン) (2017年12月号)

IRONMAN(アイアンマン) (2017年12月号)

IRONMAN(アイアンマン) (2017年11月号)

IRONMAN(アイアンマン) (2017年11月号)

私の工夫としては、減量してパワーが下がったので一回あたりの種目を絞って、トレーニング時間を短縮しつつ回数を増やすというアプローチだ。上半身・下半身で分けている。減量も進んだ頃の私のメニューはざっくり以下のローテーションだ。

11/8
Bench press 50kg->65kg Δ5kg x5 60kg 5x3
Partial deadlift 65kg 5 85kg 5 95kg 5 85kg 5x2
ISO-lateral incline press 30kg 10 50kg 8 6
ISO-lateral row 40kg 15 60kg 11
Torso rotation l/r 32kg 15 50kg 15x3

11/3
Barbell squat 40kg 10 60kg 8 70kg 8
Adduction 100lbs 20 200lbs 15x3 12
Abduction 100lbs 15 200lbs 15 13 12 13
Prone Leg curl 50lbs 12 70lbs 12 12 11 10
Leg extension l/r 55lbs 10 70lbs 10x2
85lbs 7 8
Seated calf raise 30kg 15 60kg 15 13 40kg 15x2
Leg press 260lbs 15 300lbs 15 320lbs 15 340lbs 15

今は、ここからAdductionとAbductionは削ってしまった。レッグプレスも体調次第ではスキップする。このローテーションを1〜2週で一周りすることを目指している。…目指している…というのは、こういうことだ。

環境の変化

10月一杯はニートをしていて、11月から転職をした。つまり10月はトレーニングや減量に精力を注げたが、11月からは新しい環境でみそっかすに逆戻りしたのでトレーニングだけに集中できる環境ではなくなってしまった。食事を完全制御できる自宅から職場へ、週5回食事が移ってしまった。幸い新しい職場は食事に選択肢があり、内容をコントロールできる店もあるので悪くはない。また、午後は仕事に没頭できる状況なので余計な間食を基本的に防げる。ただ食事間隔が長くなりすぎてしまうのもよくないので、帰りが遅くなりそうなときは軽く煎餅的なものを入れるようにしている。またオフィスにプロテインのボトルを持ち込んで一日に1〜2回(30g)飲むようにしている。

中間結果(進捗)

わたしは6kg減らすのが目的なので200kcalで35日/kg、ざっくり一ヶ月で1kgを目標にした。つまり半年の計画で、9月に開始して3月末に70kgを下回る計画だ。その計画と今日まで実績が冒頭のグラフになる。赤い点が月初めの目標値で、青い点が毎日の実測値になる。毎日というわけではないが基本的には赤い点を下回っており、今のところ計画した通りの値が出ている。外見の進歩に対する妻の評価も上々だ。しかしながら想定外のこともいくつかあって、

  • 11月に環境が代わり、ジムへ行く頻度が下がった
  • 睡眠時間が安定しなくなった
  • 季節の変わり目に微妙な風邪を引きかけて(家族も風邪をひき)、大事のためジムへ行けなかった
  • 体調を維持して風邪に対抗するために食事をオーバーカロリーにした時期があった

などである。特に風邪っぽい状態はかなり厳しくて、万全の睡眠と体温維持ができていなかったことが悔やまれる。今後のリスクは忘年会シーズン、寝正月や真冬の低気温などがあり予断を許さない状況である。

減量時やってはいけない目安

  • 痛飲
  • 週2日以上のオーバーカロリー
  • 週4回以上の外食(コントロールされていない食事)
  • チートデイ(かなりストリクトにしていないと意味がないし、していても意味があるかどうか分からない)

その他

近況

  • 仕事がだるかったので転職した。だるかった時期と体重が増加した時期がわりと一致していたことにさっき気付いて、身体は正直だなと思った。
  • 転職してついにPythonを書くのが本職になった。Python型がなくて難しい。これではPyspaらしからぬ有様だ。
  • ChainerMNとかPythonの話はまた別の記事で書くかもしれない。
  • 子供が小学校に入ってますます成長。Scratchを書くようになった。次はPythonに興味を持った(すぐに飽きた)。
  • 春アニメは有頂天家族2,夏はゲーマーズ!がよかった。
  • 夏アニメはJust Because, 魔法使いの嫁、妹さえいればいい。がどれも面白くて割とよい。
  • 本年3月に祖母が逝去したので新年のご挨拶は遠慮いたします。

2年半経ってようやく初めてHDDが故障したサーバーの話

今更ストレージサーバーをFreeBSDとZFSで組んだ話 - kuenishi's blogで作ったサーバーがチマチマとアップデートを繰り返しつつ FreeBSD 11.1 までアップデートされていた。

%> freebsd-version 
11.1-RELEASE-p3
(v)kuenishi@kushana:~
%> uname -a
FreeBSD kushana 11.1-RELEASE-p1 FreeBSD 11.1-RELEASE-p1 #0: Wed Aug  9 11:55:48 UTC 2017     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64

2年半何事もなく普通に動いていて、「HDDそろそろ壊れないと障害対応の方法忘れてしまいそう」などと思っていた…ところ、ようやく来た。今日ひさしぶりにアクセスしようとしたら(Macにマウントしようとしたら)返事しなくなっていた。とりあえず "zpool status" と打ち込むもものすごく返事が遅い。なので "/var/log/messages" をみると ata1 がおかしそうなので、もうちょっと調査する。

%> sudo smartctl -a /dev/ada1

これをやると「なんかオカシイ」みたいな文字が出る(保存してなかったのでなくなりました)。一方壊れてなさそうなディスクでやってみると

%> sudo smartctl -a /dev/ada2 | grep "No Errors"
No Errors Logged

となるので、どうもやっぱりディスクがおかしいということが確定する。ちなみに smartctl のコマンドは "pkg install smartmontools" でインストールできる。

仕方ないので物理的に交換する。実はこれはメインのデータ用ディスクじゃなくて控えのディスクをそのままSATAに挿して遊び場に使っていたディスクだったので、重要なデータに特に問題は起きていない。とりあえず挿してからZFSプールを作るところまでサクッとやっちゃう。gpart create のオプションはいろいろあるのだが、まあ賢いと信じて任せる。

%> sudo gpart show ada1
Password:
gpart: No such geom: ada1.
%> sudo gpart create -s GPT ada1
ada1 created
%> sudo gpart show ada1
=>        40  5860533088  ada1  GPT  (2.7T)
          40  5860533088        - free -  (2.7T)

%> sudo gpart add -t freebsd-zfs ada1
ada1p1 added
%> sudo zpool create attic ada1
%> zpool status attic                           
  pool: attic
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        attic       ONLINE       0     0     0
          ada1p1    ONLINE       0     0     0

errors: No known data errors

とまあサクッとできたので、いちおうデータ用のZFSプール (data/user) のスナップショットを注入しておく。

% sudo zfs snapshot data/user@snapshot20171120
# zfs send data/user@snapshot20171120 | zfs recv -F attic     

これでシコシコとスナップショットを送り始めるので、まあ一通りの作業は終了。そういえば何となく心配になってきたのでscrubも回しておくことにする。

% sudo zpool scrub data

なお特にオチはない。

日本が機械学習パラダイスなのは情報大航海プロジェクトのおかげ

人工知能じゃ〜これからはシンギュラリティじゃ〜と盛り上がっており、猫も杓子も深層学習で人工知能で人類皆失業などと楽しいお祭り、ぼくは嫌いじゃない。我々が生きていくためには金が必要なんだ。というわけで、ちょっと気になって調べたことがあったのでここに記録しておく。もしこれが知財や法曹方面の業界で有名な話だったらコンピュータエンジニアたち何やってんのという話ではある。


もともとこれが気になっていた。ので調べました。という話。


著作権法

とりあえず原文を引用しておこう。

第四十七条の七 著作物は、電子計算機による情報解析(多数の著作物その他の大量の情報から、当該情報を構成する言語、音、影像その他の要素に係る情報を抽出し、比較、分類その他の統計的な解析を行うことをいう。以下この条において同じ。)を行うことを目的とする場合には、必要と認められる限度において、記録媒体への記録又は翻案(これにより創作した二次的著作物の記録を含む。)を行うことができる。ただし、情報解析を行う者の用に供するために作成されたデータベースの著作物については、この限りでない。
(電子計算機における著作物の利用に伴う複製)

これを解釈すると日本は機械学習パラダイスだというわけだ。まあ確かにそうとしか読み取れないわけだが、本来の目的とか設立趣旨を知っておかないとあとの法解釈で死ぬだろう。というわけでヒマだしネットサーフィンをしたわけだ。この47条の7は平成21年の著作権法改正で追加された条文で、解説文書も文化庁のページからPDFながら公開されている。この解説文に

今回の著作権法改正は,議員立法や他法制定に伴う整備を除けば,平成 18 年(中略)以来の改正となるものである。改正事項は多岐に渡るため,個
別の改正事項ごとの経緯を述べるには紙幅に余裕がないが[1],全体の経緯は次のとおりである。

とあり、注釈に「 個別の改正事項ごとの検討経緯については,平成 21 年1月の著作権分科会報告書を参照されたい」とある。なので、この著作権分科会報告書を参照する。 これを見つけるのにいろいろ検索クエリを工夫した結果、文化審議会著作権分科会(第27回)議事録・配布資料を見つけることができた。で、これをみても著作権法47の7に直接関係しそうなところがない。が、つらつら見ていると次回の文化審議会著作権分科会(第28回)議事録・配布資料に、それらしきものがある。 「著作権法に関する今後の検討課題」(平成17年1月24日・著作権分科会決定)の概要とそれ以降のこれまでの審議状況というやつがそれで、これをみると4ページに

  • 概要: 画像・音声・言語・ウェブ解析技術等の研究開発における情報利用の円滑化のための法的課題の検討(知財計画2008)
  • これまでの審議状況等: 平成21年法改正案提出中(第47条の7の新設)

と書かれている(表の引用が面倒なので適当に書式を変更した)。これだ!!

というわけで、経緯が書かれているという資料1-2の文化審議会著作権分科会報告書(案)に戻ると、の第1編第3章第6節「研究開発における情報利用の円滑化について」が該当する。検討の背景の序文を引用しよう。

政府の知的財産戦略本部では、高度情報化社会の下、インターネット上の膨大な情報等から情報・知識を抽出すること等によりイノベーションの創出が促進されるとの観点に立ち、情報アクセスなどネットワーク化のメリットを最大限に活用できるような環境整備の必要性が認識されている。そして、本年6月に同本部で決定された「知的財産推進計画2008」においては、まず、それらの情報処理のための基盤的技術となる画像・音声・言語・ウェブ解析技術等の研究開発に関して、この研究開発の過程で行われる情報の利用について著作権法上の課題があることを指摘し、早急に対応すべき旨が盛り込まれたところである。

つまり知財戦略本部=政府からのお達しでイノベーションを促進するために著作権法をなんとかせいと言われているわけである。知的財産計画2008はまだ読んでないけど、それっぽい目次があるようだ。P26に

ネット等を活用して膨大な情報を収集・解析することにより高度情報化社会の基盤的技術となる画像・音声・言語・ウェブ解析技術等の研究開発が促進されること等を踏まえ、これらの科学技術によるイノベーションの創出に関連する研究開発については、権利者の利益を不当に害さない場合において、必要な範囲での著作物の複製や翻案等を行うことができるよう2008年度中に法的措置を講ずる。

情報大航海プロジェクト

こんどは情報大航海プロジェクトについて見てみよう。検索したら平成19年の「情報大航海プロジェクト」についてという資料がみつかった。平成19年は2007年だ。まあパワーポイントなのでポンチ絵なのだが、P3には「制度・環境」と題して「プライバシー、著作権を始めとする制度的課題について、法改正やルール整備等の所要の手当てを処置」と書かれている ((ちなみにP4には将来のIT化社会の未来像みたいなのが語られているが、なんだか昔も今も似たようなことやっとるんだなあと感慨に浸ることができる名文である)。さらに、2008年のJapioの雑誌?機関紙?には「情報大航海プロジェクト2年度目を迎えて」という文章が寄稿されている。これを見ると

今後web情報における現在の検索エンジンにとどまらず新サービスが開拓される実情について、文化庁・経産省で大航海プロジェクトにも参加するベンチャー企業への共同ヒアリングを実施、文化庁へのパブコメにも意見を提出、著作権審議会法制小委員会にて著作権法改正の方針が固まったことは、こうした利用が可能となっている諸外国並に日本の法的環境が進捗するだけではなく、さらにどのような環境を整備していくのかに内外関心を集めることになるであろう。

と書かれており、情報大航海プロジェクトの関係者が文化庁に働きかけたことがわかる。だってここをクリアしないと検索エンジンも作れないもんね。当時某プロジェクトで微妙に検索エンジン経由でそういう噂も聞いていたので、まあそうなるわなー。当時は役人仕事しろって思うけど、今思うとお役所頑張ったな!と感慨深いものがある。

改正著作権法の解説から合わせて考えると、まず検索エンジンがクローリングして集めたWebサイトや文章、音声、動画などのデータを検索エンジン事業者がそのまま国内で保存していたら著作権法上の複製にあたりそうだから、ちょっと法律関係をちゃんと整備しないといけなくなった…おそらく2006とか2007年の情報大航海プロジェクトの企画時にはわかっていたことだと思う。当時すでに国産の検索エンジンは何社もあったわけだし(当時の事業者は基本的にクロールしたデータはインデックス作成後すぐに消していたようなので、心配はしていたがそんなに問題にはなっていなかった?)。ところがグーグルが登場して技術の流れが変わって法整備ちゃんとしようということになったので、政府にプロジェクト関係者が働きかけて法改正に持っていったものと推測できるわけだ。

改正著作権法の解説

情報大航海プロジェクトと改正著作権法の関連を示すものとしては、改正著作権法の解説というページからリンクされている解説が非常にわかりやすい。公式見解ではないと前置きしつつも、どう考えても全員関係者です、という非常に味わい深い資料なのであるが、6-20をみると面白い。

法47条の7により認められる複製等によって情報解析を行い、その結果を他人に提供するサービスを実施したいと考えているが、どのようなサービスであれば問題ないか。

という問題だ。深層学習関係に敷衍すると、GANによる自動生成なんかが主に関係するだろう。ここでは、『ネガティブ4割、ポジティブ6割」は、上記の「情報解析結果のデータ」に』と書かれているように、別の記号やキーワードなどに抽出された統計情報ならOKとしか書かれていない。そして、49条で「第47条の7に定める目的以外の目的のために、同条の規定の適用を受けて作成された二次的著作物の複製物を用いて当該二次的著作物を利用した者」は、「当該二次的著作物の原著作物につき第27条の翻訳、編曲、変形又は翻案を行つたものとみなす」と書かれている。GANによる生成は統計情報の抽出なり利用を人間は全くやってないので、はてこれは新たなグレーゾーンなのでは…と心配できたりするわけである。

もちろんほとんどのケースでは元のデータが分からないくらい多くミックスされているわけで、人間の全ての創作活動が既存の作品の模倣とアレンジ、組み合わせであると主張する立場からはコンピュータと人間がやるのでは大差ないという話になるかもしれない。あるいは、創作側が「人間に見せるのはOKだがコンピュータに見せるのはNGだ」と言ってしまえば話はそれで終わるかもしれない。

まあそもそも件の記事の上野達弘氏は経歴をみるに文化審議会著作権分科会の小委員会を何度も歴任しているし、知財戦略本部にもおられたようなのでどうみても関係者(か、限りなく現場に近い)だったのであろう。知ってる人は知ってる話というだけの話だ。

まとめ

  • 著作権法47の7は2008年の政府の知財戦略の成果のひとつであり、たまたまそこにあったわけじゃない
  • 改正に関する経緯を追っていくと情報大航海プロジェクトの働きかけがあったことが分かる
  • あれくらい大きなプロジェクトであれば法改正もできるということだ!!感謝しよう!!敬え!!
  • とはいえ深層学習を応用した生成系のタスクについては著作権的に悩ましいところもまだありそう


参考

  • 高田寛, 情報大航海プロジェクトと検索エンジンの法的問題についての-考察, 比較法制研究(国士舘大学)第31号(2008)129-168

消すだけなのに rm -rf がいっつも長くて待ちきれない問題

今時のファイルシステムはみんなジャーナルもってて何かあったときにそこからリカバリする仕組みになってるので、当たり前といえばそうなんだけども。

(TODO: ここにファイルシステムのツリー+ジャーナルのポンチ絵を手描きでも何でも描く)

ご本尊のデータのツリーと何らかのWALを1セットで持っておくのはRDBだろうがファイルシステムだろうがそうは変わらない、で、削除についても並行制御をうまくやるために削除フラグをログに入れておいてあとで本尊のデータを整理するというのが基本的な設計になる。そこで私は立ち上がった(TL;DR: 特にオチとかはないです)。

で色々調べてみた結果、結論は既存のファイルシステムはよくできているということだった。何かしら高速化を期待された場合はちょっと次回以降をお待ちいただきたい(調べることが多すぎて飽きたともいう)。

ベースライン測定とか

まず1バイトのコンテンツを持ったファイルを大量に作る。

深さ4幅32なので 32^4 = 1048638 個のファイルが33284のディレクトリの下にできたことになる。論理値でいえば1MBほどだが、ディレクトリやファイルなどのオーバーヘッドの方が大きいだろう。それでもRAMが32GBあるマシンで実験したのでファイル実体のディスクアクセスは全てディスクキャッシュに乗る。おそらくWALの書き込みが支配的になるだろう。で、このファイルとディレクトリを消す方法はざっくりインターネットを調べると簡単なものは3つくらいみつかる。それに一つ我流を追加。

  1. rm(1) を使う方法: "rm -rf " とやるだけ。実はこれがかなりよくできていて速い。
  2. xargs(1) と rm(1) を使って並列化する方法: "ls | xargs -n 1 -P 8 rm -rf" などとやるだけ。rm(1)が速くできている上に並列化されて実時間はかなり速くなる。ただしコンテキストスイッチはまあまあ増える。
  3. find(1) を使う方法: "find -delete" とやるだけ。これで 以下が全部消される。いまのところこれが rm(1) よりも速いといわれている。
  4. C++17のstd::experimental::filesystem::remove_allを使う方法

この4つを /usr/bin/time で測ってみる。スペックは家のデスクトップDebianの /dev/sdc1 上に作ったXFSディレクトリである。このためだけに作ってあった。user, sys は秒、realは時:分である。

user sys real voluntary cs CPU
rm -rf 0.37 20.42 1:58 5327 17%
xargs 1.05 42.80 0:28 1151757 155%
find 0.52 20.82 1:23 942 25%
prm 4.59 46.35 1:24 1251687 60%

想定の通り最も短時間で前処理が終わるのは xargs(1) を使った方法だった。しかしシングルスレッドで最速だと思われた rm(1) よりも find(1) が速いのは意外だった。そこで strace(1) の結果を比較してみる。 これは、さきほどの実験コマンドで /usr/bin/time の代わりに "strace -c -f" とつけてやるだけである。まず rm -rf の結果がこちら

$ strace -c rm -rf tree
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99.04    0.193423           0   1082401           unlinkat
  0.31    0.000614           0    101475           getdents
  0.25    0.000488           0    304425           fcntl
  0.18    0.000351           0     67650           openat
  0.10    0.000189           0    101481           close
  0.07    0.000133           0     67653           fstat
  0.05    0.000099           0     33825           newfstatat
...

で、find(1) の結果がこちら。

$ strace -f -c  find tree -delete
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99.10    0.190004           0   1082401           unlinkat
  0.24    0.000469           0     67650           getdents
  0.23    0.000436           0    304426           fcntl
  0.13    0.000258           0     33825           openat
  0.13    0.000241           0     67650           newfstatat
  0.12    0.000235           0    135311           close
  0.04    0.000086           0     33834           fstat
...

xargs(1) の結果は rm -rf のものとそう変わらなくて(xargsのwait4(2) が必然的に待ち合わせなのでほとんどの時間を占めている)、30分違ったのはどうしてかなあというところではある。また、99%の時間を使っているはずの unlinkat(2) のシステムコールですら 0.19秒で、wallclock time には全く追いつかない。strace(1) のマニュアルを見ると"On Linux, this attempts to show system time (CPU time spent running in the kernel) independent of wall clock time." と書かれていて、system time が出てもよさそうなもんであるが…という謎に当たる。 xargs(1) で並列化した rm が速くて自作で並列化した prm.cc がどうして遅いのかは

$ strace -f -c /home/kuenishi/path/to/prm tree
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 85.01   57.128000     2197231        26         6 futex
 10.46    7.032312           6   1082401     33825 unlink
  2.21    1.484577          22     67652           getdents
  1.90    1.278376           1   2164802           lstat
  0.33    0.219737           6     33825           rmdir
  0.03    0.019788           1     33832           open
  0.03    0.017729           1     33832           close
  0.02    0.016686           0     33833           fstat
...

としてみればわかるように、 unlink(2) がちょうどディレクトリの個数だけ失敗していて、さらに lstat(2) も大量に呼ばれていることから、ああこの辺だなあとすぐに想像がつく。余談なので深くは追わないが、実際に GCC のSTL実装では簡単にポータブルに作ることを意識していて性能とかそういうことは微塵もなさそう。

このベースライン測定で分かるのは以下

  1. シングルスレッドで動くものだとざっくり1.5 ~ 2時間、マルチスレッドで速く動くものなら30分くらいかかる
  2. システムコールの使い方が下手だとそもそも並列化の恩恵つきでも赤字
  3. どうやら unlinkat(2) をちゃんと使うと速いらしい
  4. userとsysを全部足してもwallclockに追いつかないので、どこで時間が溶けているのか分からない

プロファイル(on CPU)

さてここからが本番である。strace(1)をしても何で時間が溶けているのかよくわからない。こりゃ、削除を速くするとかそれ以前に謎が多いゾ…?という話である。CPUインテンシブなジョブではないので、ふつうのプロファイリングをしてもダメだろうなあというのが容易に想像できる。そこで我らがperf(1)先生の登場だ。perf先生のすごいところは動作中のプロセスもアタッチして覗けるところなのだが、バッチプログラム相手だともっと簡単に起動できる。

実際の測定は簡単で、

$ sudo perf record -F 99 -a -g -- rm -rf tree
$ sudo perf script > out.perf

などとすれば、秒間99のレートでプロセスのスタックをすっぱ抜いてチェックできる。それをこうして…

$ ./stackcollapse-perf.pl out.perf > out.folded
$ ./flamegraph.pl out.folded > out-rm-single.svg
$ firefox out-rm-single.svg

こうじゃ!

f:id:kuenishi:20171006182347p:plain

"rm -rf tree" の代わりに "ls | xargs -P 8 rm -rf" でやったやつもあるよ!

f:id:kuenishi:20171006182505p:plain

どちらの図もほとんどの時間を unlinkat(2) が使っていることが分かる。これは strace の結果とも矛盾しない。で、そのなかでも "vfs_unlink" と "xfs_fs_destroy_inode" がものすごく時間を使っていることがわかる。ちょっとだけLinuxのコードを読んだのだけど、中で沢山ロックをとって、スピンロックも沢山あって、それから inode エントリを書き換えたりして、それをジャーナルに流している?っぽい処理が沢山ある。それから kthread の方で "xlog_iodone" がCPUを使っていることもわかる。しかしながら CPU使用率が 17% しかない( perf は実行中のプロセスに対してしかスタックをぶち抜かない)ので、これでは全体の実行時間の 17% くらいしか説明できない。

プロファイル (off CPU)

で、IO待ちのプロセスのスタックを抜くにはperfでは不足で、Linuxの eBPF というのを使う。iovisorという便利なツールキットがあるので、そいつをさくっと入れる。

# echo "deb [trusted=yes] https://repo.iovisor.org/apt/xenial xenial-nightly main" >> /etc/apt/sources.list.d/iovisor.list
# apt update
# apt install bcc-tools

これは特定にCPUを見てくれるとかはしなくて、OS内のプロセスで特定の状態にいるやつを拾ってくる。状態一覧はカーネルのヘッダをみると

$ grep TASK_ /usr/src/linux-headers-4.9.0-3-common/include/linux/sched.h  | grep define
#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
#define __TASK_STOPPED          4
#define __TASK_TRACED           8
#define TASK_DEAD               64
#define TASK_WAKEKILL           128
#define TASK_WAKING             256
#define TASK_PARKED             512
#define TASK_NOLOAD             1024
#define TASK_NEW                2048
#define TASK_STATE_MAX          4096

などとなっているので、IO待ちの TASK_INTERRUPTIBLE をみるために

$ /usr/share/bcc/tools/offcputime -f 20 --state 2 > out.offcpustack

と仕掛けておく。別のコンソールで素早く

$ time ./coreutils-8.26/src/rm -rf tree

として、コマンドが返ってきたら offcputime もさくっととめる。こいつをグラフにするには

$ ./flamegraph.pl --color=io < out.offcpustack > offcpu-2a.svg

などとすると、こんな感じで

f:id:kuenishi:20171006184650p:plain

TASK_INTERRUPTIBLE状態のプロセスのスタックを秒間20で覗いたときの集計結果を見ることができる。でもカーネル分からないのでウ~ン…となっちゃうけど、やっぱり "xlog_write" という名前からしてXFSのジャーナル書くところで時間を食っているように見えなくもない(心眼)。これは負荷がないときと比較しないといけないんだろうなーと思ったけど、なぜか僕のメモはここで途絶えている。カーネルスレッドって誰が起動してるんだろね…

結論

  • perfやiovisorを使ってon-CPUとoff-CPUのFlameGraphを描いてみた
  • XFSやrm(1)はよくできている
  • それはそれとして unlinkat(2) のシステムコールに縛られたファイルシステムはインターフェースからして改善の余地があるのではないか

想像するに、rm で消しに行ったけどシステムコールから返ってくるには何らかの待ち(おそらくはXFSのジャーナルにwrite)をしないといけないのだけど、それは非同期でやっているので on-CPU のグラフには出てこないし、 off-CPU のグラフのどこに出てくるかをちゃんと調べないとよくわからない。Kernel tracing は難しい。第二部に続く(かもしれない)。

UNIX Filesystems: Evolution, Design, and Implementation (Veritas)

UNIX Filesystems: Evolution, Design, and Implementation (Veritas)

おまけ: 環境構築

manpagesを入れる

$ sudo apt install man-db

perfなどのツールを入れる

$ sudo apt-get install linux-perf strace build-essential perf-tools-unstable
$ sudo perf test

これで(ほとんど)全ての項目がOkになるようにしておくこと。

デバッグシンボルつきの rm(1) を作る

$ apt-get source coreutils
$ cd coreutils-x.yy
$ CFLAGS="-g3" ./configure
$ make -j8
$ src/rm -h

書評: ビッグデータを支える技術

Googleを支える技術 ?巨大システムの内側の世界 (WEB+DB PRESSプラスシリーズ)で著名な西田さんの著書である。とても先見性のある本で、当時は仕事でもあったからとてもお世話になった。その西田さんの新作だというし、最近はもういろいろビッグデータのソフトウェアとミドルウェアがありすぎてワケの分からないことになっていると思ったので、知識を整理するためにサクッと購入。

ビッグデータを支える技術―刻々とデータが脈打つ自動化の世界 (WEB+DB PRESS plus)

ビッグデータを支える技術―刻々とデータが脈打つ自動化の世界 (WEB+DB PRESS plus)

本書の冒頭でも触れられているが、昨今ではありとあらゆるソフトウェアがオープンソースで公開されているし、詳しい情報はほぼすべてインターネットで公開されているから、この本はカタログ的にさまざまな概念や製品を紹介していき、個別に深く解説することはしないと注意されている。まさにそれこそが本書の価値で、元エンジニアで昨今のビッグデータの潮流を知りたい課長、部長級の管理職や、現場でビッグデータを前に呆然としているエース級のフルスタックエンジニアが知識の補完を行う用途にピッタリである。次点で向いている用途としては、これからビッグデータの赤い荒波に乗り出していこうと考えているエンジニアや営業職にとっても、業界を俯瞰して全体図を把握するにはよい(当然コレだけではダメで、そこから自分の得意分野を深掘りしていかなければならないだろう)。ビッグデータのことが分からない、という人は必読の一冊だ。

私自身はこの業界にもう10年近くいることになるので、おおよその概観を脳内に持っているつもりだったが、思った以上にビジネスインテリジェンスとかETLとかバッチとかに多様な世界があって、いろいろあるらしいなあということをざっと確認できたのでよかった。以下は、自分の専門分野で気になったところの指摘をささやかながらしておこうと思う。ちょっと忌々しい指摘ではあるが、これで本書の価値が損なわれるわけではないのでお間違いのなきよう。

10/6追記: YARNとLXCに関して - 「ビッグデータを支える技術」補足 にて捕捉いただいた。この捕捉を読んでから、以下のコメントは割り引いて読んでいただきたい。

Apache Mesos について @ P119

119ページのカラムで「Mesosによるリソース管理」と題してApache Mesosの紹介をしているのだが、2017年の本にしては情報が古い。まず出だしの「MesosはOSレベルの仮想化技術を用いており、YARNと比べると…」という話からしてアレでして、YARNもMesosもリソース制限は基本的にcgroupを使っているわけなのでそんなに変わらない。Namespacesの利用があるかどうかは異なるかもしれないが、それはリソース制御ではなくIsolationなのでちょっと違う。また「Dockerと同じくLinuxコンテナ(LXC)が用いられ」というのは明らかに誤り。遅くても1.0の時点でサポートされているコンテナエンジンはDockerかMesos独自のエンジンであり、LXCは一年以上前から利用していない。DockerもLXCは既に利用しておらず、LinuxのNamespacesを利用している。

またその後の解説でMesosにData localityがなく、一方でYARNにはあるのでYARNの方が優れていると解説されている。確かにMapReduceなどのLocality機能と親和性が高い機能がYARNだとスムーズに動作するらしいが、Mesosの2 level scheduler という思想に基づけば入力データのHDFS上の位置をみつつLocality awareに作るのはフレームワーク側の仕事である。テクニカルには、多数のOfferを抱えておけばIPアドレスは分かるので、フレームワーク側でデータの位置と割り当てられたリソースをマッチングしてスケジュールすることが可能。むしろYARNみたいに中央集権的にスケジューリングするよりも、Mesos用にスケジューリングアルゴリズムを自律的に使い分ける方が便利なケースもあるだろうから、Data localityがあるから優れていると一方的に評するべきではない。それでも、On the flyですぐLocalityを考慮してジョブを動かせるのは便利だけど、それは計算フレームワーク側が対応してるかどうかの問題じゃないかと思う。もちろんYARNの方が対応してるソフトウェアは多いと思うが、それは個別のソフトウェアの話だろう。

分散システムという言葉について

また、本書の全体を通して「分散システム」という言葉が定義なしに使われていて、都度どのような故障モデルや通信モデルを備えているのか、合意の基準は何なのかが引っかかる。

特にP150では「TCPではメッセージにシーケンス番号を付けますが、分散システムではシーケンス番号はあまり使われません」と表記していて、続く文章で欠番のないシーケンス番号の発行は(いわゆる故障あり非同期通信モデルでは)現実的に難しいためと解説している。たしかにトランザクションIDやTCPのシーケンス番号、REDOログなど欠番があったときに途中のメッセージを待つ必要がある場合には、要件を満たすシーケンス番号を発行することが技術的に難しい(Twitter の Snowflake などはあったが、それだけでクラスタを一つ組まなければならない)ので「使われません」という表現になる。なる、が、非常にこれはミスリーディングで、我々がシステムで依存しているPaxos, Zab, Raft といった分散合意プロトコルは欠番を許容するシーケンス番号を順につけていって、プロトコルの正しさはその順序性に依存しているのである。Raftはシーケンス番号の欠番を許さないが、欠けたデータを復元する手順を持っている。

この言い回しが紛らわしいのは「分散システムでは」の主語が大きいことに由来しているので、もっと限定的に書くべきであった。そもそもこの文章はストリーム処理における "at least once" の解説に含まれている場面であって、冗送排除の文脈であって欠損メッセージの検出ではない。したがって同じメッセージには同じIDがついているだけで十分で、送信側が受信側からAckを確認するまで再送し続ければ at least once は達成できる。つまり欠損の検出が不要なわけで、シーケンス番号じゃなくてもいい…シーケンス番号はよく使うんだよ…という主張だ。「あまり使いません」というミスリードは不要だったのではないかという話。

最近のBashoのニュースの「買収」という言葉はちょっと違う(追記あり)

PublickeyというIT界隈でわりと影響力のあるサイトで分散型NoSQLデータベースの「Basho」をギャンブルサイトの「Bet365」が買収。全製品のオープンソース化を表明という記事が公開された。しかしながらこの記事は若干の誤りを含みつつミスリードが多かったのでここで指摘していきたいと思う(この記事の公開後に修正あり)。今北産業の方々は末尾のまとめをご覧いただきたい。

www.publickey1.jp

なお私は 2016年3月までBashoの日本法人の被雇用者であり機密情報を一部知る立場であったが、ここでは公開情報だけをもとに解説する。また現在は一連の関係者との公的な関係は一切なく利害関係にないことを明記しておく。つまり外野で野次馬です。

基本的な指摘事項

Bet365を表現するのに「ギャンブルサイト」という言葉は一般的ではない、きちんとした会社である(対応済み)

はてブでブックメーカーをギャンブルサイトといえば確かにそうだけど。というコメントがついている通り、Bet365は伝統的なブックメーカーのオンライン版であると表現するのが正しい。「アメリカの大統領選挙やゲームの大会、アカデミー賞の授賞者や次のジェームズ・ボンドを演じる役者等もブッキングの対象になる」とあるように、イギリスではプレミアリーグから何から何までギャンブルの対象にすることが法律で認められている。飲み屋でよくある「アイツが明日遅刻するのに10ポンド賭けてもいいぜ」みたいなのが大っぴらにできるというわけだ。日本では賭博行為は一部の公営のものだけが認められており、その他の賭博は全て違法である。日本語で「ギャンブル」というときはネガティブな文脈で出ることが多く、関連付けて記述されたものはよい迷惑であろう。

こちらの解説にもあるようにBet365はきちんとした歴史ある会社で知名度も高い。

BET365とは1974年から続く超老舗ブックメーカーで、 現在は、全世界200ヵ国に500万人の顧客がいる と言われている大手メーカーです。
イングランドプレミアリーグ(イギリスのトップリーグ)、ストークシティのユニフォームスポンサーを務めるなど、名実ともに信頼ある大企業です。

しかるにPublickeyではタイトルからしてミスリーディングであり、Riakというソフトウェアの将来が怪しいギャンブル企業に買われてしまってどうなってしまうのか分からない…といったことを示唆する記事になっている。もちろん本文にそういった記述はないが、日本での賭博行為に対する一般的なイメージからいって先入観をもって読まれることは確実であろう。

したがって、新野さんは何よりもそれを予め防ぐような書き方をすべきであったと思います。訂正入りました

Riakを始めとするBashoの製品は「ほとんど」がそもそもオープンソースソフトウェアであった(対応済み)

記事には「Bet365のCTOが、Bashoの全製品をオープンソース化すると宣言」という見出しがあり、この曖昧な記述ではBashoの製品がプロプライエタリであるかどうかはっきりしない。全製品をオープンソース化という表現は、全製品がクローズドソースであったことを強く示唆する書き方であり、Riakというソフトウェアの正しい理解を妨げると思う。もともとRiakはOSS版とプロプライエタリ版があり、OSS版では一部機能が実装されていないという差があっただけのことだ。それはPublickeyの以前の記事(Amazon S3互換、Yahoo! Japanも採用した分散オブジェクトストレージのRiak CSがオープンソースで公開 - Publickey)でもある程度触れられていると思ったのだが、ここの記述は簡素に過ぎると思う。

OSS版との機能差は主に以下である。

  1. データセンター間レプリケーション
  2. SNMP/JMXによる監視機能

SNMPなどはまあオマケで、基本的にこのデータセンター間レプリケーションが目玉であったため、ここだけはソースコードは公開されていなかった。OSS部分は実に膨大で、ソフトウェアの機能でいうと9割以上はOSSとして公開されていたといっていい。いちおうここに機能差の表がある(が、いつまで残っているかはBet365次第だろう)

Bashoの資産はソースコードだけではないし、全ての資産を買収したわけでもない(対応済み)

Bashoの資産は商用版のソースコードだけでなく、他にも多くのものがある。

  1. 既存アカウントとのサポート契約
  2. basho.com のドメインと関連するインターネットサービス( *.basho.com のWebサイトや riak-users などのML
  3. GitHubアカウントや、Bashoが持っていた各種データ、ログ、ビルド関連のツールやサーバーなど
  4. Riakの商標権

たとえばRiakのドキュメント docs.basho.com はしばらく前から利用できなくなっていたし、 RiakのカンファレンスRICONのサイト ricon.io も今はアクセスできくなっている。RiconはRiakに限らない分散システムのカンファレンスを標榜していて、Riakに限らず分散オタクたちのハードコアなカンファレンスとして有名であった(こういうやつ)。まあGitHubアカウントやいろいろな性能や試験などのソフトウェアに関するデータはそのうち出てくるかもしれないし、Bet365が不要だと判断して破棄するかもしれない。

なかんづく重要なのはRiakの商標権で、これについてスレッドでも盛り上がっていた。商標権を確保しているといないとではOSSとしてのRiakの使いやすさが大きく違う。もちろん商標がなくてもライセンスで認められているのでOSSとしてソフトウェアを利用し続けることはできるが、Riakそのものを使ってビジネスをすることが難しくなるし、OSSとして好ましい状態ではない。Hudsonのことを覚えておられる読者諸賢も多いのではないだろうか?

最後の問題点は既存アカウントとのサポート契約だ。Bet365の人からのメールにも "Basho's remaining assets (except support contracts)" と明記されている。つまり厳密には「Bet365とBashoは、Bashoの資産をすべてBet365が買収することで合意」という表現も誤っている。

私の推測では、Bet365の動機はこの商標権とデータセンター間レプリケーションなのではないかと思う。データセンター間レプリケーションは長年の大型クラスタでの無停止運用にも耐えた実績があり、こちらをうまくコミュニティで共同でメンテナンスすることで使い続けたいという意図がOSS化の背景にあると想像している。

「買収」の背景: これはいわゆる普通のスタートアップの買収とは違う

さてRiakやBashoという名前、昨年はほとんどインターネット上で見かけることもなかったと思う。今年に入ってからはめっきり動きがなくなり"Will the last person at Basho please turn out the lights?" と、その消えっぷりに疑問を持つ人が多くいたくらいだ。これが 7/13 で、その月末には End of the road for Basho: Court puts biz into receivership • The Register という記事が出ており、 "filed for receivership in early July after Basho defaulted on payments" と書かれている。つまり資金繰りができなくなって7月にreceivership状態になった(何と訳すのがよいか知らないが「管財申請」とか財産管理状態ということだろう)。Wikipediaによると破産すらできない状態ということらしい。こうなると具体的にどういうプロセスを経ていくのかは詳しくはないので分からないが、こういう状態であるから、いわゆるスタートアップの買収とは異なり人もモノもないので、二束三文の価格だったのだろうと容易に推測できる。つまりBashoに投資した投資家は大損こいたわけである(あれ、Receivershipになったということは投資家には二束三文どころか1セントも戻らないということ?アメリカの制度詳しくないので誰かに教えてほしい)。これは救済とは呼べない。

実際に世界中のオフィスが閉鎖され、ほとんどの従業員が既に解雇されており、Bashoの良心たるMvMが Basho closed とメッセージを発信していた。さてこれで困るのは大規模なRiakクラスタを抱えるユーザーたちである。データセンター間レプリケーションを除くほぼ全ての機能はソースコードが公開されているからすぐには困らないものの、ソフトウェアをメンテナンスしながら使い続けるか、他のソフトウェアに移行するかを選ばなければならない。後者は基本的に黙って去るので、特にインターネット上で観測できない。前者はBet365を筆頭に、BashoとRiakの技術を高く買っているところが集まったようだ。6月にはErlang Solutionsが商用サポートの検討を始め、8月の時点で商用サポートが行われることがアナウンスされた。- Erlang SolutionsのRiakページ によるとRiak CSもサポート対象のようだ。おおお。。。

NHSは商用版に諦めをつけ始めたのか、データセンター間レプリケーションのミドルウェアをRabbitMQを使って作ってしまったようだ(公開直後にBet365のニュースを知って驚いたともコメントしている)。

Riakはこれからどうなるのか?

コミュ二ティでは、Bet365、Erlang Solutions, NHS を中心にメンテナンスが続けられていくだろう。公開予定の商用版コードについてはApache 2ライセンスが支持されているようだ。その場合、Bashoなき今、著作権者は誰になるのだろうか? 素直に Apache 財団に送ってもよいと個人的には思うが、みんなJIRA嫌いだったしなあ…CNCFってこともないだろうしな…

商用サポートについては、アナウンス通りTI Tokyoという東京の会社がサポート契約を買い取っており、既存顧客のサポートはそちらでErlang Solutionsと共同で行われる模様だ。
あとのことは分からない。

まとめ

  • Bet365は「ギャンブルサイト」ではなく伝統的なブックメーカーであり、合法で社会的に認められた事業である
  • 「全製品をオープンソース化」ではなく、これまでプロプライエタリだった部分を公開するとBet365が宣言した
  • Bashoの資産はソースコードの他にもいろいろあって一番不安視されていたのが商標権
  • これはいわゆる普通のスタートアップ買収とは異なるものであるが「救済」という言葉も少し違うと思う

追記: その後コメントをいただき、記事が修正された。時間をみるにわたしが記事を公開した直後の対応だったようだ。

参考

Replication (Lecture Notes in Computer Science)

Replication (Lecture Notes in Computer Science)

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化