2016年5月18日水曜日

RAID6 のディスク交換

家のサーバーのディスクの1つにバッドセクタが出てきました。SMARTで調べたら、もう5.7年も稼働しているディスクのようで、そろそろ交換していいころですね。よく頑張ってくれました。そのディスクは2.0TBのやつなのですが、確かあの頃はすごくディスクが安くて確か6000円とかで買えたような気がします。手元にある3.0TBのやつが確か半年前ぐらいに買ったのですが8000円ぐらいしてたように思うので、5年ほど経った割にほとんど価格が変わってないなぁと思ったりもします。

さて早速交換しましょう。バッドセクタがあるとは言え、現状動いているのでまずアレイから抜く作業をします。Disk Utility 等でどのディスクが交換対象なのかは押さえておきます。私の場合 /dev/sdd でした。シリアルナンバー等も控えておきます。(同じサイズのものが複数あるので)

まずは取り外しのコマンドから
# mdadm --manage /dev/md126 --fail /dev/sdd1
すると
# mdadm --detail /dev/md126
(略)
    Number   Major   Minor   RaidDevice State
       0       8        3        0      active sync   /dev/sda3
       2       8       81        1      active sync   /dev/sdf1
       3       8       19        2      active sync   /dev/sdb3
       4       8       33        3      active sync   /dev/sdc1
       6       8       65        4      active sync   /dev/sde1
      10       0        0       10      removed

       5       8       49        -      faulty   /dev/sdd1
のように faulty としてマークされ、アレイから除去されます。そしたらシャットダウンして、物理的にディスクを交換します。

交換したら起動して、新しいディスクにパーティションを作成します。今回はOSが入っているディスクと同じサイズのディスクなので、OS部分のパーティションを切った関係で sdd1 だったものが sde3 になりました。その領域を追加します。
# mdadm --manage /dev/md126 --add /dev/sde3
mdadm: added /dev/sde3
大丈夫そうですね。もう一度上の detail で調べると
# mdadm --detail /dev/md126
(略)
    Number   Major   Minor   RaidDevice State
       0       8        3        0      active sync   /dev/sda3
       2       8       81        1      active sync   /dev/sdf1
       3       8       19        2      active sync   /dev/sdb3
       4       8       33        3      active sync   /dev/sdc1
       6       8       49        4      active sync   /dev/sdd1
       7       8       67        5      spare rebuilding   /dev/sde3
 
となり、リビルドが開始します。なんて簡単なんだ・・・。とはいえ、作業は簡単ですが2TB領域のリビルドなんで時間だけは盛大にかかります。とりあえずリビルドが終わるまではあまり負荷をかけないようにします。まあ現状でもRAID5の正常状態と同じなので安心感はありますが。

2016年4月20日水曜日

Jar の META-INF/MANIFEST.MF に書いた Class-Path が効かない件

案外ググったりしてもぴったりの記事には遭遇しなかったので、ブログに書いておきます。

まずやりたかったことですが、Javaで書いたコードをjarにまとめて、それをjava -jar (やダブルクリック等)で開けるようにしようと思ったのですが、その際別のライブラリがjarで提供されているので、そのjarもclasspathに追加した状態で起動したい、ということでした。これ自体は META-INF/MANIFEST.MF に書けばなんら問題なくできます。できるはずでした。

まずそのまとめるjarのほうですが、mavenを使って書いていたので、pom.xmlにこのように書けば main メソッドの指定は簡単にできます。
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>jartest.Main</mainClass>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>
これでビルドして実行すると
$ java -jar jartest-0.0.1.jar 
Hello!
当然ですが、問題ありません。

次に外部 jar の呼び出しですが、その前にこちらの jar の main メソッドをこのように書いておきます。
public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("Loaded:" + Class.forName("jartest2.EndPoint").getName());
    }
}
呼び出される側は jartest2.EndPoint というクラスを持っています。この時点で
$ java -cp jartest-0.0.1.jar:jartest2-0.0.1.jar jartest.Main
Loaded:jartest2.EndPoint
となります。これを jartest2 のほうを classpath に指定しなくても java -jar jartest-0.0.1.jar で起動できるようにしたいというのが今回の目的なわけです。
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>jartest.Main</mainClass>
          </manifest>
          <manifestEntries>
            <Class-Path>jartest2-0.0.1.jar</Class-Path>
          </manifestEntries>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>
このように pom.xml を変更すればいけるはずです。実際はこちらの jar は他にも依存してるライブラリがあって、ただそちらは maven で取得できるライブラリなので、dependencies に記述し、よくある方法にて maven-assembly-plugin のほうに上のような記述をします。さていざ実行。
$ java -jar jartest-0.0.1-jar-with-dependencies.jar 
Exception in thread "main" java.lang.ClassNotFoundException: jartest2.EndPoint
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:264)
 at jartest.Main.main(Main.java:5)
!?
とりあえず jartest.Main.main() までは来ているので MANIFEST.MF が全くダメなわけではないということはわかります。中身を見てみると、
$ tail -3 META-INF/MANIFEST.MF 
Main-Class: jartest.Main
Class-Path: jartest2-0.0.1.jar
と、正しく指定されているように見えます。

正直相当はまりました。しょうもないtypoしてるのかと思ってコピペでクラス名を書いてみたり、ファイル名もコピペしてみたり。はたまた開発環境に使っているMac特有の問題なのじゃないかと思ってWindows機でテストしてみたり・・・。

そしていろいろやった後も解決せず、jar を展開してぼーっと眺めていたら
$ ls META-INF/
INDEX.LIST    LICENSE.txt    MANIFEST.MF    maven/        services/
ん?MANIFEST.MF以外にもいろいろあるな?まさかな、と思いつつ MANIFEST.MF だけにしてみたところ・・・
$ java -jar jartest-0.0.1-jar-with-dependencies.jar 
Loaded:jartest2.EndPoint
おおお!動きましたね!

結論から言うとこの INDEX.LIST が悪さをしていたようです。そもそもこれは何かというのを知らなかったですが、Jarファイルの仕様にしっかり書かれています。でも今までこんなファイルを作るなんて指定はどこにもしてなかったけど・・・?原因はこれでした。
    <dependency>
      <groupId>io.undertow</groupId>
      <artifactId>undertow-core</artifactId>
      <version>1.0.16.Final</version>
    </dependency>
私が作っていた java application は embedded web server を実装するのに undertow を使っていました。そしてそれを dependency にして jar-with-dependency で1つの jar にしていたわけですが、もともと undertow-core 用に書かれた INDEX.LIST が jar-with-dependency によって1つの jar に収められたことにより生じた問題だったようです。いやはやなんとも難しい・・・。

というわけで解決方法としては INDEX.LIST ファイルを jar に含めない、またはちゃんと INDEX.LIST ファイルを生成する、のどちらかだと思うのですが、undertow が使っている INDEX.LIST の内容は特になくても問題ない(ように思える)ので、含めない方法をとることにしました。maven-assembly-plugin の jar-with-dependency の指定のところを外部の assembly.xml に記述することとし、そこに以下のような記述を行います。
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
  <id>jar-with-dependencies</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <unpack>true</unpack>
      <scope>runtime</scope>
      <unpackOptions>
        <excludes>
          <exclude>META-INF/INDEX.LIST</exclude>
        </excludes>
      </unpackOptions>
    </dependencySet>
  </dependencySets>
</assembly>
これで無事 INDEX.LIST を含まずに dependency を含んだ jar が生成されました。めでたしめでたし。

2015年9月4日金曜日

艦これ+航海日誌環境における猫事件についての調査

ブログ書くの相当久しぶりになりました。最近趣味では新しいことがあまりできてなかったので書くネタがなかったのですね。もっと時間を作らないと。

さて今回のネタはもともと技術的な話ではなかったのですが、結局は技術的な話になったのでここに書くことにしました。内容は艦隊これくしょん(艦これ)の通信についての話なので、興味のある方だけ読んでみてください。

私が艦これを始めたのは相当前になります。最初はただの興味本位で始めたのですが、基本運ゲーでも結構いろいろ考えることが必要なことがわかり、最初はアナログな試行錯誤をしていたところ@sanae_hirotakaさん作の航海日誌という大変便利なソフトに出会い、より楽しくプレイさせていただけるようになりました。作者さんがソースを公開してくださっているので、私の専門のJavaで書かれていることもあり、ほんの少しですがpull request等で開発に協力させていただいたりもしていました。

ところが事件が起きた(起き始めた)のは2015年の夏イベント(通称夏イベ)が開始されてからです。今まではほとんど猫った(エラーが起きた)ことのない平和な我がタウイタウイ泊地だったのですが、夏イベ開始のサーバーメンテナンス明けからちらほら猫るようになりました。最初はサーバーが混んでるのかなと思っていましたが、空いてそうな時間帯でもなることがあり、変だなと思い始めました。しかしネット上では特に騒がれている風もなく・・・。

すると艦これをやってる知り合いから「どうも航海日誌を使ってると猫るって話になってるぞ」との知らせが。そんな馬鹿なと思いツイッターで「航海日誌 猫」とかで調べてみると確かにそういう事象にあっている方もいるようで、ただ実行環境によるのか、サーバーによるのかは不明にせよ、全く起きない方もいるのも事実。 しかし調べていたら、こんなに便利に使わせてもらってるソフトをしかもタダで使わせてもらってるのに、「使えねー」とか「ふざけんな」とか言われてるのは納得いかないので調査してみようと思ったのがこの記事を書いている理由です。

するとその知り合いからさらに「特にテザリングでやってるとしょっちゅう猫る」との知らせが。それをヒントに、まずどういう環境で出やすいのかを考えました。家ではあまり出ない、テザリングで出やすい、と考えると、やはり遅い回線だと出やすいのではないかと考えました。そこで私はiijmioのSIMでiPhone4Sを運用しているのですが、このiijmioのSIMはアプリで通信速度を低くすることができます(正確には高速通信は月3Gまでとなっているので、高速通信をオンオフできます)。なので高速通信をオフにした、たしか200kbps程度の通信速度でテザリングして艦これしてみました。

すると


でました、猫。ログインしてすぐというわけではないですが、任務をクリックしたり母港に戻ったりとか通信を何度もしていると、私の環境では数分で起きます。これは何かありそうですね。そう思って航海日誌を通さずに艦これしてみると、不思議なことに全く猫は起きません。なぜでしょう。

悩んでても解決できないので、Wireshark を使ってパケットキャプチャをしてみました。そして猫が出るまで通信を繰り返します。そして猫が出た時と出なかった時を比べます。すると
うまく行った時はこんな感じです。これは任務一覧を表示した時ですね。POSTのメッセージに対して ACK が返り、その後 200 の応答が返ってきます。普通です。ところが猫が出た時は(キャプチャミスってボケてます。すみません。)

のように、[FIN, ACK] が返ってきています。FIN は通信終了なので切断するという意味なので、航海日誌が使っている jetty の ProxyServlet は EOFException を投げます。結果ブラウザから見れば通信エラーとなり、猫が出るという仕組みでした。

しかしこれだったら普通に航海日誌抜きでやっても同じなのでは?と思って試してみたところ・・・
おお、これは・・・。どういうからくりかはわかりませんが、上のようにAPIの呼び出しが切断された時はどうもリトライしにいくようですね。これは任務の受諾をやめた時に呼ばれるAPIなので、連続で来るはずはないリクエストになります。通常は stop が来た後 questlist が来るはずのところを2回 stop が来ているので明らかにリトライしているようです。

