WHEREに転職しました。

2年半お世話になったサイバーエージェントを先月一杯で退職し、本日からWHEREではたらくことになりました。

サイバーエージェントでの2年半

ざっくり三つの部署を渡り歩きました。

初めての大企業、大規模サービスでしたが、それに見あった経験を得ることができて、採用を決めて頂いたHさん、Sさん、Tさんには今でも感謝が絶えません。

担当システム外としては、社内チューニンガソンで優勝させてもらったり、某クソコラ職人氏と一緒にうるう秒反対対応などやったりしていました。

まあ割とフリーダムにやらせて頂いていただきました。

転職の理由

端的に言うと知人からの引き抜きです。

転職先のWHEREは、測位技術によるジオソリューションを提供する会社です。観光や防災を主要なキーワードとしておもてナビというブランドを提供しています。また、昨年末に協和エクシオさんの子会社になりまして*1、測位技術を使って世の中を変えていきます。まずは2020年の東京オリンピックパラリンピックに向けて、全力全開、頑張ります。

転職の決め手は、日本での位置測位と言えば準天頂衛星です*2。宇宙ですね。

そんな感じです。はい。

よろしくおねがいします

再び開発メインに戻ってきました。早速Spring FrameworkとかMyBatisとか弄ってます。
中小企業がオンプレ持つ時代でも無くがりがりパブリッククラウドも使っていくので、各方面の皆様今後ともよろしくお願いいたします。

従業員としては離れることになりましたが、サイバーエージェントの皆様とも一緒に仕事ができる機会を作っていきたいので、そちらも末永く縁をつないでいければと思います。

C89

もう前日なのですが、コミックマーケット89に初参加します。
こんな感じの本だします。

東4のメ-34bに居ますので、お近くまでお越しの際はよろしくお願いいたします。

なお、これから印刷はじめつつ表紙作る感じです。

Advent Calendar つまみぐい Advent Calendar 12/01

技評さんがまとめてくださっている技術系Advent Calendarを見たら目玉飛び出るぐらい多すぎたので、自分の視野を広げることも兼ねて、適当に拾った中から紹介していくAdvent Calendarをやってみようと思います。それぞれの日の記事を紹介していくので、日付変わってからの更新です(という1日付けの記事を書いているのが3日という時点でお察しください)。

というわけで12/01付けの記事を上から順にだいたい全部見ていったら二日かかりました。

cmd.exe基礎

Windows & Microsoft技術 基礎 Advent Calendar 2015
なんだかんだでまだまだ使う事が多いWindowsのcmd.exeです。
Windows10でもかなりUI面が向上したのが話題になっていましたが、細かく機能が追加されていたりするのをあらためて発見しました。また、コードページをUTF-8に変更する方法も載っています。

MicrosoftのVisualStudioCodeがオープンソースになったので使ってみた

Visual Studio / Visual Studio Code Advent Calendar 2015
最近サーバサイドでコード書くことが多いのでまだ触っていないのですが、VSCode、かなり気になっています。

実例で学ぶ Julia-0.4.1

Julia Advent Calendar 2015
科学技術計算が得意なJulia言語の入門書がPDFでまるっと配布されています。
今年中に新しい言語を覚えたい人におすすめ。

日本語も美しく表示できるBootstrapテーマ Honoka が使いやすくなった

Bootstrap Advent Calendar
ホノカチャン!!
「企業サイトのベースにも使われるようにもなるなど」、広く普及していっているようです。個人的には宗教上の理由でNicoが気になっています。

仮想DOMで魂が震えてから一年、仮想DOMとFluxの今

仮想DOM/Flux Advent Calendar 2015
フロントエンド開発での仮想DOMの現状まとめです。話題になって一年経ちましたね。

手を動かしながら学ぶモダンなデータ操作とtidyなデータ(2015年版)

R Advent Calendar 2015
ビッグデータやらオープンデータやらで、データ処理の機会が増えています。
環境省が公開するデータを使いながら、「tidyデータ」というデータ形式とそれを扱うRパッケージでモダンなデータ操作を試す記事です。

PHP 7 リリース内容の確認

PHP Advent Calendar 2015
記事を書いている時点で既にタグが打たれたようですが、PHP 7のリリース内容のおさらいです。