なので ProxyServlet 経由でも全く同じ状況、FIN を返すことができれば勝手にリトライしに来ると考えられます。しかしそれを ProxyServlet を使ってやるのは難しそうに思います。試しに ReverseProxyServlet を無理やり extends して EOFException が出た時にリトライするサーブレットを書いてみたところ、私の環境では猫は出なくなりました、があまりに無理やり過ぎるので pull request はしないほうがよいかなと思って保留しています。

なぜ通信が切断されるようになったか、という点については、どうもこのメンテナンスでサーバーによっては HTTP 1.1/ keep alive が使われるようになったそうです。とはいえメンテナンス前が keep alive じゃなかったかどうかは全く知らないですけどね。その実装の影響でこうなったのかもしれません。想像でしかないですが。

結論としては、
- なぜか環境によっては艦これサーバーからAPIリクエストの通信が切断されることがある
- ブラウザから直結している場合は自動的にリトライする
- 航海日誌やその他プロキシの実装によってはその切断が別のエラーとして処理されると猫る
ということのようです。なので実装系が違う他のソフトでも同様な挙動をしていれば、航海日誌と同じように猫りやすくなったソフトもあると考えられます。というわけで、この猫事件(?)の真相は「艦これの微妙な(怪しい)挙動」が根本原因であって、航海日誌その他プロキシの実装のバグと呼ぶのはフェアじゃないと思いますね。


2014年10月27日月曜日

undertow を使ってみる

ひょんなことから自分のJavaアプリケーションにWebサーバーというかサーブレットコンテナの機能が少しあったら便利だなと思って調べてみたところ、undertowというのがお手軽に使えそうに見えたので試してみました。

1. インストール


そのJavaアプリケーションはmavenを使っていたので、依存関係を追加するだけです。
  <dependency>
   <groupid>io.undertow</groupid>
   <artifactid>undertow-core</artifactid>
   <version>1.0.16.Final</version>
  </dependency>
いやぁ、この手の依存解決ツールって楽ですよねぇ。今さら ant とか書きたくないです。

2. 使う


トップページの下のほうに Show me the code というのがあるので、そのコードをそのままコピー&ペーストします。

Undertow server = Undertow.builder()
 .addHttpListener(8080, "localhost")
 .setHandler(new HttpHandler() {
  @Override
  public void handleRequest(final HttpServerExchange exchange) throws Exception {
   exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
   exchange.getResponseSender().send("Hello World");
  }
 }).build();
server.start();
これだけです?w

3. 使ってみる


では早速リクエストを投げてみます。
$ curl localhost:8080
Hello World$ 
これだけです?w(再

たったこれだけですがサーブレットコンテナとして既に動いているわけですね。これはなかなか楽かも。

当然ですがこのままでは localhost からしかつながりません。 addHttpListener のところで "localhost" を "0.0.0.0" とかにすれば任意のマシンから接続できます。

2014年9月30日火曜日

#f1yosou を今シーズン限りでやめることにしました

公式アカウントから既におしらせした通り、これまで約4年半に渡って開催してきた #f1yosou ですが、今シーズンの終了を持って開催を終了することとしました。みなさん気を遣ってくださって、理由は特に聞かずに受け入れてくださっている方がほとんどですが、決定に至った理由を書いておきますね。

理由を一言で言うなれば「一定の役割を果たした」という感じでしょうか。当初の目的だった、ツイッターでゆるい感じの予想大会をして、それでF1好きの方々でわいわい楽しめたらいいね、という目的は果たせたかなと思います。

当初はサイトもなかったので、有志でお題を決め、予想を管理して、的中者の発表をしていました。人数も少なかったので、フォロワーさんの間でわいわいやりながら、特に強制することもなくおめツイートもしていましたね。そのうち管理が楽になるように私がサイトを作りました。私の技術不足(ウェブ周りの技術者じゃないのです)もあり、結構な時間を費やしましたが、参加していたみなさんからの暖かい言葉に助けられ、なんとか使える程度のサイトを作ることはできたのかなと思っています。

サイトが出来たことで、手作業に比べてはるかに楽になりましたし、F1の話題、しかも予想のお題が上位とは限らなかったので普段注目しない順位のドライバーの話題に一喜一憂できる楽しさがあったので、もっと多くの方と楽しめるように宣伝もし、おかげさまで2013年には最大51名もの参加者を集めることができるようになりました。主に私の技術的興味の側面もありましたが、サイトのリニューアルなんかも行ってきました。途中でインフラとして使っている Google App Engine の課金方法が変更され、それまでの方法ではすぐにサイトが使えなくなったりする苦労もありました。以降施したさまざまな改善により、最近はサイトが使えなくなるようなことはおきないようになりました。いやぁ、Datastore Read Operations の制限は厳しかったっすよ Google 先生。。

そんな苦労もありましたが、でも多くの方、特に初期のころから参加してくださってるみなさんは、ツイートの自動検出が難しいこと(投票のフォーマットは決めていないので)や、課金されないように運営することが大変なこと、などを理解してくださっていたので、いろいろ対策した後の効果の検証を助けてくださったり、何よりねぎらいの言葉をかけてくださったのが非常にうれしく、運営のモチベーションになっていました。

***

しかし、人数が増えたことだけが問題とは思いませんが、運営を続けるにつれ初期に比べて参加者のみなさん同士の新たなつながりは少なくなったように感じていました。的中者におめでとうのツイートをするのが唯一の賞品なわけですが、それを行わない方も多くなったように思います。もともとおめツイートをすることによって、これまでフォローしていなかった方と新たにつながったりできるといいよね、という考えで参加者を広く募ってきていたので、それが行われないとなると続ける意義がどれだけあるのかがわからなくなってきました。また、おめツイートをしても1ターン(?)で会話が終わることもほとんどで、なかなか新たなつながりには結びつかなくなりましたね。

さらに、最近は運営に対する批判もいくつか頂戴しました。上記のように、「ツイッターでゆるく予想を楽しむ」がコンセプトだったので、予想のツイートには特にフォーマットを定めておらず、そのために検出漏れ、検出間違い等はどうしても避けられませんでした。そのため「予想がおかしいです、直してください」というお知らせはよく受け取りましたが、多くのケースはドライバーの名前があまり見ないカタカナ綴りやあだ名になっているか、お題の答えになっていないケース(たとえば10位のドライバーを予想してください、というお題で、「10位は可夢偉」ではなく「可夢偉は10位」とツイート(お題の抽出精度を高めるために助詞の前後の関係とかも見てるのです))だったりすることが多かったです。その都度ある程度対応していますが、参加者全員の名前の読み方を統一することは不可能ですし、一部を調整すると他に検出漏れが出るなどの問題もあり、残念ながら手作業は欠かせない状況です。ですが私はもちろんこのサイト管理で食い扶持を得ているわけではないためサイトに張り付いて管理することはできず、どうしても対応は遅れがちになります。その状況で「まだ直ってないんですが」というツイートを何度かもらうのはさすがに滅入りました。それ以外は主に私の管理者としての問題に起因するのでしょうが、他にもいくつか批判を頂戴しました。

***

ですが、これらはある意味不特定多数の参加者を募っている時点である程度しかたのないことなんだと思います。サイトの運営で利益を上げているわけではないのでそれらの批判には腹も立ちますが媚びへつらう必要もないわけで受け流せばよいわけです。それよりも直接の原因となったのは、むしろ「孤独感」のほうかも知れません。

以前は何かサイトを改良したりすると参加者のみなさんからすぐに感想をもらえましたし、こんなことやってるよというツイートに誘われて今度参加してみますという会話がTL上にあったり、「Statsのページはまだかな(チラッ」のようにさりげなく期待の声があがっていたり。 もともとは予想1つだったのを2つを予想するようになったこと。ポイントシステムを採用したこと。これらもすべて私ではなく参加者のみなさんで決定したことでした。私やサイト、公式アカウントが何かするのではなく、みんなで決めていた、その感覚が楽しかったのかも知れません。最近参加された方はもちろんご存知ないと思いますが、サイトや公式アカウントのロゴも私が作ったのではありません。

それに比べると今は「管理者」としての立場が強すぎるのか、私自身もひとりで黙々とミスなく作業するのが当たり前という感覚ですし、参加者のみなさんから頂戴する批判からもかなりのみなさんがそのような感覚でいるのだと思えます。それは果たして #f1yosou が求めてきた姿なのでしょうか。これ以上運営していて何か意味はあるのでしょうか。

いろいろな変化があるとは言え、 #f1yosou をはじめたころに参加していたメンバーの大半が参加していないかまたはほとんどツイートしなくなってしまっています。シーズン末の結果発表にわざわざ「皆勤賞」「準皆勤賞」を設定しているのは、ずっと参加して盛り上げてくださっているみなさんに少しでもお礼・お祝いをしたいという気持ちで設定していますが、逆にほとんどツイートしていないのに #f1yosou だけ参加してくださってる方もおられ、そのような方にはむしろ余計な義務感を与えてしまっているのかもとさえ思います。もともとの「ゆるく予想して楽しもう」のコンセプトからは完全に離れてしまったと感じています。

***

このような考えに至り、そろそろ #f1yosou は幕引きの時期を迎えたのだろうと判断しました。公式アカウントとしては特に感情抜きで作業するようにしていますが、やはり日本GPは特別なものなので、発表は日本GPのころにしようと決めていました。参加者のみなさまには突然のお知らせとなって恐縮ですが、決めたのはもっと前になります。

もちろん、ツイッターのハッシュタグの性質上、この #f1yosou というタグになんら縛りがあるわけではないので、来年以降これをつかって予想する方々がおられても楽しいですし、どこかで似たようなイベントを起こす方がおられてもいいですね。私もどこかで参加するかも知れません。

以上、長文失礼いたしました。残り5戦となりましたが、参加者のみなさまと #f1yosou を楽しめるよう努力しますので、最後までお付き合いいただけるとうれしいです。公式アカウント、サイトとも今年いっぱいは維持する予定です。

2014年9月30日
@f1yosou と中の人 @Sdk0815

2014年7月28日月曜日

アメリカ出張の話(完結編)~ Ready SIM 使ってみました

前回書いたとおり、アメリカに出張に行ってきました。その時通信手段として、今回は Ready SIM というプリペイド SIM を試してみました。その結果のお話です。

Ready SIM は文字通り買ったらすぐ使えるというところをポイントにしているプリペイドSIMです。アメリカ国内だと送料が無料なのですが、今回は出張が決まったのが出発の4日前、ホテルが取れたのが3日前というわけで、通常の発送では間に合わないと思われたので、仕方なくトラッキング付きの $8.99 での発送にしました。あて先は滞在先のホテルです。

当然出発前に発送されたので、そのメールにあるトラッキングの番号でUSPSのサイトに行くと、配送状況が見れました。出発前に既に目的地の州に到着していて、乗り継ぎの空港で見たらもう Delivered となっていてホテルについていたようでした。楽しみにしつつ飛行機を乗り継いで目的地へ到着。

さてチェックインの時に「私宛に package(荷物)が届いてない?」と聞いてみたところ、「いや、何も届いてないよ」との返事。ううむ。おかしいですね。トラッキングの画面を見せて説明しないとだめかな?と思ってフロントへ行ってみると、既に深夜だったため(0:30)誰もおらず。しかしフロントの中をのぞいてみると、なにやら大きめな封筒が・・・。しかも USPS って書いてある。たぶんあれじゃないか?

と思って翌朝フロントで「私宛に USPS 経由で mail(手紙)が届いてない?」と聞いたところ、その置いてある封筒を見て、「名前は?」と聞かれ、答えると渡してもらえました!やったー。封筒で届いたやつだと package と言うと認識されないかもですね。なるほど。

届いたのはこんな封筒です。→
アメリカではよくみるやつですかね。





早速中をあけてみましょう。中には本体(?)とレシートが1枚入っているだけです。シンプルですがもちろんこれで十分。今回は現地たった4泊5日なのと、遊びに行く暇はなく会社との往復と夕食ぐらいしか移動することはないので、最低のデータ通信量(500MB/$15)のカードを買ってみました。そのように台紙にも書いてありますね。サイズの下に "Expires after 14 days"、つまり14日しか使えない旨も明記されています。

その下にある"7850"という数字がミソでして、基本自動でアクティベートしてくれうのがウリではありますが、狙った地域の電話番号を取ることもできるようです。その際はSMSでこの7850に向かって郵便番号を送ればいいとのこと。ただ今回はデータ通信のみのカードなので特に気にしなくてもいいですがね。

さて早速使おう・・・と思ったとき実はあせりました。どう見ても SIM のサイズが大きいのです。あれー、Micro SIM って頼んだはずなのに、自分か向こうかが間違えたかな?SIM カッターなんて持ってないよ、と思ったのですが、よく見ると細い溝が入っていてちょっと押せばこのように Micro SIM のサイズで取れるのでした。よかった。


さあ実際 SIM フリーの iPhone 4S に入れてみましょう。ただこの SIM にはピンが付いているのか不明だったので、念のため日本から SIM を入れ替えるためのピンを用意しておきました。実際入っていなかったので持って行って正解でしたね。入れ替えて日本のやつをなくさないようにこの台紙に入れておきます。さあスイッチオン!

・・・つながらないですね。当たり前か。モバイルデータ通信のところで APN の設定がいります。まあそのぐらい楽なもんなのでさっさとやります。・・・まだつながらないです。

うーむ。やはりSMSで送らないとだめかな?でもiPhoneでの送り方知らない・・・。などとホテルの WiFi 経由でググったりしていたら

いつの間にかつながっていた

なんという拍子抜けw アクティベーションが自動だとは言え、数分はかかるみたいなので、単純に待っていればよかったようです。一応 SMS で郵便番号を送ってはおきましたが、開通してしまった後では意味があるのか不明でした。

一度つながると、このように T-Mobile の回線として認識されています。使い勝手は正直地域にもよると思うので何とも言えませんが、今回の滞在中では会社の地下の会議室ではかなり電波の入りが悪い感じでしたが、それ以外ではほとんどつっかかることもなく良好でしたね。

というわけで、この Ready SIM、プリペイド SIM としては非常に楽です。事前に手に入っていれば、恐らく差し替えて APN の設定さえすればすぐつながると思います。ホームページからアクティベーションをして、トップアップカードを買って、とやるよりは数段楽ですね。

というわけで総じて気に入ったので、早速次回用に日本に発送してみました。日本宛の送料は $9.90 でした。来月使うのはほぼ決定なので、今回は2枚注文しました。結果的に1枚当たり $15+$9.90/2 = $19.95 ですね。手軽さを考えれば十分安いです。

しかし、一度アクティベートしてしまうとそこからは14日とか決まっていますが、使わないで持っていたらいつまで有効なんでしょう?会社がつぶれるまで?w 便利なのでつぶれないでもらいたいものです。

2014年7月17日木曜日

アメリカ出張に行くことになりました(アメリカでのSIMカードの話)

まあ話は出ていたのですがえらい人の折衝がなかなかはかどらず、昨晩ようやくいろんな承認ものがすべて完了し、本日から手配を開始したわけです。出発予定はなんと来週の月曜日。あと4日しかないw 労働日なんて明日1日だけ!w

私はアメリカ出張は何度か経験があり(1年ちょっとの赴任も含む)、慣れてると思われがちなんですが、実はアメリカへの出張ではカリフォルニアのいわゆるシリコンバレー以外に行ったことがないのです。ですが今回はカリフォルニアのあるPST/PDT(太平洋標準時/夏時間)の時間帯ではなく、CST/CDT(中部標準時/夏時間)の時間帯にあたるテキサス州はオースティンに行くことになっています。なので飛行機の常識とかもよくわからず、微妙に戸惑っているのですね。

カリフォルニアだと大体日本の夕方出発、向こうの午前中に着。向こうの午前発、こちらの(翌日)午後着、が普通ですね。最近は羽田から深夜便とかもあって、それに乗ると深夜出発、向こうの夕方着、向こうの夕方発、翌日夜着になりますね。個人的には着いた当日、帰ってきた日はすぐ寝たいのでこの深夜便はかなりお気に入りです。ですが今回の場所はこの手の常識もないのでいまいち感覚がつかめず。どうなることやら。(なんて言ってられる時期かどうかは不明ですが・・・。まだ取れてないものは仕方がない。)

今回はこれまた初経験なのですが、3人での同一行程の出張です。しかも私より年上の方々が一緒なので、責任は少なくて楽かな?でも逆に一人での自由行動は取れない(レンタカーが1台なので)という難点があります。一人でうろうろ出来るなら観光しようと思ったけど・・・。聞いたらあまり観光スポットはないかもとのことで。まあ私ならここ一択ですけどね!まあ遊べる時間はほぼないと覚悟しています。

しかし、やはり無駄に金だしてSIMフリーiPhoneを買ったバカ技術者としては、アメリカ出張となると外でのネット接続に異様な執念を見せたくなるわけですw 前回のドイツのときは事情がわからなかったのでモバイルルーターを借りていきましたが、アメリカはSIM万歳の国ですよ。ええ。せっかくのSIMフリー端末を活用しない手はない!(←結局言ってるw)

前々回の出張はアメリカ・カリフォルニアだったのですが、その時はAT&TのSIMを買っていろいろ悪戦苦闘しながら接続しました。でもその価値はあって、レンタカーにはナビは着いておらず、現地の人たちと遠くのレストランに行く時に私と同行者(日本人)だけで車で行かなければいけなかったのを、無事ナビ代わりにしてつくことができました。今回はそんな役目はなさそうですが、別の大きな理由がありまして。

来月インディーカーの最終戦であるMAVTV 500@フォンタナというレースがあるんですが、これを念願の現地観戦する予定になっています!飛行機はもう取ったので絶対いきます!その時には当然1人なので、ネット接続は非常に大事。何か試すなら今回の出張で試して、インディーカー観戦のときは万全の体制で臨みたいわけです。

では何を持っていくか。まず一番安心確実なのはやっぱりモバイルルーターなのです。 たとえばドイツ出張の時は US-RACING さんによく提供してくれているテレコムスクエアさんから借りたのですが非常に助かりましたね。設定はほとんどいらず、現地でオンにするだけ。電話も使える普通のスマホとかもあって、普通の旅行に行く方にはもちろんこれがお勧めです。アメリカだと 1,000円/日 ですかね。この金額がまず鍵になります。今回は日本不在期間(=借りる日数)が6日なので、6,000円也。

さてではまず前回と同じAT&TのSIMを買ったらどうなるか。前回は恐らく日本では買えなかったという意味だと思うんですが、eBayで$10ぐらいで買って日本に送ってもらいました。いろいろググってもらえばわかるんですが、そこからが結構面倒なのです。まずアクティベーションという処理が必要になりますが、これ、ネットとかからもできるんですけど、最終的に現地でSMSを受け取らないといけないので、結局現地についてからしか処理ができない。今日会社で聞いたらそのへんやれるのかやってくれるサービスなのかで日本で全部できましたよと言ってた人がいたので、最近は変わってるのかも知れません。で、アクティベーションした後に通信するためのお金をチャージするんですが、これも日本のクレジットカードではできませんでした。なのでスーパーでトップアップカードというカードを買ってチャージするという方法でなんとか使えるようになりました。

ただこの方法、手続きも結構微妙な線をついていて、なぜかスペイン語に言語を変更しないと手続きできないとか、 IMEIをどっかからもってこなきゃいけなかったりとか、かなり面倒な印象。しかも有効期限のあるプリペイドで使い切りなので、アメリカから帰ってきて1年後に行くときに使いたいと思っても、別のSIMを買ってやりなおさないといけない。まあこれは前回の印象なので、最近はだいぶ改善したようではありますが、今回はせっかくなので他の手を探ってみます。250MB/7日で$15と。SIMは今なら日本のアマゾンでも買えますね。1,000円程度です。

いろいろググっていたら KDDI mobile x h2o なるサービスを発見しました。日本で買えるなら便利ではあります。・・・ってオンラインショップでは「日本での購入を希望」というボタンは押せないし、日本の販売店のリストを見てもいまいち微妙な感じ?あと、一度チャージしなくなった後再チャージした場合にどうなるのかがいまいちはっきりわからないのです。これができると AT&T のとはずいぶん楽さが違うんですが。で、もっと調べていて一番困るかも知れないと思ったのは、データ通信分を使いきると追加等ができないことですね。たぶん越えないとは思うんですが、いざ超えた時に何も対策が取れないのはキツイ。なのでこれはナシかなと。通話つきで 500MB/1ヶ月で $30。

最後にググっていてたどり着いたのは Ready SIM でした。これこそまさにプリペイドの使い捨てです。T-mobileの回線を使っているらしいですが。これのよさげなところは、アクティベーションが楽っぽいこと。入国したらSIMさしてほうっておけばいいだけっぽいです。プリペイドで最初から通信量がついているので、トップアップ等も必要ないようですね。おまけに日本にも(というか国際)発送してくれるようなので、今回は当然間に合わないんですが、事前に頼んでおけば、アメリカ着いてSIMさせば終わり?あと、データ量足りなさそうな場合は後で追加もできるっぽいです。国際発送してくれるぐらいだから、日本のクレジットカードでも大丈夫なんじゃないかと期待しています。AT&Tに比べるとカバレッジが低いんじゃないかと言われてるようですが、今回行くとこ、あとフォンタナもカバレッジを見る限りバッチリカバーされているようなので気にしなくていいかな。500MB/14日で$15(SIM代込み)なのでAT&Tよりも安いですね。これは試してみる価値ありそう。

そう思って問題になるのはどうやって手に入れるかです。空輸は間に合わないので、現地調達ですかね?でもよく見るとデータ通信専用(電話なしなので安いほう) はオンラインでしか買えないようです。これは困りました。しかも FREE standard shipping within the USA、つまり米国内なら送料無料じゃないですか。いいなー。

では日本で売ってくれる業者さんはいないのかと調べてみました。おお、日本のアマゾンとかでも売ってますね。どれどれ・・・。「通話とSNS、データ通信500MB 7日間」サイトで$25のやつですね。価格は・・・

\5,980

倍じゃきかない・・・。orz

それ以外もいくつか調べましたが、売り切れだったり似たような($15 のやつを\4,000とか)価格設定だったので、正直買う気が失せました。日本までの送料があるとはいえ、本来$15や$25と知ってしまったのでそれが\4,000や\5,980になってしまうと手が出なくなってしまいます。我慢して現地のお店で買おうかと思ったらオースティンにはないようだし、そもそも3人同行なので(しかも年上の方に)「ちょっとSIM買いに行きたいんですけど」は言いにくい。そうなると残る手はただ一つ。

「アメリカのどこかに送るしかない」

同僚がよく「出張中にアメリカのアマゾンでしか買えないグッズをホテルに送ってるんです」とか言ってたことを思い出しました。聞いてみると問題なくホテルで受け取ってくれて、部屋に入るとおいてあったりしますよ、とのこと。ふむふむ。これはいいことを聞いた。失敗しても$15とかだし、まあ話のネタになったとあきらめもつく金額だからこれを試してみようと思います。そしてもしうまく行って使い勝手もよかったら、14日過ぎた後に2GB/1ヶ月 $40をチャージすると、フォンタナに行く期間がカバーできる。まあ2GBもいらないと思えば普通に500MBのを日本に輸入する実験をしてみてもいいですしね。

などと期待しつつ、まだホテルが決まってないので購入できないでおりますw 早く決めてほしいものですね。結果どうなるか、乞うご期待。

2014年2月2日日曜日

自己満足的自宅サーバーディスク構成変更(6)~仕上げ

さてようやく2.0TBのRAID5/2から4.0TBのRAID6/4となり、サイズも倍、冗長性も倍となりました。まあこの時点ではRAID10と同等と言えなくもないですが、RAID10は2本壊れるとダメな組み合わせもあるわけで、少しは改善したかな?

しかしアレイを大きくしただけではLVMのPVとしては大きくなっていません。
# pvdisplay /dev/md127
  --- Physical volume ---
  PV Name               /dev/md127
  VG Name               vg_data
  PV Size               1.82 TiB / not usable 3.50 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              476899
  Free PE               41829
  Allocated PE          435070
  PV UUID               N1cjJ3-N5Zy-7SqP-aVsz-47H4-9eF1-uucRbY
これを大きくするには
# pvresize /dev/md127
  Physical volume "/dev/md127" changed
  1 physical volume(s) resized / 0 physical volume(s) not resized
# pvdisplay /dev/md127
  --- Physical volume ---
  PV Name               /dev/md127
  VG Name               vg_data
  PV Size               3.64 TiB / not usable 2.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              953799
  Free PE               518729
  Allocated PE          435070
  PV UUID               N1cjJ3-N5Zy-7SqP-aVsz-47H4-9eF1-uucRbY
でOKです。これが終わったら最後に残っているRAID 1のアレイにあるextentをここに移動します。(また数時間仕事w)それが終わったらそのアレイをLVMから外し、パーティションを切りなおし、またRAID 6のアレイに追加します。
# mdadm --add /dev/md127 /dev/sdd1 /dev/sde1 
mdadm: added /dev/sdd1
mdadm: added /dev/sde1
# mdadm --detail /dev/md127
/dev/md127:
    Number   Major   Minor   RaidDevice State
       0       8        3        0      active sync   /dev/sda3
       2       8       81        1      active sync   /dev/sdf1
       3       8       19        2      active sync   /dev/sdb3
       4       8       33        3      active sync   /dev/sdc1

       5       8       49        -      spare   /dev/sdd1
       6       8       65        -      spare   /dev/sde1

スペア2台になりました。サイズを増やします。やっぱひとつずつだよね・・・。
# mdadm --grow /dev/md127 --raid-devices=6
mdadm: Need to backup 2048K of critical section..
おっ!?いきなり2個分増やせたのかな?
# cat /proc/mdstat 
md127 : active raid6 sde1[6] sdd1[5] sdb3[3] sda3[0] sdc1[4] sdf1[2]
      3906763776 blocks super 1.2 level 6, 512k chunk, algorithm 2 [6/6] [UUUUUU]
      [>....................]  reshape =  0.0% (607232/1953381888) finish=1849.1min speed=17600K/sec
できてるっぽい!しかもたった(!)1849分=30時間じゃないか!(←既に麻痺してるw)実際は26時間ほどで完成しました。
# mdadm --detail /dev/md127 
/dev/md127:
        Version : 1.2
  Creation Time : Fri Jan 24 09:11:13 2014
     Raid Level : raid6
     Array Size : 7813527552 (7451.56 GiB 8001.05 GB)
  Used Dev Size : 1953381888 (1862.89 GiB 2000.26 GB)
   Raid Devices : 6
  Total Devices : 6
    Persistence : Superblock is persistent

    Update Time : Sat Feb  1 09:49:27 2014
          State : clean 
 Active Devices : 6
Working Devices : 6
 Failed Devices : 0
  Spare Devices : 0

         Layout : left-symmetric
     Chunk Size : 512K

    Number   Major   Minor   RaidDevice State
       0       8        3        0      active sync   /dev/sda3
       2       8       81        1      active sync   /dev/sdf1
       3       8       19        2      active sync   /dev/sdb3
       4       8       33        3      active sync   /dev/sdc1
       6       8       65        4      active sync   /dev/sde1
       5       8       49        5      active sync   /dev/sdd1

おお・・・。8.0TBのディスク(しかも2本の冗長性)なんてもはや家庭用とは思えないw これで子どもの写真や動画とかがなくなるリスクが軽減されたのだと納得させます。
もちろん
# pvresize /dev/md127 
をしてLVM上でも使えるようにすることをお忘れなく。

これにて完成!まとめると
  1. 2.0TB (/boot, swap, /, pv(1))
  2. 2.0TB (/boot, swap, /, pv(1))
  3. 2.5TB (pv(2))
  4. 2.5TB (pv(2))
  5. 3.0TB (pv(3), data)
  6. 2.0TB (pv(3))
でデータ領域はpv(1) (1.5TB RAID 1) + pv(2) (2.5TB RAID 1) + pv(3) (2.0TB RAID 1)= 6.0TB の構成だったわけですが、
  1. 3.0TB (/boot, /, pv)
  2. 2.5TB (/boot, /, pv)
  3. 2.5TB (pv)
  4. 2.0TB (pv)
  5. 2.0TB (pv)
  6. 2.0TB (pv)
で pv (2.0TBx6 RAID 6) = 8.0TB の構成となりました。この後、1から3のディスクには空きが少しあるので、swap 領域の確保とテンポラリ領域を作成して終わりです。

本当は停電対策(正確にはUPS故障対策)のために別アレイにコピーしたいんですけどね。いろいろ考えていたら、RAID 6ってデータ書き込むとき全ディスクにほぼ同時にアクセスするわけじゃないですか。その瞬間にUPSが壊れて電源ロスが起きたら同時に3台以上のディスクがダメになるということも考えられなくもないかなと。まあそれはかなりのレアケースだと思うので、現状はこの状態で運用しようと思います。

2014年1月30日木曜日

自己満足的自宅サーバーディスク構成変更(5)~他のアレイを移行

会社から帰ってきたらRAID 5(2台)の構築は終わっていました。
# mdadm --detail /dev/md5 
/dev/md5:
        Version : 1.2
     Raid Level : raid5
     Array Size : 1953381888 (1862.89 GiB 2000.26 GB)
  Used Dev Size : 1953381888 (1862.89 GiB 2000.26 GB)
   Raid Devices : 2
  Total Devices : 2
    Persistence : Superblock is persistent

    Number   Major   Minor   RaidDevice State
       0       8       67        0      active sync   /dev/sde3
       2       8       81        1      active sync   /dev/sdf1
ふむふむ。いい感じです。この状態だと前のRAID 1と(サイズ的にも、冗長性的にも)同等の状態なのでこれを再びLVMに戻して他のディスクをあけます。
# pvcreate /dev/md5
  Physical volume "/dev/md5" successfully created
この時点では、まだVGに属してないボリュームとして見えます。
早速追加します。
# vgextend vg_data /dev/md5
  Volume group "vg_data" successfully extended
pvdisplay等でも正しく追加されたことが確認できますが、GUIでも
のように確認できます。あとはここに次に移行したいアレイから extent を移動します。今度は /dev/md4 をあけました(ってさらって書いてますがこれも5、6時間は放置してたかなw)。同じようにすべて"Unused Space"になっているのを確認して"Remove Volume from Volume Group"してからアレイを停止します。

その外したディスクについて新しくパーティションを切ります。切ったパーティションを今度は前回作ったRAID 5のアレイに追加します。

# mdadm --add /dev/md5 /dev/sdc3 /dev/sdd1 
mdadm: added /dev/sdc3
mdadm: added /dev/sdd1
# cat /proc/mdstat 
Personalities : [raid0] [raid1] [raid6] [raid5] [raid4] 
md5 : active raid5 sdd1[4](S) sdc3[3](S) sdf1[2] sde3[0]
      1953381888 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/2] [UU]

# mdadm --detail /dev/md5
/dev/md5:
        Version : 1.2
  Creation Time : Fri Jan 24 09:11:13 2014
     Raid Level : raid5
     Array Size : 1953381888 (1862.89 GiB 2000.26 GB)
  Used Dev Size : 1953381888 (1862.89 GiB 2000.26 GB)
   Raid Devices : 2
  Total Devices : 4
    Persistence : Superblock is persistent

    Update Time : Sat Jan 25 16:20:44 2014
          State : clean 
 Active Devices : 2
Working Devices : 4
 Failed Devices : 0
  Spare Devices : 2

         Layout : left-symmetric
     Chunk Size : 512K

    Number   Major   Minor   RaidDevice State
       0       8       67        0      active sync   /dev/sde3
       2       8       81        1      active sync   /dev/sdf1

       3       8       35        -      spare   /dev/sdc3
       4       8       49        -      spare   /dev/sdd1

この状態ではRAID 5(2台+スペア2台)になります。これをRAID 5(3台+スペア1台)に変更します。(再起動した関係でデバイス名が変わっています。)
# mdadm --grow /dev/md127 --raid-devices=3
mdadm: Need to backup 1024K of critical section..
# mdadm --detail /dev/md127
/dev/md127:
        Version : 1.2
  Creation Time : Fri Jan 24 09:11:13 2014
     Raid Level : raid5
     Array Size : 1953381888 (1862.89 GiB 2000.26 GB)
  Used Dev Size : 1953381888 (1862.89 GiB 2000.26 GB)
   Raid Devices : 3
  Total Devices : 4
    Persistence : Superblock is persistent

    Update Time : Sat Jan 25 17:57:44 2014
          State : clean, reshaping 
 Active Devices : 3
Working Devices : 4
 Failed Devices : 0
  Spare Devices : 1

         Layout : left-symmetric
     Chunk Size : 512K

 Reshape Status : 0% complete
  Delta Devices : 1, (2->3)

    Number   Major   Minor   RaidDevice State
       0       8       67        0      active sync   /dev/sde3
       2       8       81        1      active sync   /dev/sdf1
       3       8       35        2      active sync   /dev/sdc3

       4       8       49        -      spare   /dev/sdd1
無事3台構成のRAID 5としてreshapeのプロセスに入ったようですね。いつもの /proc/mdstat も見てみましょう。
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md125 : active raid1 sdb1[1] sde1[2] sdc1[3]
      524276 blocks super 1.0 [3/3] [UUU]
      
md126 : active raid1 sdb4[1] sda4[0]
      1676161496 blocks super 1.2 [2/2] [UU]
      
md127 : active raid5 sde3[0] sdc3[3] sdf1[2] sdd1[4](S)
      1953381888 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
      [>....................]  reshape =  0.1% (2117632/1953381888) finish=1676.8min speed=19393K/sec
えええっ! 1676分!27時間じゃないですか!w ディスク2本のときは6時間だったので1本増えた分で9時間ぐらいかなと思ってたんですが甘かったですね・・・。これ6本になったら3週間ぐらいかかっちゃう!?

今さらだけど、RAID5/2 -> RAID6/4 にするのはエラーになったので、RAID5/2 -> RAID5/3 -> RAID 6/4 という道で行くことにしたんだけど、もしかしてRAID5/2 -> RAID5/4 なら一度で行けたのかな?もしできるなら RAID5/2 -> RAID5/4 -> RAID6/6 としたほうが reshape の数が少なくてよかったのかな・・・。それともやっぱりRAID5/2 -> RAID5/4 もエラー?

まあはじめてしまったのは仕方ないので、27時間待ちますw 問題は定期的に行われる resync? もこのぐらいかかるのだと一日では到底終わらないので困るんですがどうなんだろう。あとやっぱりこんなにかかるとなると、degradeしたときのRAID 5ってやっぱりこわいですね。冗長性を復活させるのに丸一日かかってたら、その間にもう一本やられちゃうこともありそうです。なのでRAID 6の安心にコストを払うのが正解という判断で。

そう思って一晩置いたところ、開始後15時間ほどでまだ50%ぐらいだったんですが、なぜか残り時間が220分とかになってますね。
# cat /proc/mdstat     
md127 : active raid5 sde3[0] sdc3[3] sdf1[2] sdd1[4](S)
      1953381888 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
      [==========>..........]  reshape = 53.5% (1045575200/1953381888) finish=220.5min speed=68608K/sec
その後もちょくちょくチェックしてたらスピードが最初のころの5倍とかのままでどんどん進んでいます。何か2フェーズにわかれてるのかな?

最終的に23時間ほどで完了しました。
# mdadm --detail /dev/md127
/dev/md127:
        Version : 1.2
  Creation Time : Fri Jan 24 09:11:13 2014
     Raid Level : raid5
     Array Size : 3906763776 (3725.78 GiB 4000.53 GB)
  Used Dev Size : 1953381888 (1862.89 GiB 2000.26 GB)
   Raid Devices : 3
  Total Devices : 4
    Persistence : Superblock is persistent

    Update Time : Sun Jan 26 16:38:19 2014
          State : clean 
 Active Devices : 3
Working Devices : 4
 Failed Devices : 0
  Spare Devices : 1

    Number   Major   Minor   RaidDevice State
       0       8       67        0      active sync   /dev/sde3
       2       8       81        1      active sync   /dev/sdf1
       3       8       35        2      active sync   /dev/sdc3

       4       8       49        -      spare   /dev/sdd1
ちゃんとサイズが4TBになっているのがわかりますね。すばらしい。さあいよいよRAID 6です。
# mdadm --grow /dev/md127 --level=6 --raid-devices=4 --backup-file=/root/raid.back
mdadm: level of /dev/md127 changed to raid6
# cat /proc/mdstat 
md127 : active raid6 sde3[0] sdc3[3] sdf1[2] sdd1[4]
      3906763776 blocks super 1.2 level 6, 512k chunk, algorithm 18 [4/3] [UUU_]
      [>....................]  reshape =  0.0% (96256/1953381888) finish=3719.6min speed=8750K/sec
      
わははw 3719分ということは61時間、約3日かかる計算ですw 実際はまた途中から早くなるかもしれないですけど。これは気長に待つしかないですね。

そして1日経過、まだまだw

2日経過、60%は越えましたが途中から早くなるかもという希望は打ち砕かれましたw

開始から2日半でようやく80%台を越え、残り976分と1000分を切りました!w

そして開始から3日と6時間ぐらいたったころ、ようやく完了しました。長かった・・・けどまだ2本追加するんですがw

終わる直前↓w
# cat /proc/mdstat 
md127 : active raid6 sde3[0] sdc3[3] sdf1[2] sdd1[4]
      3906763776 blocks super 1.2 level 6, 512k chunk, algorithm 18 [4/3] [UUU_]
      [===================>.]  reshape = 99.9% (1952316928/1953381888) finish=3.3min speed=5360K/sec

2014年1月28日火曜日

自己満足的自宅サーバーディスク構成変更(4)~RAID 6の元になるアレイの作成

さていよいよ最終的にはでかいRAID 6のアレイに育てるアレイを作ります。まず外したアレイのメンバだった2.0TBのディスクを全体で1つパーティションを切ります。(全体なので切らなくてもいいような気もしますが、これより大きいディスクでサイズをあわせやすくするために一応切っておきます。)そして3.0TBのディスクはシステム部分が入っているとはいえ2.0TB以上あまっているので、ここに同じサイズのパーティションを作成しました。
(parted) unit b                                                           
(parted) print                                                            
Model: ATA WDC WD30EZRX-00D (scsi)
Disk /dev/sde: 3000592982016B
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start          End             Size            File system  Name  Flags
 1      1048576B       537919487B      536870912B      ext4               raid
 2      537919488B     275415826431B   274877906944B                      raid
 3      275415826432B  2275813621759B  2000397795328B                     raid

(parted) select /dev/sdf
Using /dev/sdf
(parted) print                                                            
Model: ATA WDC WD20EARX-00P (scsi)
Disk /dev/sdf: 2000398934016B
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start     End             Size            File system  Name  Flags
 1      1048576B  2000398843903B  2000397795328B                     raid

このように1バイト単位まで同じです。さていよいよ「ディスク2本のRAID 5」は作れるのか!?

# mdadm --create /dev/md5 --level=5 --raid-devices=2 /dev/sde3 /dev/sdf1
mdadm: /dev/sdf1 appears to be part of a raid array:
    level=raid1 devices=2 ctime=Tue Jan  1 10:32:54 2013
Continue creating array? y
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md5 started.

# cat /proc/mdstat 
Personalities : [raid0] [raid1] [raid6] [raid5] [raid4] 
md5 : active raid5 sdf1[2] sde3[0]
      1953381888 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/1] [U_]
      [>....................]  recovery =  0.1% (3436876/1953381888) finish=389.9min speed=83342K/sec