知能と技術的特異点

人工知能 Advent Calendar 2015
昨今の機械学習アルゴリズムの普及などによってふたたびバズっている人工知能ですが、汎用人工知能についてその技術を紹介していくアドベントカレンダーのようです。
今年きっちり追いかけていきたいアドベントカレンダーの一つです。

Transifex Live Translation Pluginを使ったWordPressサイトの多言語化

WordPress Advent Calendar 2015
Transifexというウェブ翻訳プラットフォームがあるのを初めて知りましたが、そのなかのTransifex Liveというサービスを使ってWordpressを多言語化する記事です。
コンテンツ管理(CMS)と翻訳を機能として分けるのは新しい視点でした。

ハロー!! Office UI Fabric

Office UI Fabric Advent Calendar 2015
MITライセンスで公開されているCSSフレームワークOffice UI Fabricの紹介です。みんなだいすきBootstrapよりも「少しカッキリした(まさにオフィスアプリ的な)印象」というもののようです。

UXデザインからの卒業

UX Tokyo Advent Calendar 2015
UXという単語が氾濫し始めてだいぶたちますが、"「UI設計」と「UX調査」"というのは分かりやすかったです。

Live2D事始め!

Live2D Advent Calendar 2015
思いのほか簡単に作れるように見える……!

RubyとAWSでつくるメディアストレージ基盤

ドワンゴ Advent Calendar 2015
昨今はやっているAWSネイティブのアーキテクチャで作ったメディアストレージ基盤の、詳細な解説です。

Dockerとchrootを組み合わせたシンプルなコンテナデプロイツール

はてなエンジニアアドベントカレンダー2015
実際のアプリケーション運用を踏まえた上での、丁度良い落としどころとしてchrootを利用していくという議論です。

数学ド素人の社会人が独学する際のノウハウ

Qiita 数学 Advent Calendar 2015
最後に求められるのが数学の知識だったりしますが、復習するきっかけに!

PayPal Technical Slides

Payment Advent Calendar 2015
PayPalの技術スライドてんこもり。[あとで読む]。

「通信の最適化」の論点

論点書き出してみたけど多すぎて超絶カオス。

  • 現状発生している実害
  • 技術的詳細が非公開
  • 「最適化」という単語の是非
  • オプトインとオプトアウト
    • 送信者(コンテンツ提供者)の同意
      • 自衛のために全HTTPS化することで、かえってトラフィック増える問題
      • HTTPS化による計算機コスト、ファイル改竄による不具合対応のリスクの負担
      • サービス内容の意図しない/再現が難しい劣化*1
        受信者の財産権の侵害とも言える。
    • 受信者(顧客)の同意
      • 消費者保護観点からより深い内容周知の上での同意が必要では無いか
    • オプトアウトが可能かどうか
  • ISPとしてのサービスが土管であるべきか否か
    • 例えば、可逆圧縮での再圧縮なら良かったのかどうか
    • 携帯キャリアが提供しているのは「インターネット」サービスかどうか
  • ISPとしての正当業務行為に含まれるかどうか (以下の各種法令における違法性阻却事由)
  • アプリケーションレベルで内容を見ることが「通信の秘密」に触れるか否か
    • DPI議論
    • 帯域制御の運用基準に関するガイドライン
      • 帯域制御を目的するか否か
      • 「個別かつ明確な同意」があったかどうか
    • 電気通信事業法第四条
      • 特に「符号、音響又は影像」で音響と映像が切り出されていることの解釈
  • アプリケーションレベルで内容を変更することが「検閲の禁止」に触れるか否か
  • 著作権 (同一性保持権)
  • 公職選挙法
    • 「候補者のウェブサイトの改ざん等、選挙に関し、文書図画を毀棄し、その他不正の方法をもって選挙の自由を妨害」*2