むむっ、拍子抜けするぐらい普通に作れたんですけどw あ、小さい領域で実験してからにすべきだったか・・・。しかも2.0TB2本で389分ということは、6本全部構成し終わったらresyncに1200分、つまり20時間かかる計算!?w

というわけで、20時間待って失敗は悲しいので、小さい領域で実験してみることにしました。まずは4つパーティションを用意します。
(parted) unit gib
(parted) mkpart primary 1 2                                               
(parted) mkpart primary 2 3
(parted) mkpart primary 3 4
(parted) mkpart primary 4 5
(parted) set 1 raid on
(parted) print                                                            
モデル: ATA M4-CT128M4SSD2 (scsi)
ディスク /dev/sdd: 119GiB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos

番号  開始     終了     サイズ   タイプ   ファイルシステム  フラグ
 1    1.00GiB  2.00GiB  1.00GiB  primary                    raid
 2    2.00GiB  3.00GiB  1.00GiB  primary                    raid
 3    3.00GiB  4.00GiB  1.00GiB  primary                    raid
 4    4.00GiB  5.00GiB  1.00GiB  primary                    raid
違うマシンでやったのでロケールが日本語になってますがご容赦を。さてパーティションは切れたので早速RAID 5のアレイを作ってみます。実際と同様に2台です。
# mdadm --create /dev/md0 --level=5 --raid-devices=2 /dev/sdd1
/dev/sdd2
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md0 started.
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd2[2] sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/1] [U_]
      [====>................]  recovery = 24.1% (253736/1047552) finish=0.1min