判断ポイント

  • オプトアウトができれば良いのか
  • デフォルトoffで明確な利用者(端末契約者)のオプトインがあれば良いのか
  • 可逆圧縮での再圧縮なら良いのか
  • HTTPレスポンス本文のデコード結果を改変しないレベルなら良いのか
    • 例: HTTPレスポンスをTransfer-Encoding: gzip(delfate)にして圧縮する
    • 例2: HTTP/1.1のpersistent connectionやpipeliningで接続をまとめる
  • HTTPレスポンス本文は変更せずヘッダの改変だけなら良いのか
    • 例: Content-Length外してchunkにする

  • トランスポート層の壁>

  • TCPの再構成だけなら良いのか
  • パケットのフラグメント再構成*3なら良いのか

  • <極論の壁>

  • NAPTに必要なTCP/UDPのポート番号変更以外の全てのIPパケットペイロードの変更を禁じるのか(インターネット原理主義者)
  • NAPTも禁止し、IPパケットヘッダ以外の全ての変更を禁じるのか(真のInternet Protocol原理主義者)

*1:とくにニコニコ動画など「画質」によるフリーミアムモデルを採用している場合

*2:http://twitter.com/kei1_yama/status/624094538659860480

*3:例: PFのscrub

Linuxのうるう秒おさらい

7/1 午前9時(JST)にうるう秒が挿入されますが、注意すべきポイントのおさらいです。

うるう秒って何よ

NICTの資料の先頭7ページ目まで読んでください。

ざっくり言うと、現在の時計というのは「原子時計」が基準になっています。太陽の周りを回る公転周期に合わせて微調整するのがうるう年で、地球自体が回転する自転時間に合わせて微調整するのがうるう秒です。
現象としては、「月末」の日付が変わる直前に1秒追加されます。ただし、これはUTC(協定世界時)での話なので、日本標準時では9時間の時差があるので朝9時(の直前)になるわけです。

時間の進みを表にするとこんな感じです。

UTC(協定世界時) JST(日本標準時) うるう秒を知らない時計
2015年 6月30日 23時59分57秒 2015年 7月 1日 8時59分57秒 2015年 7月 1日 8時59分57秒
2015年 6月30日 23時59分58秒 2015年 7月 1日 8時59分58秒 2015年 7月 1日 8時59分58秒
2015年 6月30日 23時59分59秒 2015年 7月 1日 8時59分59秒 2015年 7月 1日 8時59分59秒
2015年 6月30日 23時59分60秒
うるう秒発生!
2015年 7月 1日 8時59分60秒 2015年 7月 1日 9時 0分 0秒
2015年 7月 1日 0時 0分 0秒 2015年 7月 1日 9時 0分 0秒 2015年 7月 1日 9時 0分 1秒
ここで1秒進んでしまう!
2015年 7月 1日 0時 0分 1秒 2015年 7月 1日 9時 0分 1秒 2015年 7月 1日 9時 0分 2秒
2015年 7月 1日 0時 0分 2秒 2015年 7月 1日 9時 0分 2秒 2015年 7月 1日 9時 0分 3秒
2015年 7月 1日 0時 0分 3秒 2015年 7月 1日 9時 0分 3秒 2015年 7月 1日 9時 0分 4秒

おわかり頂けただろうか。

本当はこわいうるう秒

前回のうるう秒は2012年7月1日(JST)に挿入されましたが、このときにLinuxカーネルでいくつかの不具合が判明しました。
一番影響が大きかったものが「CPU利用率が100%に張り付く」というもので、以下のブログ記事が詳しいです。

これは「不具合」による想定外の問題でしたが、そもそも「想定内」の範囲でも以下のような問題があります。

  • タイムゾーンの設定
    • Linuxでは、例えばJSTであれば right/Asia/Tokyo という特殊なタイムゾーンを設定した場合にのみ、59分60秒といううるう秒の時刻を取得できます。
    • Asia/Tokyo のままだと、59分59秒を二周します。IBMの技術記事の表記が分かりやすいので引用します。
      • 23:59:59.000000(→ 23:59:59.999999)→ 23:59:59.000000 → 00:00:00.000000 (小数点以下が 1 秒以下の時刻を表します。)
  • ログの前後関係の逆転
    • たとえば操作履歴の分析を想像して、手動で全力出しすぎて1秒以内に連続で操作したような場合、59分59秒を2周するような設定だと、操作の前後関係が逆転する可能性があります。
      • 8時59分59秒 800ミリ秒 操作A
      • 8時59分60秒 400ミリ秒 操作B → 8時59分59秒 400ミリ秒と記録され操作Aより前とみなされてしまう
    • また、監査ログの紐付けなどでも同様の問題が発生します。
  • 時刻が修正されるタイミングの不一致
    • 誤ったやり方でうるう秒を回避しようとした場合に発生します。
    • 広く使われているNTPソフトウェアでは、うるう秒の事前情報(後述するLeap Indicator)が無い場合には、時間のずれを検知してから15分間たってから一気に時刻を調整します。上位のNTPサーバに接続する間隔は、サーバの起動時間などの理由でバラバラなので、時刻が調整されるタイミングもバラバラになります。これではログ上の時刻突き合わせもできなくなり死ぬしかなくなります。

このように、きちんと考えると奥が深いのがうるう秒の処理です。

うるう秒を正しく扱う

比較的新しいサービスのみ面倒を見ているのであれば、おそらくうるう秒に起因する不具合もないでしょうから、全力でうるう秒を受け入れてあげるのが良いと思います。2012年以上前のディストリビューションでは上記不具合が修正されていない可能性がありますが、それ以外は特に何の問題も無く動くと期待されています。

「60秒」を保存できることを確認できているなら、right/Asia/Tokyo などのタイムゾーンに変更するとより良いです。

本来のうるう秒の処理

例えば、インターネットマルチフィードのNTPサーバから時刻を受信し、データセンター内の自前NTPサーバを立てているようなケースを想定すると、全体像は以下のようになります。

うるう秒の情報は、最終的には3つの方法で各サーバのLinuxカーネルに届きます。

1. 清く正しいLinuxカーネルうるう秒を処理

うるう秒の情報は、NTPのLeap Indicator(LI)というフラグを経由して各サーバに配布されます。最新のRFC上は一ヶ月前からフラグを立てても良いことになっていますが、NICTでは以前のRFC等も考慮してうるう秒の24時間前からフラグを立てる運用となっています。

Leap Indicatorを受け取ったNTPクライアントは、adjtimex(2)というシステムコールを呼んでLinuxカーネルうるう秒の情報を伝えます。Linuxカーネルはtime_stateという変数にそれを保存しておき、月末(UTC)になったらその変数を見て必要ならばうるう秒を挿入します。

カーネル内部のシステムクロックは正しくうるう秒を扱いますが、プロセスから現在時刻を聞かれたときには、right/Asia/Tokyo などうるう秒対応のタイムゾーンが設定されていれば、59分60秒という正しいうるう秒時刻を返し、そうでなければ59分59秒を2周するような時刻を返すようになります。2周する場合も、カーネルにより厳密にループが行われるので午前9時0分0秒(JST)になることなく繰り返されます。

標準ntpdのデフォルト設定(STEPモード)ではこの動作となります。また、ChronyではSLEWモードで設定をしていてもLinuxカーネル側でうるう秒を挿入するようです。

万が一、カーネルうるう秒情報を受け取ってしまった後になって回避策を実施したい場合は、ntptimeコマンドでカーネル内のtime_stateを変更することができます。外部NTPサーバを参照するntpdが起動しっぱだとまた受け取ってしまうのでそちらの対応もお忘れ無きよう。

% sudo ntptime
ntp_gettime() returns code 1 (INS)
time d93c801b.a8d4dc28 Tue, Jun 30 2015 11:40:27.659, (.659498716),
maximum error 207343 us, estimated error 490 us, TAI offset 0
ntp_adjtime() returns code 1 (INS)
modes 0x0 (),
offset -30.648 us, frequency -0.114 ppm, interval 1 s,
maximum error 207343 us, estimated error 490 us,
status 0x2011 (PLL,INS,NANO),
time constant 8, precision 0.001 us, tolerance 500 ppm,
% sudo ntptime -s0
(省略)
% sudo ntptime
ntp_gettime() returns code 0 (OK)
time d93c8023.30a87000 Tue, Jun 30 2015 11:40:35.190, (.190070),
maximum error 211343 us, estimated error 490 us, TAI offset 0
ntp_adjtime() returns code 0 (OK)
modes 0x0 (),
offset -30.000 us, frequency -0.114 ppm, interval 1 s,
maximum error 211343 us, estimated error 490 us,
status 0x0 (),
time constant 8, precision 1.000 us, tolerance 500 ppm,