speed=84578K/sec
      
# mkfs.ext4 /dev/md0
# mount /dev/md0 /mnt/tmp
ファイルシステムも作ってマウントしました。念のためということでそこにランダムなデータのファイルを作り、それを別のパーティションにもコピーしておきます。
# dd if=/dev/urandom of=random.dat count=1800000
$ cp /mnt/tmp/random.dat .
さあ準備はできたのでいよいよ1パーティション壊してみましょう。まずは fail にしてから remove です。
# mdadm --fail /dev/md0 /dev/sdd2
mdadm: set /dev/sdd2 faulty in /dev/md0
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd2[2](F) sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/1] [U_]

# mdadm --remove /dev/md0 /dev/sdd2
mdadm: hot removed /dev/sdd2 from /dev/md0
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/1] [U_]
無事抜けました。この状態でも degraded ですが動いている(はず)。さっきコピーしておいたファイルとマウントしているところにあるファイルを比べてみると
$ diff random.dat /mnt/tmp/random.dat 
$
おお、問題なさそうですね!念のためその外したディスクは別のデータで上書きしてみます。
# mkfs.ext4 /dev/sdd2
# mount /dev/sdd2 /mnt/tmp2
# ls /mnt/tmp2/
lost+found

$ diff random.dat /mnt/tmp/random.dat 
$
やはり問題はないです。すばらしい。 さていよいよ本題のRAID 6への変換です。 先ほど外したパーティションを戻してから、さらに2つのパーティションを追加します。
# umount /mnt/tmp2
# mdadm --add /dev/md0 /dev/sdd2
mdadm: added /dev/sdd2
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd2[2] sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/1] [U_]
      [=============>.......]  recovery = 68.6% (720256/1047552) finish=0.0min
speed=102893K/sec

# mdadm --add /dev/md0 /dev/sdd[34]
mdadm: added /dev/sdd3
mdadm: added /dev/sdd4
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd4[4](S) sdd3[3](S) sdd2[2] sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [2/2] [UU]

# mdadm --detail /dev/md0
/dev/md0:
    Number   Major   Minor   RaidDevice State
       0       8       49        0      active sync   /dev/sdd1
       2       8       50        1      active sync   /dev/sdd2

       3       8       51        -      spare   /dev/sdd3
       4       8       52        -      spare   /dev/sdd4
はい。2台追加されてスペアとなっています。これを4台のRAID 6に・・・と思ったらエラーになりました。1台ずつしかできないのかな?とにかく1台ずつ行きます。3台ではまだRAID 6にできないので、まずは3台のRAID 5にします。
# mdadm --grow /dev/md0 --raid-devices=3
mdadm: Need to backup 1024K of critical section..
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid5 sdd4[4] sdd3[3](S) sdd2[2] sdd1[0]
      1047552 blocks super 1.2 level 5, 512k chunk, algorithm 2 [3/3] [UUU]
      [=====>...............]  reshape = 26.1% (273920/1047552) finish=0.4min
speed=30321K/sec

なんか Need to backup... って言われたのでコマンドはrejectされたのかと思いきや普通にRAID 5への変換が行われました。いいねいいね。終わったらいよいよRAID 6への変換です。
# mdadm --grow /dev/md0 --level=6 --raid-devices=4
mdadm: level of /dev/md0 changed to raid6
mdadm: /dev/md0: Cannot grow - need backup-file
mdadm: aborting level change

おお、今度はちゃんとrejectされました。バックアップファイルを指定して再実行です。
# mdadm --grow /dev/md0 --level=6 --raid-devices=4
--backup-file=/home/raid.back
mdadm: level of /dev/md0 changed to raid6
# cat /proc/mdstat 
Personalities : [raid1] [raid0] [raid6] [raid5] [raid4] 
md0 : active raid6 sdd4[4] sdd3[3] sdd2[2] sdd1[0]
      2095104 blocks super 1.2 level 6, 512k chunk, algorithm 18 [4/3] [UUU_]
      [>....................]  reshape =  1.5% (16384/1047552) finish=2.0min
speed=8192K/sec

すばらしい。うまくいきました。

でもこれってつまり2台追加するときは2回 reshape するってことよね。2.0TBが2台で6時間として、3台は9時間、4台は12時間、5台は15時間、6台が18時間、それぞれ全部やらないといけないということは合計39時間w

2014年1月26日日曜日

自己満足的自宅サーバーディスク構成変更(3)~システムパーティションの移動