2. NTPがうるう秒の処理

何らかの設定により、NTPクライアントがうるう秒の処理をする場合があります。
具体的には、ntp-4.2.6p5-1.el6、ntp-4.2.6p5-2.el6_6、および ntp-4.2.6p5-18.el7 以下を実行しているRHELディストリビューションでSLEWモード(後述)を設定した場合などが挙げられます。これらの環境では、Leap IndicatorによりNTPクライアントはうるう秒を把握しますが、その情報をLinuxカーネルには渡しません。その代わり、うるう秒になったらstetimeofday(2)やclock_settime(2)などのシステムコールを用いて1秒間時刻を戻します。
カーネルの処理では無いため、一瞬だけ9時0分0秒(JST)を過ぎてから8時59分0秒(JST)に戻されます(検証例あり)。

これは、安定した結果を保障できないため、オススメできません。

3. NTPを利用せずtzdataからうるう秒を取得

タイムゾーンの情報をまとめたtzdataというパッケージには、最新のうるう秒の情報が含まれます。そのため、最新のtzdataパッケージに更新しておくことで、NTPを利用できない場合にもうるう秒の処理を適切に行うことができます。
実際のうるう秒前後の挙動は、1の場合と同じです。

うるう秒を全力を挙げて見逃すには

このように、うるう秒を上手い具合に処理するためにいくつかの方法が用意されているわけですが、古いカーネルで動けど止めづらいサーバがあったり、サーバ数が多すぎて漏れの無い対応がし切れないなどの理由で回避が必要であれば、全力を挙げて見逃す必要があります。その為には、以下の2つをどうするかを考えなくてはいけません。

  • 本来のうるう秒の処理を行わせない。
  • 別の方法でうるう秒の1秒を「うまく」さしこむ。

うるう秒三原則の厳守

回避すると決めたら、大事なのは「うるう秒をもたず、つくらず、もちこませず」の非うるう秒三原則をどう厳守するかを考えます。

1. 持たない

ntpdにパッチを当てることで、強制的にLeap Indicatorをクリアする方法があります。
私は未検証なので紹介に留まりますが、IBMの記事では01や10に強制セットするパッチが下部「図3」として記載されているので、00に強制クリアすることも可能でしょう。

2. 作らない

ntpdが落ちている場合でもうるう秒が不用意に挿入されないよう、意図しないサーバでtzdataが最新にならないようにします。
なお、最新のtzdataが入っているようなケースは他のパッケージでもうるう秒の影響を受けづらいとは思います。

3. 持ち込ませない

Leap Indicatorを除去するためには、仮想化環境でない物理サーバがあるのであれば、ハードウェアクロック(RTC)もそれなりに正確ですので、一時的に外部のNTPサーバへの参照を辞めてしまうのが一番手っ取り早いです。

前述したとおり、NICT系のNTPサーバではうるう秒の24時間前からLeap Indicatorが設定されるので、それより前からうるう秒の後まで、24時間以上を外部への参照を止める必要があります。当然ながら、RTCの品質があまりにも悪い場合や仮想サーバなどでは秒単位で時刻がずれてしまう可能性もあります。

今後Leap Indicatorが一ヶ月前から設定されるようになると現実的では無くなるでしょう。それまでにはうるう秒を誰もが受け入れられる優しい世界か、なんらかの代替策が用意されていると嬉しいです。

1秒の挿入方法

うるう秒を無視するためには、その1秒を何らかの形で「より影響が少ない方法」で反映する必要があります。これは、時計をゆっくり動かして1秒を生み出すのが一般的です。実際に、パブリッククラウドAWSGCP、携帯キャリア、東京証券取引所などではこのやり方を採用しています。

一般的には、ntpdのSLEWモードを使う事になります。特に自前でNTPサーバを立てず、NTPクライアント側で設定を入れるのであれば、「-x」オプションを付ければ良いです。ただし、前述したとおりNTPのバージョンによってはSLEWモードにしていても、うるう秒だけは1秒ガツンと戻されるような不具合がすぐ最近まで残っていたので、注意が必要です。