前回LVMから外した3.0TBのディスクに/bootと/を持ってきます。切りなおしてファイルコピーでもいいんですが、せっかくなのでRAID 1の機能を使って行きましょう。

まず現状を確認です。
# parted
GNU Parted 2.1
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit b                                                           
(parted) print                                                            
Model: ATA WDC WD20EARS-00M (scsi)
Disk /dev/sda: 2000398934016B
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start          End             Size            Type     File system  Flags
 1      1048576B       537919487B      536870912B      primary  ext4         boot, raid
 2      537919488B     9127854079B     8589934592B     primary               raid
 3      9127854080B    284005761023B   274877906944B   primary               raid
 4      284005761024B  2000396321279B  1716390560256B  primary               raid

(parted) select /dev/sde
Using /dev/sde
(parted) print                                                            
Model: ATA WDC WD30EZRX-00D (scsi)
Disk /dev/sde: 3000592982016B
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start           End             Size            File system  Name  Flags
 1      1048576B        2000398843903B  2000397795328B                     raid
 2      2000398843904B  3000592498687B  1000193654784B

(parted)
ここでsdaの1と3が/bootと/なのでこれと同じサイズのパーティションを作成します。
(parted) rm 1                                                             
(parted) rm 2                                                             
(parted) unit mib                                                         
(parted) mkpart                                                           
Partition name?  []?                                                      
File system type?  [ext2]?                                                
Start? 1                                                                  
End? 513                                                                  
(parted) mkpart                                                           
Partition name?  []?                                                      
File system type?  [ext2]?                                                
Start? 513                                                                
End? 262657                                                               
(parted) set 1 raid on                                                    
(parted) set 2 raid on                                                    
(parted) unit b                                                           
(parted) print                                                            
Model: ATA WDC WD30EZRX-00D (scsi)
Disk /dev/sde: 3000592982016B
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start       End            Size           File system  Name  Flags
 1      1048576B    537919487B     536870912B                        raid
 2      537919488B  275415826431B  274877906944B                     raid

(parted) 
これでサイズも全く同じパーティションができました。これをアレイに追加します。
# mdadm --add /dev/md0 /dev/sde1
mdadm: added /dev/sde1
# cat /proc/mdstat 
Personalities : [raid0] [raid1] 
md0 : active raid1 sde1[2](S) sdb1[1] sda1[0]
      524276 blocks super 1.0 [2/2] [UU]

スペアとして追加されてることがわかります。それを3台構成のRAID 1として定義しなおします。
# mdadm --grow /dev/md0 --raid-devices=3
raid_disks for /dev/md0 set to 3
# cat /proc/mdstat 
Personalities : [raid0] [raid1] 
md0 : active raid1 sde1[2] sdb1[1] sda1[0]
      524276 blocks super 1.0 [3/2] [UU_]
      [============>........]  recovery = 62.5% (327680/524276) finish=0.0min speed=109226K/sec
問題なさそうですね。同じことを / 用のアレイにも行えば /boot と / を3.0TBのディスクに移動したのと等価になります。

さて、あとは忘れずにこのディスクにもGRUBを入れなければいけません。
grub> root (hd4,0)
root (hd4,0)
 Filesystem type is ext2fs, partition type 0x83
grub> setup (hd4)
setup (hd4)
 Checking if "/boot/grub/stage1" exists... no
 Checking if "/grub/stage1" exists... yes
 Checking if "/grub/stage2" exists... yes
 Checking if "/grub/e2fs_stage1_5" exists... yes
 Running "embed /grub/e2fs_stage1_5 (hd4)"... failed (this is not fatal)
 Running "embed /grub/e2fs_stage1_5 (hd4,0)"... failed (this is not fatal)
 Running "install /grub/stage1 (hd4) /grub/stage2 p /grub/grub.conf "... succeeded
Done.
果たしてこれで立ち上がってくれるのか?

一応確認のため、UEFIの起動順をこのディスクに変えて起動。大丈夫そうです。まあ厳密には他のディスクを外してみないと、本当にこのディスクだけから立ち上がってるかどうかの確認はできてないですが。

最後の仕上げで、今は3台のRAID 1になってるので、それから1台抜いて2台に戻します。
# mdadm --fail /dev/md0 /dev/sda1
mdadm: set /dev/sda1 faulty in /dev/md0
# cat /proc/mdstat 
Personalities : [raid0] [raid1] 
md0 : active raid1 sdb1[1] sde1[2] sda1[0](F)
      524276 blocks super 1.0 [3/2] [_UU]

# mdadm --remove /dev/md0 /dev/sda1
mdadm: hot removed /dev/sda1 from /dev/md0
You have new mail in /var/spool/mail/root
# cat /proc/mdstat 
Personalities : [raid0] [raid1] 
md0 : active raid1 sdb1[1] sde1[2]
      524276 blocks super 1.0 [3/2] [_UU]

# mdadm --detail /dev/md0
/dev/md0:
        Version : 1.0
  Creation Time : Fri Dec 21 23:57:28 2012
     Raid Level : raid1
     Array Size : 524276 (512.07 MiB 536.86 MB)
  Used Dev Size : 524276 (512.07 MiB 536.86 MB)
   Raid Devices : 3
  Total Devices : 2
    Persistence : Superblock is persistent

    Update Time : Fri Jan 24 08:24:51 2014
          State : clean, degraded 
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

    Number   Major   Minor   RaidDevice State
       0       0        0        0      removed
       1       8       17        1      active sync   /dev/sdb1
       2       8       65        2      active sync   /dev/sde1
一瞬 degraded になりますが(当然メールも飛びますが)、2台体制に戻します。
# mdadm --grow /dev/md0 --raid-devices=2
raid_disks for /dev/md0 set to 2
# mdadm --detail /dev/md0
/dev/md0:
        Version : 1.0
  Creation Time : Fri Dec 21 23:57:28 2012
     Raid Level : raid1
     Array Size : 524276 (512.07 MiB 536.86 MB)
  Used Dev Size : 524276 (512.07 MiB 536.86 MB)
   Raid Devices : 2
  Total Devices : 2
    Persistence : Superblock is persistent

    Update Time : Fri Jan 24 08:26:04 2014
          State : clean 
 Active Devices : 2
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 0

    Number   Major   Minor   RaidDevice State
       1       8       17        0      active sync   /dev/sdb1
       2       8       65        1      active sync   /dev/sde1

これで問題なく移動が完了しました。/ 用のアレイについても同様に処理しました。

まあこの移行の間にディスクが故障するってことを警戒しなければ、3つにして1つ抜くなんてしないでいきなり1つ抜いて別のと sync すりゃいいんだと思うんですが、基本ディスクは壊れるものという信念で作業しておりますw

2014年1月25日土曜日

自己満足的自宅サーバーディスク構成変更(2)~LVMからアレイを外す

それでは<お約束>ここに書かれていることを試す場合はデータをバックアップし、自己責任でお願いします。間違い等があっても責任は負いません。</お約束>

さて、まずは領域をあけます。ディスク上の不要なデータを削除して、なんとか2.5TBぐらいは開き領域を作成しました。つまり4TB程度はデータがある状態になります。Logical Volume Management を開き、必要ならLVのサイズを減らし、空きextentを確保します。この状態で、除去しようとしているアレイから使用中の extentを他のアレイに移動しなければいけません。早速行ってみましょう。

まず除去しようとしているアレイを Physical View でポイントします。すると以下のような絵が出てくると思います。この時点で全部が"Unused Space"だったら今すぐにでも除去できるわけですが、たいていの場合このように使用中になっていると思います。その場合は移動したいextent、下だとlv_shareが割り当てられているところをクリックします。あ、もちろんこの時点で他のPhysical Volumeに今選んでいる領域が使っているextentの数以上の空きextentがあることは確認してください。大丈夫であれば"Migrate Selected Extent(s) From Volume"をクリックします。


すると、確認のダイアログが出ます。

ここで適当に移動してもらってもいい場合は Automatically ... で、指定したい場合は Destination を選んでいざ OK を押します。

あれ、今さら気づいたけど、"Only migrate extends belonging to LV" ってのがチェックされてないってことは、もしかしてこれって選択してる領域にかかわらず全部移動するのかな?未確認。もし複数のLVがある場合はお気をつけください。

ともかくこれを実行してのんびり待つと空のPhysical Volumeとなります。今回の場合は2時間ぐらい後に見たら終わってました。
 こんな感じに全部が Unused Space になったらあとは"Remove Volume from Volume Group"をクリックするだけです。こちらはすぐに終わります。

せっかくなのでアレイの停止とかもGUIでやってみますか。Disk Utilityを開いて"Stop RAID Array"を押します。これは慎重に。間違えちゃだめなやつですよね?w
これでアレイは停止状態になりました。ちなみにコマンドでは mdadm -S <device> ですね。

自己満足的自宅サーバーディスク構成変更(1)~計画

先日のエントリで会社の開発機に起きた顛末をつらつらと書き連ねましたが、無事復活したことで急に家のサーバーのディスクは大丈夫かいなと思い始めました。ディスクの稼動時間なら会社のやつに負けないよ?いっぱい壊れてるかもよ?w

早速帰宅して調べたところ、すばらしいことにどのディスクも1つも不良セクタはないようです(ディスクが気づいてないだけかもw)。一番長いやつで 3.4 years となっているので3年以上稼動しているようですが。とりあえずそんなひどい状況ではないようです。

自宅サーバーはこんな感じでRAID 1のアレイをいくつか作り、それをLVMで取りまとめていたわけですが、今回LinuxのソフトウェアRAIDの便利さに感銘を受けたので、もっと使い込もうかなと。しかも当時誤解していたのか、ソフトウェアRAIDって0/1/10ぐらいしかできないと思ってたのに5や6もできるんですね。Linuxすばらしい。

現状のディスクはちょっとずつ買ったせいでサイズはまちまちです。
  1. 2.0TB (/boot, swap, /, pv(1))
  2. 2.0TB (/boot, swap, /, pv(1))
  3. 2.5TB (pv(2))
  4. 2.5TB (pv(2))
  5. 3.0TB (pv(3), data)
  6. 2.0TB (pv(3))
/boot, /, pv(1), pv(2), pv(3) はすべてRAID 1、swap は RAID 0、data は素の領域となっています。これをもっと改善できないかな?

/boot や / は何もディスクをケチるほど大きくないので RAID 1 のままでよいとして、他はせっかく6台もあることだし、RAID 5/6 にしたいですよね。私は個人的にはRAID 5が嫌いなので6にしたいかなと。もし/bootや/を2.5TBや3.0TBのディスクに移動できれば、2.0TBx6(RAID 6)=8.0TB になるわけで、現状の約6.0TBから2.0TBも増やせた上に冗長性が高くなります。これはやらない手はない。なぜRAID 5が嫌いかというと、5ってリビルドの負荷がかなり高くて、その間に大丈夫だったディスクがやられちゃうのが怖いのです。 6なら仮にそれがおきてもさらに1台やられない限り大丈夫なので気持ちの余裕が違うかなと。

しかしやるとなっても、システムには既にデータが数TBオーダーで置いてあるので、退避して戻すのは不可能。そんなでかいストレージは他にないです。なのでオンラインで変更できるわけもないし無理かなーと思っていたのですが、できそうなんですよ。確かに言われて見ると、「2台のRAID 5」=「RAID 1」なわけで、それをRAID 5、さらに6と上げていくのは技術的には可能でおかしくはないか。このあたりを読むとRAID 5から6への変更は mdadm コマンドでできるっぽいので、もしかしたらRAID 1から5もできたりしないのかな?

しかし、それができるとわかっても、やっぱりデータが載ってるRAID 1のアレイをリンク先の手順に書いてあるように一度消して作り直すのはちょっと怖い。なので、やるなら以下の方法がいいかなと思ったわけです。
  1. 現状LVMに参加しているアレイの最大サイズ(2.5TB)の分だけなんとか領域をあける
  2. そのアレイをLVMから抜く
  3. そのアレイをRAID5/2(RAID5の2台の意)にする
  4. 再びLVMに参加
  5. 別のアレイをLVMから抜く
  6. そのアレイを壊して3で作ったアレイに追加し、RAID5/2+2(RAID5の2台+スペア2台)
  7. RAID5/2+2をRAID6/4に変更
  8. 最後のアレイをLVMから抜く
  9. そのアレイを壊して7のアレイに追加し、RAID6/6に変更
 いやこれはまた壮大ですねw

しかも理想的には最低サイズ(2.0TB)にあわせてアレイを構築したほうがいいので、 /boot 等のシステム用のパーティションはでかいディスクに移したいわけです。まずはそこから手をつけるか?
  1. 3.0TBが参加しているアレイをLVMから抜く
  2. パーティションを切りなおし、既存の2.0TBのシステム用パーティションにあわせる
  3. RAID 1として参加させる
  4. GRUBをセットアップ
  5. 既存のディスクをアレイから抜く
基本これでいけるはず。じゃあアレイの構築とか相当時間がかかると思うのでのんびり行きますか。

2014年1月23日木曜日

再びディスクの話

おっと気づいたら2014年初エントリですね。つまりこんな感じで頻繁に書くものではないですが、今年もよろしくお願いします。

突然ですが、私はソフトウェア開発を生業としております。従って会社でもプログラムを書く仕事をしていて、机にはいわゆる「開発機」という開発専用のマシンを所有して(もちろん正確には貸与されて)います。会社は社員にノートPC(Windows)を貸与しているので日々の業務アプリケーション等は Windows が基本ですが、WindowsでないとできないものはノートPCでやればいいので、開発機は各自の自由な管理となっています。大半の人はWindowsですけどね。私はもちろんLinux - Red Hat Enterprise Linux を入れて活用しています。

その開発機もディスクが飛んですべて吹っ飛ぶのはいやなので、家のサーバーのように RAID 1 で冗長化しています。正確には、悲しいかな会社で使うマシンはうちのマシンより高いくせに貧弱(失礼)で、ディスクも 1.5TB/1.0TB/500GB を後生大事に使い続けるという状態なので、大事なデータを RAID 1 (1.5TB のうち 1.0TB と 1.0TB)と RAID 0 (1.5TB のうち 500GB と 500GB)で運用しています。しかもその1.5TBと1.0TBは前のマシンから転用してきたので結構前からあるやつです。

それが先週ふと GNOME の上のバーのところに、ディスクのアイコンに「!」がついてるアイコンがでていることに気づきました。最初は「何だろ?ディスクいっぱいにでもなったかな?」と思ったのですが、クリックしてみると

「ディスクが壊れかけています」(うろ覚え)

!!!
これはまずいと思いさらにクリックだかダブルクリックだかでディスクユーティリティーなるものが開くので見てみます。(余談ですが Linux もずいぶん便利になりましたよね。)すると、1.0TBのディスクの表示が既に「故障しています」になっているではないですか。 orz

どうも SMART の情報に何かあるということでクリックしてみると、"Reallocated Sector Count" という項目に赤が。ダメになって別のところが使われたと判定されたセクタの数ということですね。警告の出る閾値が確か100ぐらいだったんですがなんと2000越え。これは危険だ。仕方ないので交換用のディスクを注文し、翌日見ると3000越え。その翌々日見たら4000越えと日増しに増えてました。

とはいえ、上に書いたようにこのディスクは基本 RAID 1 のメンバーなので、最悪吹き飛んでもいいわけです。なのでのんびり見てたんですが、さすがにこんだけ増えてくるとなるともう外したほうがいいかと思って物理的に外しました。/proc/mdstat を見るとしっかり全部 degrade 状態に変化します。

秋葉原で買ってくれば即日なのに会社ってのは面倒なもんで、指定した業者から納品されたのは1週間後ぐらいでしたか。秋葉原で買ってくれば半額ぐらいなのに。 早速つないで RAID を再構築です。全く簡単な話で、既にあるアレイと同じか大きいパーティションを作成し、
# mdadm --add /dev/md127 /dev/sdb1
などとするだけです。しばらくして resync が終われば冗長性も完全復活です。