その一方で、前述の図のように自前NTPサーバを立ててそこを参照しているような場合は、NTPクライアントの設定によりNTPサーバに時刻を聞きに来る頻度がデフォルト設定でも1024秒(約17分強)だったりするので、NTPサーバに「-x」オプションを付けるだけではダメです。また、自前NTPサーバも冗長化している場合にはそのサーバ間での時刻同期も重要となってきます。


このように、結構厄介な地獄が待っていますが、詳しくはそのうちどっかで記事に載るのでは無いでしょうか(他人事)。

(2016-07-04追記) 掲載済みです⇒ CyberAgentでの「うるう秒」対策

確認方法

自由に偽時刻やLeap Indicator、うるう秒を発生させられる検証用NTPサーバNICTさんが配っているので、それを上位NTPサーバとして検証ができます。

まとめ

うるう秒でも正しく動くシステムを作りましょう。
そして、うるう秒の廃絶に向けて、廃止の動きを応援しましょう。

更新履歴

うるう秒まとめ

今年は、2015/07/01 08:59:60 JST としてうるう秒が挿入されます!(うるう秒実施日一覧)

うるう秒なんてきちんと処理したくない」という人向けのまとめ。

AWS

  • 事前にご確認ください - AWSでのうるう秒対応
  • うるう秒の時点が最大となる0.5秒のズレが計算式(単純な割合)として保証されている。とても素直な実装。
  • EC2等はUTCに同期しているので、AWS側が提供するサービスと時刻が0.5秒ずれる可能性がある。
  • AWS調整時刻(AWS Adjusted Time)を提供するNTPサーバは用意されていない?

GCP

前後10時間ずつ、計20時間かけて調整

  • 最大で0.5秒前後0.5秒のズレ。
  • うるう秒の前は「lie(t) = (1.0 - cos(pi * t / w)) / 2.0」の計算式に沿うが、うるう秒後はSLEW相当?
  • 「おおよそ 100 万分の 14 ずつ」(0.5秒/10時間)ずらして、うるう秒前後で最大0.5秒ズレる。
    • 2011年の時は上記の複雑な計算式を利用していたが、2015年では単純な手法に変更された。
  • metadata.google / metadata.google.internal としてNTPサーバが提供される。外部への提供はない(もし必要なら自前でNTPサーバ建てて公開すれば良い)。

Microsoft Azure

  • 資料が見つからなかった。

ntpd SLEW mode

うるう秒直後時点で1秒時計が先に進むが、そのあと少しずつ修正される。

ntpd LI flag + STEP mode

Leap Indicatorフラグを元に、うるう秒直後に1秒巻戻る。

  • 最重要ポイント: 時間が逆行する(同じ1秒間が二度繰り返される)

23:59:59.000000(→ 23:59:59.999999)→ 23:59:59.000000 → 00:00:00.000000

Windows

ドメイン コントローラーの場合】
(略)
つまり、NTP Server との時刻差が 5.25 秒未満、もしくは 3.5 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

ドメイン メンバー サーバーの場合】
(略)
つまり、NTP Server との時刻差が 225 秒未満、もしくは 150 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

【ワークグループの場合】
(略)
つまり、NTP Server との時刻差が 1 秒未満の場合は、Slew モードで時刻同期が行われる結果となります。

雑感

この中だと「0.5秒ずらしておく」で丁度良い人が多そうだけどAWSGCPでも実装が異なるし、基盤をまたいで時刻を統一するのは諦めた方が良さそう。0分0秒の方をきっちり合わせたい人が多そうだから、あらかじめ最大1秒進めておくのもアリなのではと思うけど、そういう実装はないようだ。

エンタープライズ用途とか、0分0秒の厳密さが求められる場合には、マルチフィードみたいな正しくLeap Indicatorを実装したNTPサーバと同期する必要したうえで、その場合もミドルウェアやアプリケーションが正しくうるう秒(59分60秒999999)を扱えることを確認する必要がある。

追記

  • 2015-05-22 21:00 AWSについて、EC2系はAWS調整時刻ではないことを追記、AWSGCPのNTPサーバ提供有無について追記
  • 2015-05-26 14:00 新しい記事によるとGCPは単純な計算式に変更されたようなので修正
  • 2015-05-29 13:42 NICTの説明資料を追加