しかしですね、もうお分かりかと思うんですが、今さら同じサイズ(1.0TB)のディスク買う理由はないのですよ。というわけで今回買ったのは秋葉原なら普通に3.0TBや4.0TBも買えるのになぜか2.0TBの大容量!w つまり1.0TBも多いのです!(遠い目

なので、そのあまった分も RAID に組み入れたい、と思ったわけですが。当然アレイのサイズは変えられないし、別のアレイを作って LVM に追加かなぁと思っていたところ、アレイのサイズは変えられるんですね。Linux えらい。

詳細な手順は間違えているかもしれませんが、覚えている限りやったのは以下です。上の mdadm --add する前、既存のアレイが degraded の状態からです。
  1. 大きくしたいサイズでパーティションを切る(私の場合既存のアレイが800GB ぐらいでしたが、1.3TB ぐらいで切りました)
  2. mdadm --add して追加する
  3. mdadm --detail や /proc/mdstat 等で resync が終わるのを待つ
  4. mdadm --fail や物理的に外すなどで元の小さいパーティションをアレイから除く
  5. パーティションを切りなおす
  6. mdadm --add して追加する
この時点ではまだアレイのサイズは変わりませんが、アレイが乗っているディスクのサイズはどちらも増えた状態ということになります。なのでアレイのサイズを増やすことができます。
  1. mdadm --grow <device> -z max
これで使える最大サイズのアレイとなりました。実行する前と後で mdadm --detail <device> | grep Size などとすれば違いがわかると思います。

私はこのアレイをさらに LVM で使っていたので、PV としても大きくなってもらわなければ意味がありません。が、pvdisplay 等で見てもまだ前のサイズのままです。なのでもうひと手間かけましょう。
  1. pvresize <device>
これで無事 PV としても大きなサイズになりました。めでたしめでたし。

ちなみにパーティションのサイズは完全に一致している必要はありません。追加するほうがちょっと大きいぐらいなら無駄にはなりますが全く問題はありません。が、しかし、小さいとちょっと面倒です。先に大きいほうのパーティションでアレイを構築してしまうと、「アレイのサイズ」=「大きいほうのパーティションのサイズ」となってしまい、後から小さいのを追加すると怒られます。アレイのサイズを小さくすればいいのかもですが、大きくするのに比べて小さくするのはちょっと怖い感じですので・・・。(昔乗ってるファイルシステムよりLVを小さくしてぶち壊した経験ありますw)

さらになんでこのエントリが「自宅サーバー」ラベルなのか?それはこの出来事に触発されて自宅サーバーをいじることにしたからです。それはまた後日。

2013年10月15日火曜日

play-pac4j : Play! Framework 2.2 で OAuth(失敗 -> 2.1 では成功)

ちょっと前のエントリで Play! Framwork で twitter4j を使うのに SecureSocial というのを使ってみましたが、別のものということで今度は pac4j というのを使ってみます。定義によると
pac4j is a Profile & Authentication Client for Java (it's a global rebuilding of the scribe-up library)
だそうです。それをさらに Play! Framework から利用しやすいように play-pac4j というものがあるようですね。早速使ってみます。

まずは dependency の解決です。上のガイドに従うと、Twitter を使うためには、play-pac4j_java と pac4j-oauth が必要なようですね。Maven の central repo では最新はそれぞれ 1.1.1 と 1.4.1 です。以下のように build.sbt に追加します。(このファイル、2.x では project/Build.scala だったはずなんですが、変わったんですね・・・)

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "org.twitter4j" % "twitter4j-core" % "3.0.4",
  "org.pac4j" % "play-pac4j_java" % "1.1.1",
  "org.pac4j" % "pac4j-oauth" % "1.4.1"
)  

前回やったように、IntelliJ IDEA を一度止めて play idea してから開きなおすのが手っ取り早いようです。ではコードの変更です。
  1. コントローラーが継承しているクラスを Controller から JavaController に
  2. Global.onStart() で TwitterClient を登録
  3. ログインを要求したいコントローラーメソッドに @RequiresAuthentication を追加
  4. routes に callback を追加
具体的には
1
import org.pac4j.play.java.JavaController;

public class Application extends JavaController {
2
public class Global extends GlobalSettings {
    @Override
    public void onStart(Application application) {
        final TwitterClient twitter = new TwitterClient(CONSUMER_KEY, CONSUMER_SECRET);
        final Clients clients = new Clients("http://localhost:9000/callback", twitter);
        Config.setClients(clients);
3
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result top() {
4
# For pac4j
GET   /callback               org.pac4j.play.CallbackController.callback()
POST  /callback               org.pac4j.play.CallbackController.callback()
GET   /logout                 org.pac4j.play.CallbackController.logoutAndRedirect()
おお、結構作業量が少なくていい感じ。早速実行してみましょう。
[info] play - Application started (Dev)
Uncaught error from thread [play-akka.actor.default-dispatcher-7] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[play]
java.lang.AbstractMethodError
あっさりオワタw
まだ 2.2 がサポートされてないんですね。この方も嘆いてますが、Play! Framework ってバージョン間の互換性がなさすぎる・・・。

仕方ないので Play! Framework を 2.1.5 にしてみます。2.1.5 で play new して作った雛形から、Build.scala をコピーして、build.sbt 内に加えた変更を移動します。あとは念のため diff で差分が出た build.properties とか plugins.sbt とかを直していざテスト。

おっ!
うまくいきました。これは結構簡単。

最後にお約束の twitter4j のインスタンス作り。
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result login() throws TwitterException {
        final TwitterProfile profile = (TwitterProfile) getUserProfile();
        TwitterFactory factory = new TwitterFactory(new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY).setOAuthConsumerSecret(CONSUMER_SECRET).build());
        Twitter tw = factory.getInstance(new AccessToken(profile.getAccessToken(), profile.getAccessSecret()));
これでうまくいきました。

2013年9月30日月曜日

Heroku を試す(7)~ Play! Framework 2.2 を IntelliJ IDEA で動かしてみる

実は前の記事はだいぶ前に書いていて公開し忘れていたものでした。このたびもう一度使ってみようと思ったので、新しいエントリを書く前にとりあえず公開したものです。で、もう一度やろうとしたらいろいろバージョンも変わっていたので変化部分を。

まず前回はあきらめた git のバージョンですが、ちゃんとバージョンをあげておきました。

$ git --version
git version 1.7.11.3

これなら文句は言われまいw IntelliJ IDEA を起動しましたが、確かに何も警告は出ませんでした。勝った!(←何に?w)これで IDEA のほうも最新バージョンで進めます。

Play! Framework のほうですが、最新は 2.2.0 になっていました。なにやら嫌な予感が・・・。Play! Framework 自体は好きなんですが、バージョンアップ時の挙動が結構変わるのが難儀するんですよね。まあいいか、早速プロジェクトを作ってみます。


orz
こんな予想的中してもうれしくないw まだIDEAのプラグインが対応してないのかな。ここは気を取り直して、Play側から作って IDEA 対応を試みます。

$ play new sample-app
$ cd sample-app
$ play
[sample-app] $ idea

これを IDEA から開くと、無事開けました。

前回なぜはまらなかったのか不明ですが、デフォルトでは起動すると 9000 番ポートにつなぎに行きます。しかし他のアプリケーションで使っていると当然失敗します。直接コマンドラインから指定するときは

$ play run --http.port=9001

のようにすればいいのですが、IDEA からの起動だと play に直接コマンド渡せるわけではないので。結論としては Run/Debug Configurations のところで、Play 2 の起動構成を出し、 JVM Options に -Dhttp.port=9001 のように足せばポートが指定できます。

これで起動、デバッグ、あとは heroku へのデプロイ等は問題なくできました。しかし初回の push は長い・・・。いろんなライブラリの解決してるからっぽいですけど。あとはデータベースへの接続やバージョン管理(GAEで version.application.appspot.com で試せるやつのような)のやり方を学ばねば。

2013年9月29日日曜日

Heroku を試す(6)~ Play! Framework 2.0 を動かしてみる

さてなんとなく感じがつかめてきたところで今度は Play! Framework を使ってみようと思います。せっかくなのでちゃんと対応している(はずの)IntelliJ IDEA を使ってみましょう。Eclipse でやると結局のところ Java 以外のところはテキストエディタとして使うことが多くていまいち便利になった感がないので。

早速起動してプロジェクトを作成・・・ってあれ?前はここに Play! って出てた気がしたんですが・・・。恐らく完全な気のせいで、プラグインを入れなければいけないようです。それじゃ Eclipse と同じとかは思わないことにしますさくっと入れますw すると、おお、確かにでてきましたね!

実は最初何度やってもバージョンを変えてもうまくいかなくて相当悩んだんですが、ここに問題があがっていてこれかと思って普通にコマンドラインから play new してもエラーになったんです。なんだろうと思ったら Play! Framework 自体を /opt (つまり書き込み不可な場所)に入れていたのが原因だそうで。どうせ読み書き可能にしなきゃいけないのならユーザーのディレクトリに入れて指定したところうまくいきました。この思想がいいかどうかは別として。

さてこれを Heroku に上げてみましょう。Heroku のほうPlay! Framework のほうと両方に異なる文書がありますが、スクロールバーが短い(w) Play! のほうにしたがってみます。

まずは Store your application in git の部分。git コマンドをたたけばいいわけですが、IDEA から行きましょう。VCS > Import into Version Control > Create Git Repository で・・・

orz

厳しいっすw

git は rpm 経由で入れていて上げるのはまあまあ面倒なので、12.0.1 を再度引っ張り出してきて構成しました。するとコマンド自体は動いていたのか、既に git の管理下になっているようです。

では heroku の設定を。
$ heroku create sdk0815-sample2
Creating sdk0815-sample2... done, region is us
http://sdk0815-sample2.herokuapp.com/ | git@heroku.com:sdk0815-sample2.git
Git remote heroku added
これでリモートがセットされたはず。 しかし
$ git push heroku master
Warning: Permanently added the RSA host key for IP address '50.19.85.154' to the list of known hosts.
error: src refspec master does not match any.
error: failed to push some refs to 'git@heroku.com:sdk0815-sample2.git'
うーむ。これは何のエラーだろう。いろいろ調べたらどうやら何も push するものがないときに出るエラーみたいですね。 git commit したら確かにコミットされたので commit まではされてなかったんですね。
#IDEA からやるべきだったんですがついコマンド打っちゃいました。プロジェクトを右クリックで Git > Commit Directory... で全部 commit できます。

さて今度は push したらずっと待たされました。いけー。どりゃー。おおおお!

やったー!・・・ってあれ、こんな殺風景なはずは・・・w

どうもフレームワーク動いてないですね、これ。前に作ったときにあった Procfile にあたるものが必要なのかも。と思ったらちゃんと書いてありました。 これを作って再度挑戦です。また待たされました。いつ終わるのかな~。終わった!

変化なしw

よく考えてみると、この "Your new application is ready." という文字列って、ソースコードの中では
@(message: String)

@main("Welcome to Play 2.1") {
    
    @play20.welcome(message, style = "Java")
    
}

となっていて、文字列はコントローラである Application.java から送られてきています。ということはフレームワークは動いているということかな? @play20 というカスタムタグ(?)が動いていないようだと。

まあちょっと玉虫色な感じもしますが、とりあえず動かせるところまではもってこれました。実際に何か作るかは意欲と時間とネタ次第です。

2013年8月2日金曜日

IntelliJ IDEA で maven の dependency を解決する

ほんのちょっとした Tips 的ですが、しばらく悩んだので。

IntelliJ IDEA で Maven Module を指定して Project を作成します。ここまではよし。しかし実際に作成された pom.xml に dependency を追加する方法がわかりませんでした。すると、いくつか方法はあるようですが、そのうちの1つはエディターから Alt+Enter 等で出てくるメニューから "Add Maven Dependency..." を選べばよいと。ふむふむ。出てくるダイアログで文字列検索すれば・・・
 でてこない。 orz
全く出てこないわけではなく、何も入れてないときは ant とか commons なんとかとかそのへんは出てるんですよね。うーむ。どうもローカルにあるリポジトリだけを見てるっぽいですね。

そんなときは File > Settings から Maven > Repositories を選ぶと以下のような画面になるので、central repo を選んで Update を押せばよいようです。
その後同じ操作をすると、
めでたしめでたし。

2013年6月26日水曜日

Play! Framework で twitter4j を使う

久しぶりにちょっと時間ができたので遊んでみました。

表題のとおりです。とりあえず OAuth でログインできるところまで行きたいですね。

まずは twitter4j を追加します。これまでは jar をコピーしていたのですが、そんなことするよりずっと簡単な方法があります。Managed Dependency という項に書かれているように Build.scala に依存を書けば勝手に解決してくれます。フレームワークって大事ですね。
  val appDependencies = Seq(
    "org.twitter4j" % "twitter4j-core" % "3.0.3"
  )
これだけ・・・。便利になりました。

早速コードを書き始めると・・・おや、Play! を再起動しても IntelliJ IDEA では解決してくれないですね。うーむ。File > Invalidate Caches なんかもやってみましたがだめです。どうやら
$ play idea
を実行しないとだめみたいです。このへんはもう少し便利になってくれるとうれしいですけどね。まあこれで特に問題はないです。

では OAuth のページを作成しましょう。

と思ったらなんか便利そうなものを見つけました。 ここに書かれている SecureSocial なるものを使ってみますか。また dependency をつけます。
  val appDependencies = Seq(
    "org.twitter4j" % "twitter4j-core" % "3.0.3",
    "securesocial" %% "securesocial" % "master-SNAPSHOT"
  )

  val main = play.Project(appName, appVersion, appDependencies).settings(
    // Add your own project settings here
    resolvers += Resolver.url("sbt-plugin-snapshots", new URL("http://repo.scala-sbt.org/scalasbt/sbt-plugin-snapshots/"))(Resolver.ivyStylePatterns)
  )
この時点では Play! 2.1 には spapshot を使えとあるのでそうしてみました。これで同じように play idea も実行して解決させておきます。routes は書いてあるものそのままで。play.plugins からは不要な Provider を消します。
9994:securesocial.core.DefaultAuthenticatorStore
9995:securesocial.core.DefaultIdGenerator
9997:securesocial.controllers.DefaultTemplatesPlugin
9998:service.InMemoryUserService
10000:securesocial.core.providers.TwitterProvider
こんな感じで。あ、sample から InMemoryUserService を持ってきました。動作確認に使えます。次に securesocial.conf を作って application.conf から include します。
securesocial {
  onLoginGoTo=/
  onLogoutGoTo=/login
  ssl=false

  twitter {
     requestTokenUrl="https://twitter.com/oauth/request_token"
     accessTokenUrl="https://twitter.com/oauth/access_token"
     authorizationUrl="https://twitter.com/oauth/authenticate"
     consumerKey="****"
     consumerSecret="****"
  }
}
いよいよ実行です・・・。とその前に、ログインしてないとだめなメソッドに @SecureSocial.SecuredAction アノテーションをつけます。
    @SecureSocial.SecuredAction
    public static Result index() {
        Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
        final String userName = user != null ? user.fullName() : "guest";
        return ok(index.render("Logged on as " + userName + "."));
    }
では実行です。/login にアクセスすると
まずはこのようにログインの画面が出ます。ここで t のアイコンをクリックするといつものツイッターの認証画面に飛ばされます。そこで認証を行うと
のようになります。やったー。・・・ツイッターだけだと正直楽になったかどうか微妙ですがw ほかのサービス(facebook とか)でもログインできるのでその手のサービスを作りたいときは便利なのは間違いないですね。

さてこれでログインはできましたが、twitter4j が使えなければ意味がないわけで。ログインした後に実行されるメソッドの中身を変えます。

        String ret = "Unknown";
        Identity user = (Identity) ctx().args.get(SecureSocial.USER_KEY);
        if (user != null) {
            Twitter twitter = new TwitterFactory().getInstance();
            twitter.setOAuthConsumer(Play.application().configuration().getString("securesocial.twitter.consumerKey"),
                    Play.application().configuration().getString("securesocial.twitter.consumerSecret"));
            AccessToken accessToken = new AccessToken(user.oAuth1Info().get().token(), user.oAuth1Info().get().secret());
            twitter.setOAuthAccessToken(accessToken);
            User u = twitter.verifyCredentials();
            ret = "Logged on as " + u.getName() + "(@" + u.getScreenName() + ") followed by " + u.getFollowersCount() + " followers.";
        }
        return ok(index.render(ret));
実行すると・・・
 できたー。

2013年5月24日金曜日

Heroku を試す(5)~コードを変更してデプロイしてみる

ずいぶん間があいてしまいました。興味の向く先がいろいろ変わるのはいいのか悪いのかわからないですが・・・。前々回の続きです。

しかしこのページ、殺風景ですね。
と思ったら
 あらら、エラーになってますね。早速直してみましょう。

直すためにはどうやってこのコードが動いているのかを知る必要があります。ソースコードを開いてみます。右にあるように、Main.java と HelloServlet.java があります。どう見ても Main が怪しい(w)ので開いてみると、思いっきり main メソッドがありますね。へぇ、これって任意の(サーブレットコンテナだけでなく)Java コードを実行できちゃったりするんですかね?それはそれで面白いような怖いような・・・。

ひとつ疑問なのは、この main メソッドをどうやって見つけているのか、ということ。これがわからないと間違ってどこかのクラスに main メソッドを作ってしまうととたんにアプリが動かなくなったりということもありうるのでは。ファイルを眺めていると大体のファイルは予想がつくものですが、中に Procfile なるファイルがあります。これは何だろう。
web:    java $JAVA_OPTS -cp target/classes:target/dependency/* com.example.Main
ほほう。どうやらこれがその答えだったようですね。なので一安心w

で、本題の修正です。もう twitter.github.com は twitter.github.io に変わっているために殺風景なページになっているのでしょうね。ローカルで編集して試します。Main クラスを Java Application として起動します。Eclipse 内では m2e のおかげでクラスパス等は解決されているはずです。 起動しました。8080 にアクセスしたらちゃんと同じページが出てきます。よしよし。Edit > Find/Replace で github.com を github.io に Replace します。保存してリロードすると・・・
めちゃめちゃ今どきになったじゃないですかw

さてこの変更をコミットしましょう。チュートリアルに戻って、まずは変更をコミットです。それから Push to Upstream をクリックしてしばし待ちます。すると無事サイトのほうも更新されます。なるほど。