Other」カテゴリーアーカイブ

builderscon 2018に登壇します

今年もCfPを採択いただき、buildersconへ行けることになりました。前回はメインホールをもらいながらも、とても悔しい思いをしたのを覚えている。

今回僕はコンテナ起動の高速化、ボトルネックの解消に絞った話をする予定です。

話し手の所属するGMOペパボではロリポップ!マネージドクラウドというコンテナホスティングサービスを提供しており、1台のサーバに数千のコンテナを起動します。

コンテナはプロセスであるという認識は一般的になりつつありますが、コンテナプロセスを起動するにはネームスペースの作成や、マウントなどいくつもの処理が行われてプロセスを起動する必要があり、通常のプロセス起動と違う箇所にボトルネックが現れます。またコンテナ技術はLinuxのカーネルレイヤに近い領域で実装されているためそのボトルネックの解消には深いLinuxに対する理解が必要です。

本セッションにおいては話し手が1台のサーバで数千のコンテナを起動する際に直面したボトルネック、その調査方法、そして解決する方法を共有したいと思います。

昨今k8sの台頭により、あらゆるサービスでコンテナ技術が利用されつつありますが、コンテナ技術の深い理解は、今後のエンジニアのあらゆる開発において有用な知識となるはずです。ぜひ本セッションに足を運んでいただき、一歩進んだコンテナ利用をしていきましょう。

今後、コンテナの利用がさらに加速することは自明なので、ぜひ僕のセッションを聞きに慶応キャンパスへお越しください。

個人的には奥一穂さんにお会いしたことがないのと、興味深いセッションなので楽しみにしています。

サイト誤認を防ぐためにGithub Enterpriseのヘッダカラーを変えた

ペパボでは、Github Enterpriseを @hsbt を中心に運用し、全職種で利用している。最近ではgithub.comにあるリポジトリはペパボが社外公開しているOSSや個人プロジェクトのOSSを公開する場所としか利用していないのだが、エンジニアの場合、双方を利用するので、デザインが類似していすぎて、誤認するということが度々あった。

そこで、ngx_http_addition_moduleを利用することで、ヘッダカラーをいわゆるペパボブルー(#3e6f99)に変更するようにした。

設定としては超簡単で、nginxのコンフィグにこれを書くだけで動く。

    location / {
      proxy_pass https://origin;
      add_after_body  /change_header;
    }

    location /change_header {
      return 200 '<style type="text/css">
        body .Header {background-color: #3e6f99;}
        body .Header .header-search-scope {border-right-color: #3e6f99;}
        body .notification-indicator .mail-status {border: 2px solid #3e6f99;}
      </style>';
    }

こんな感じで青みがかったヘッダーになるので、だいぶ見分けがつくようになった。

ヘッダ

ある程度の規模の会社でGHEを利用するケースは今後も増えてくると思うので、簡単にできる対策としていかがだろうか。

nginxのイベント駆動アーキテクチャをソースコードリーディングする

はじめに

昨今、ngx_mrubyの開発ばっかりやっていて、そもそもnginxの挙動をソースレベルで理解できてないなとふと思いたったので、今日はnginxの挙動をソースで追いかけてみたいと思います。

nginxといえば、所謂イベント駆動モデルで、非同期I/Oで実装されておるのですが、それぞれ何のこっちゃ?という方も多いのではないでしょうか?それらをソースコードレベルでどの様に実装されているか理解することで、実装の本質を理解し、自分でも似たようなコードが書けるようになるかもしれません。

またブログ中において、github.comにラインリンク貼ろうとも思ったのですが、nginxだと普通にずれていって無意味だと思ったので、貼るのやめました。

バックトレースから実行スタックを取得する

僕がCのプログラムを読むときはだいたいgdbで直接実行して、backtraceを取得することで呼び出し巡ごとに読むようにしています。今回は#15あたりから#9あたりまで読んでいってみます。

$ gdb ./build/nginx/sbin/nginx
(gdb) set follow-fork-mode child
(gdb) b ngx_mrb_start_fiber
(gdb) run
#0 ngx_mrb_start_fiber (r=0xa369f0, mrb=0xa37fc0, rproc=0xacf8a0, result=0xa37670) at /home/pyama/src/github.com/matsumotory/ngx_mruby/src/http/ngx_http_mruby_async.c:53
#1 0x0000000000535753 in ngx_mrb_run (r=0xa369f0, state=0xa313b8, code=0xbe6710, cached=1, result=0x0)
at /home/pyama/src/github.com/matsumotory/ngx_mruby/src/http/ngx_http_mruby_module.c:850
#2 0x0000000000537c40 in ngx_http_mruby_post_read_inline_handler (r=0xa369f0) at /home/pyama/src/github.com/matsumotory/ngx_mruby/src/http/ngx_http_mruby_module.c:1578
#3 0x000000000048c6b2 in ngx_http_core_generic_phase (r=0xa369f0, ph=0xc13110) at src/http/ngx_http_core_module.c:880
#4 0x000000000048c601 in ngx_http_core_run_phases (r=0xa369f0) at src/http/ngx_http_core_module.c:858
#5 0x000000000048c56e in ngx_http_handler (r=0xa369f0) at src/http/ngx_http_core_module.c:841
#6 0x000000000049c064 in ngx_http_process_request (r=0xa369f0) at src/http/ngx_http_request.c:1952
#7 0x000000000049a9a3 in ngx_http_process_request_headers (rev=0xd2dde0) at src/http/ngx_http_request.c:1379
#8 0x0000000000499d4e in ngx_http_process_request_line (rev=0xd2dde0) at src/http/ngx_http_request.c:1052
#9 0x00000000004987fe in ngx_http_wait_request_handler (rev=0xd2dde0) at src/http/ngx_http_request.c:510
#10 0x000000000047a8cf in ngx_epoll_process_events (cycle=0xa1fed0, timer=60000, flags=1) at src/event/modules/ngx_epoll_module.c:902
#11 0x00000000004684e9 in ngx_process_events_and_timers (cycle=0xa1fed0) at src/event/ngx_event.c:242
#12 0x0000000000477daa in ngx_worker_process_cycle (cycle=0xa1fed0, data=0x0) at src/os/unix/ngx_process_cycle.c:750
#13 0x0000000000474397 in ngx_spawn_process (cycle=0xa1fed0, proc=0x477cc3 <ngx_worker_process_cycle>, data=0x0, name=0x6a34d3 "worker process", respawn=-3)
at src/os/unix/ngx_process.c:199
#14 0x0000000000476b5e in ngx_start_worker_processes (cycle=0xa1fed0, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:359
#15 0x0000000000476104 in ngx_master_process_cycle (cycle=0xa1fed0) at src/os/unix/ngx_process_cycle.c:131
#16 0x0000000000430f51 in main (argc=1, argv=0x7fffffffe658) at src/core/nginx.c:382

スタックを読む

ngx_master_process_cycle

実行している大きな処理としては ngx_start_worker_processes でワーカープロセスを起動することと、そのあとはループを回してタイマーで利用する現在時間を更新したり、ワーカープロセスの状態を確認したり(SIGCHILD)、シグナルに準じた処理を実行したりしている。

ngx_start_worker_processes

ngx_spawn_process を実行し、workerプロセスをforkしてhttpdサーバとしての処理を開始する。forkしたプロセスでは ngx_worker_process_cycle を実行する。

ngx_worker_process_cycle

ワーカーが継続する限りは、 ngx_process_events_and_timers が実行される。ちゃんとgraceful意識されてて、なるほどという気持ち。

ngx_process_events_and_timers

nginxのeventfdをpollしてイベントを発火していく処理。

まず ngx_event_find_timer が実行される。nginxのtimerはレッド・ブラック・ツリーで管理されている。そのあたりの実装は ngx_rbtree.c に一通り書かれていてわかりやすい。timerについては ngx_rbtree_insert_timer_value で値を追加し、 ngx_rbtree_insert の後処理でrebalanceされている。

ngx_event_find_timerは最も発火が近いタイマーを取得する。そしてそのタイマーを引数に ngx_process_events を実行する。

ngx_epoll_process_events(ngx_process_events)

ngx_process_events はいくつかのシステム・コールから非同期I/Oを実現する形式を選択出来るのですが、現状はepoll一択なのでepollの例で追いかけます。 ngx_epoll_process_events では epoll_waitを利用して、イベントの発生を待つ。この時のタイムアウトは ngx_event_find_timer の戻り値が入るので、何からかのタイマーの発火の必要性があるまではイベントを待ち続けることになる。

またevent自体は例えばhttpであれば ngx_handle_read_event などにラップされた関数で、イベントを追加し、そのイベントに実処理が記載されたハンドラ渡すことで処理を行っていく。

  1. eventfdを作る
  2. eventfdに対してeventをハンドラ付きで書き込む
  3. envetfdからeventを読み込む
  4. enventのハンドラを実行する
  5. 2に戻る

ざっくりだがnginxのイベント実装はこんな感じで行われている。またこの処理の後に、 ngx_process_events_and_timers でtimerの残り時間を確認し、timerの残り時間がないもの(指定した時間になったtimer)のhandlerを順次実行していく。

ngx_http_wait_request_handler

コネクションをacceptした時に ngx_event_accept を経由して、コールされます。以降のハンドラも似たような感じでhttpの各フェーズで順次登録されたハンドラがイベントで呼び出されていく感じですね。またこれらのハンドラにはモジュールのハンドラを追加することが可能な仕組みになっていてngx_mrubyこのハンドラにmrubyのコードを実行するハンドラを登録することで、mrubyでトラフィックのコントロールを可能にしています。

まとめ

今日は早起きしたがゆえに、nginxのイベント駆動実装を追いかけてみました。これまでに書いたとおり、それぞれのイベントにハンドラを登録してキューイングしていき、それを非同期的に実行していくというのが大枠の実装になっており、あれ・・・これ何かに似てるな?ジョブキューじゃん!!!!1なんて思ったりもしました。

ソフトウェアや、システムのアーキテクチャ、このように似ている、類似点があることが本当に多いので、なにか新しい仕組みを作る時にこのようなコードリーティングして習得した知識が応用できるかもしれないので、まずはひたすらインプットすることが大事だなと思った次第です。

ubuntu xenialでnetnsの追加処理を40倍早くする

こんにちは。筆者が現在関わっているプロダクトで、数千のコンテナを起動する際に、ネットワークネームスペース(netns)の作成が律速になるという問題が発生しました。このエントリでは、そういった問題が発生した場合に、どのようにボトルネックを特定し、対応するかについて紹介したいと思います。

以前類似の調査をした内容は下記のスライドにまとめています。

netnsってなに?というかたは、 @ten_forward さんの連載記事がわかりやすいです。

まずは環境を作っていきましょう。実行環境はmacOS上で動くVirtualboxでcpuを2コア、メモリを2G割り当てた ubuntu/xenial64 です。netnsの作成はshellを書きます。

#!/bin/bash

if [ $# -ne 3 ]; then
  echo "usage netns.sh [add|del] from to" 1>&2
  exit 1
fi


for((i=$2;i<$3;i++))
do
  echo "create netns test_$i"
  ip netns $1 test_$i;
done

作ったshellを利用してサクッと、2000個くらいnetnsを作ってしまいます。

$ ./netns.sh add 0 2000
$ ip netns | wc -l
2000

この状態で2001個目をstarceしながら作ってみましょう。

$ strace -tt -s 1024 -o ./strace_2001 ip netns add test_2001
$ head -1 strace_2001 
22:08:52.027006 execve("/sbin/ip", ["ip", "netns", "add", "test_2001"], [/* 16 vars */]) = 0
$ tail -1 strace_2001 
22:08:54.974859 +++ exited with 0 +++

straceしつつでも2秒くらいで作れてしまうので、まださほど遅い状態ではありません。続いて4000個netnsを作って、同じように試してみます。

$ ./netns.sh add 2002 4000
create netns test_2002
...
create netns test_3938
create netns test_3939

3939個目のnetnsを作製しているところでかなり遅くなることが確認できました。またこの状態になると、インスタンスの操作ができなくなるほどの過負荷状態になります。盛り上がってきました!!!1

一度サーバを再起動して、再度トライします。ギリギリに攻めるとまた過負荷で操作できなくなるので、3930個作製してみます。

$ ./netns.sh add 0 3930
$ strace -tt -s 1024 -o ./strace_3931 ip netns add test_3931
$ head -1 strace_3931
00:52:45.225735 execve("/sbin/ip", ["ip", "netns", "add", "test_3931"], [/* 16 vars */]) = 0
$ tail -1 strace_3931
00:52:55.286222 +++ exited with 0 +++

おー、10秒くらいかかるようになりましたね。何が遅いのかstraceの結果を覗いてみます。

00:52:45.278671 open("/var/run/netns", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 5
00:52:45.279814 fstat(5, {st_mode=S_IFDIR|0755, st_size=78620, ...}) = 0
00:52:45.279979 brk(NULL)               = 0xc2d000
00:52:45.280305 brk(0xc56000)           = 0xc56000
00:52:45.280591 getdents(5, /* 1024 entries */, 32768) = 32752

00:52:45.281504 open("/var/run/netns/test_3929", O_RDONLY) = 6
00:52:45.281756 sendmsg(4, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\34\0\0\0Z\0\1\0\316\325\305Z\0\0\0\0\0\0\0\0\10\0\3\0\6\0\0\0", 28}], msg_controllen=0, msg_flags=0}, 0) = 28
00:52:45.282098 recvmsg(4, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\34\0\0\0X\0\0\0\316\325\305Z\231\27t\342\0\0\0\0\10\0\1\0\377\377\377\377", 32768}], msg_controllen=0, msg_flags=0}, 0) = 28
00:52:45.282332 close(6)                = 0

中身を見ると、getdentsで/var/run/netns/の一覧を取得後、既存のnentsのfdを開いて、何かしらメッセージを送ってますね。これがひたすらnetns分繰り返されているようです。さらに、perfでコールグラフを取得し、どの部分がボトルネックなのかを特定します。

$ perf record --call-graph dwarf -- ip netns add test_3945
$ perf report -g -G --stdio
    65.10%     0.21%  ip       [kernel.kallsyms]  [k] entry_SYSCALL_64_fastpath                
                 |
                 ---entry_SYSCALL_64_fastpath
                    |          
                    |--26.54%-- sys_open
                    |          |          
                    |          |--26.44%-- do_sys_open
                    |          |          |          
                    |          |          |--24.97%-- do_filp_open
                    |          |          |          |          
                    |          |          |          |--24.87%-- path_openat
                    |          |          |          |          |          
                    |          |          |          |          |--13.38%-- link_path_walk
                    |          |          |          |          |          |          
                    |          |          |          |          |          |--12.02%-- walk_component
                    |          |          |          |          |          |          |          
                    |          |          |          |          |          |          |--6.27%-- __lookup_hash

全結果はこちら

この時のメモリの状態はこのような感じでした。freeが 56324 とかなり枯渇しています。

$ free
              total        used        free      shared  buff/cache   available
Mem:        2048100     1144188      ★56324          12      847588       22628
Swap:        524284       86260      438024 5 total

sys_openの処理が支配的になっていることから、メモリが枯渇状態の時にsys_openを大量に実行するようなnetnsの挙動は律速なることがわかります。
考えうる対処としては、ipコマンドのパッチを書き、netnsの追加時にすべてのnetnsをopenするような挙動をやめることが挙げられます。

また余談ですが、メモリが枯渇していないときのperfの結果は このように なっており、sys_open
の負荷はさほどありません。

先のstraceの結果のsendmsgが何をやっているのかを確認します。

00:52:45.278671 open("/var/run/netns", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 5
00:52:45.279814 fstat(5, {st_mode=S_IFDIR|0755, st_size=78620, ...}) = 0
00:52:45.279979 brk(NULL)               = 0xc2d000
00:52:45.280305 brk(0xc56000)           = 0xc56000
00:52:45.280591 getdents(5, /* 1024 entries */, 32768) = 32752

00:52:45.281504 open("/var/run/netns/test_3929", O_RDONLY) = 6
00:52:45.281756 sendmsg(4, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\34\0\0\0Z\0\1\0\316\325\305Z\0\0\0\0\0\0\0\0\10\0\3\0\6\0\0\0", 28}], msg_controllen=0, msg_flags=0}, 0) = 28
00:52:45.282098 recvmsg(4, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\34\0\0\0X\0\0\0\316\325\305Z\231\27t\342\0\0\0\0\10\0\1\0\377\377\377\377", 32768}], msg_controllen=0, msg_flags=0}, 0) = 28
00:52:45.282332 close(6)                = 0

ここからはみんな大好きgdb。

$ gdb ip
(gdb) b sendmsg # ブレークポイント打って
(gdb) run netns add test_1 # nents追加して
Starting program: /sbin/ip netns add test_1

Breakpoint 1, sendmsg () at ../sysdeps/unix/syscall-template.S:84
84      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt # バックトレースで呼び出し履歴を見る
#0  sendmsg () at ../sysdeps/unix/syscall-template.S:84
#1  0x000000000043c8b3 in rtnl_talk ()
#2  0x0000000000413b1d in ?? ()
#3  0x000000000041453f in netns_map_init ()
#4  0x00000000004145ce in do_netns ()
#5  0x0000000000407284 in ?? ()
#6  0x0000000000406d72 in main ()

呼び出し箇所がわかったのでiproute2の実装を読みます。
do_netnsの実装を眺めて見たのですが、 netns_map_init はnetnsの名前からID(nsid)を取得して、構造体に保有するような実装でした。恐らくIDで管理される処理があるので、変数として保有するのでしょう。

しかし、実装を見ると、netns_map_init引数がないときlistサブコマンドのときしか呼ばれないように見えます。

コミットを追い掛けてみると iproute2: build nsid-name cache only for commands that need it において、必要なときだけnsidを解決する処理が行われるように修正されていることがわかりました。

つまり、最新のiproute2を使うと今回の律速問題は改善する可能性がありますし、余計なsys_openが抑制されるので、netnsの追加が高速になることが期待されます。

$ apt-get update -qqy
$ apt-get install flex
$ git clone https://salsa.debian.org/debian/iproute2.git
$ cd iproute2
$ make
$ make install

先ほどと同じようにgdbで確認します。

$ gdb ip

(gdb) b sendmsg
Breakpoint 1 at 0x406dc0
(gdb) run netns add test_4
Starting program: /sbin/ip netns add test_4
[Inferior 1 (process 3248) exited normally]

先ほどと異なり、breakにかかることなく処理が完了しました。2000個のnetnsが存在する状態で速度を見てみましょう。

$ strace -tt -s 1024 -o ./strace_2001 ip netns add test_2001
$ head -1 strace_2001 
23:02:06.269076 execve("/sbin/ip", ["ip", "netns", "add", "test_2001"], [/* 16 vars */]) = 0
$ tail -1 strace_2001 
23:02:06.310005 +++ exited with 0 +++

もともと2秒ほどかかっていた処理が、0.05秒ほどで完了するようになりました。単純計算すると 40倍 ほど早くなったことになります。

次に過負荷状態でコールグラフを見てみましょう。

$ ./netns.sh add 2001 3935
$ perf record --call-graph dwarf -- ip netns add test_3936
$ perf report -g -G --stdio
    96.36%     0.00%  ip       [kernel.kallsyms]  [k] entry_SYSCALL_64_fastpath              
                 |
                 ---entry_SYSCALL_64_fastpath
                    |          
                    |--92.12%-- sys_unshare
                    |          unshare_nsproxy_namespaces
                    |          create_new_namespaces
                    |          copy_net_ns
                    |          setup_net
                    |          ops_init
                    |          |          
                    |          |--41.21%-- loopback_net_init
                    |          |          register_netdev
                    |          |          register_netdevice

このようにボトルネックがsys_openからsys_unshareに移ったことがわかります。

まとめ

iproute2を用いて、netnsを追加する場合に、ubuntu/xenial64の環境だと、既存のnetns全てにID解決要求を投げてしまうため、sys_open~recvmessageのオーバーヘッドが存在します。これらのオーバーヘッドは最新のiproute2をコンパイルし、インストールすることで改善することができます。またこれらの問題において、strace、perf、gdbを利用すればボトルネックの特定から改善まで至ることが出来ます。

みなさんもぜひ呼吸するようにLinuxコマンドを使い倒していきましょう。

Agreeを重ねる

Agree=同意する 賛成する、応ずる

帰り道にふと思ったのだけど、大事だと思った。
最近あった出来事で、僕とかが思いついたことを手の空いているメンバーに検証をお願いすることもたまにあったりして、結果は僕のアイディアに対する正否のようなものを結果でもらうことが多い。

でも、僕がその検証を頼むときに、そのアイディアで、本来成し遂げたいことを伝えて、検証する人がそれに同意できれば、その人はその検証だけじゃなくて、さらにアイディアにアイディアを重ねて、よりよい閃きが生まれるんじゃないかって。

ある目的に対して誰かがアイディアを思いついたときに、極端な話、無条件に同意して是として扱うのもありかもなと思う。僕たちの業界って、アイディア一つで何かが変わることも少なくない。そのアイディアをどの角度から見るか、そして、可能な限り同じ角度で見ることで、同じ方向に線を伸ばしていけるから、まずは無条件にAgree、いいなって思った。

夏休みをずらして北海道に行ってきた

今関わっているプロジェクトの開発をお盆に集中して @udzura さんとこなして、9月の1週目に夏休みをずらして取る大作戦で5泊6日、北海道に行ってきました。

旅の目的は単純にのんびりするのと、今個人でサービス開発しているのでそれを旅駆動開発することでした。北海道は毎年冬にスノーボード旅行で訪れているのですが夏の北海道は初めてでした。

福岡と北海道はそれなりに便数があるので、行きはSKY、帰りはANAにしました。しかし、客層や旅客機のサイズなどだいぶ違って、体験にかなり差があるので両方ANAにすればよかった・・・。

1日目

初日は夕方に到着する便にしたので、そのまま空港快特で札幌に移動し、ホテルにチェックイン後、すすきので食事。現地、なかなか寒くすぐにエスタに服を調達しに行った。

ホテルは今回帝王プラザホテルを利用し、とても綺麗で、対応もよくてまた行きたいと思いました。

食事は5年くらい前に行ったこふじを利用する予定が日曜でしまっていたので急遽おがへ。店員さんが仲良くてカウンターから店の厨房の雰囲気を楽しみながら食事を頂きました。九州育ちだからかもうあまり海鮮の感動がなくなってしまったので、もっとジャンキーなものにすればよかったな、なんて思いながら、初日は終了。

2日目

せっかく夏の北海道だしということで、小さく一周することにしていたので釧路へ移動した。

かなり長距離移動で若干時間もったいなかったなぁと思う反面、北海道の車市街地以外はマジで80km/hで走行しているので、ナビの予測時間の半分くらいで移動できる知見を得た。釧路は湿原で熊と戦うために訪れたのですが、熊と出会うことなく、夜は@matsumotoryおすすめの炉ばた焼き発祥の店「炉ばた」へ。

ここはもう、なんというか行ってみてくれ!!!という感じで、とにかくおいしいし、コの字型の低めのカウンターしかない店内の中央におばあちゃんが座っていて、そのおばあちゃんが機械的にひたすら炉端焼きを同じモーションで焼くという世界線間違えたかな???というくらい異世界だった。メニューに金額記載はないのだけど、観光客中心のためか客単8000円くらいで若干割高かなぁという印象は残るが、うまい。

3日目

この日は西に戻りつつ北上して、富良野へ。

膝を壊しているので、強靭な足腰は得られませんでしたが、きれいな花を見たり、青い池に行くなどした。
しかし、いかんせん田舎で、やばいホテルに当たったりして、もう夏はいかなくてもいいなという気持ちになりました。

Canon EOS 6D (75mm, f/3.2, 1/125 sec, ISO100)

Canon EOS 6D (28mm, f/9, 1/500 sec, ISO400)

Canon EOS 6D (45mm, f/3.5, 1/2000 sec, ISO200)

Canon EOS 6D (75mm, f/5, 1/250 sec, ISO100)

4日目・5日目

この日からはのんびりしようと決めておったので、キロロリゾートでひたすら開発することをしていた。

温泉もあったし、ジョギングできる芝生公園もあったし、客室もきれいで最高だったが、ご飯だけが致命的においしくなかった。ただ一人で一部屋借りて一泊1万円弱で泊まれたので、かなり満足。ハイシーズンだけ営業しているレストランが多いので、ハイシーズンだとその点はクリアできるのだろうと思った。

6日目

この日は帰る日ということもあって、お土産を買いにイオンへ。大体全国どこに行ってもイオンに行けば現地の食べ物も並んでるし、べたなお土産もあるので全国共通お土産はイオンにしている。今回訪れたイオン札幌発寒店はサイズも大きくてとても便利だった。

そのあとは毎回好例札幌市中央卸売市場へ。市場といえど、場外なので観光客価格ではあるのだが、手広く色々揃っているし、オペレーションもこなれているので、とても便利で毎回寄っている。今回は翌日にBBQする予定があったので、しゃけやらホッケを保冷バッグで持ち帰った。

まとめ

北海道、マップで見ると小さく見えるから欲張って移動しちゃったのですが、富良野行かなくてよかったなぁというくらいに移動に時間を使ってしまった。一方で当初の目的であるゆっくりすることと、開発についてはそれなりに進捗あったし最高だったし、仕事を離れることで、自分を客観的に考える時間もできたのでとてもよかった。秋口くらいにまた沖縄に行こうと思うのでそれまでまたしばらくバーーーーンとやっていきたい。

YAPC::Fukuoka 2017 HAKATAでロリポップのAPIについてトークしてきた

僕にとって、YAPC::Fukuoka 2017 HAKATAは非常にロングランで濃いものだった。まずは前日に自社のオフィスで開催された、全然野菜に始まる。

これは元々同僚である @hsbt さんが社のSlackで下記の投稿をしたことから全てが始まった。


現在ペパボ@福岡はオフィス改装中で、ペパステというステージを設けて、登壇イベントをパッケージングしているのでほとんど準備することなく飲み物の準備をするくらいで、当日 #全然野菜 がバズるくらいには盛り上がって大変良かった。

その後は公式の前夜祭に移動し、 @udzura が酔って変なテンションになりながらも、Perlと称してClangのライブコーディングをやり遂げるさまを眺めたりしていた。

そんなこんなでLTソンも終わり、 @hsbt と談笑していると、後ろから肩を誰かにぐわっと捕まれ、 「魚っ!おすすめ!」のような検索ワードか!!という勢いで @songmuさんに声をかけられたので、前夜祭のあとは次の日のトップバッターが両方存在するというチキンレースのような面子で鯖郎へ。

この時間も僕にとってはTwitterでは知ってるけど、お会いしたことない・・・というエンジニアと過ごせてとても良い時間だった。その日はあまり遅くなることなく戻ったのだが、帰ってからなぜ映画を見たりしてしまい、寝不足のまま翌日へ。

本番ではトップバッターでロリポップのコアAPIをバージョンアップすることなく、なんとか開発する体制へと持っていった話をした。

当日反省だったのは、トップバッターだったのだけども、接続確認を直前にしてほしいとのことで、あれをあれしたのだが、いざ直前になると会場の方も接続方法わかっておらず、色々ゴニョゴニョはまって、「ふーーー、繋がったーーー」で話し始めたのはよいものの、急いでいたので発表者モードじゃないまま話し始めてしまい、スライドの前後わからず話してしまったのが失敗だった。トップバッターのときは自分の端末だけじゃなくて他の要素も起こり得るから、次回の肥やしにしたい。

イベント自体は会場提供のLINE Fukuokaすごい!!の一点張りで、トークも非常に面白いものが多かった。ベストトーカーになった徳丸さんのセッションを、ボケッとしていて移動するのをミスってしまい聴き逃したのが非常に残念だったが、あとで動画配信ありそうなのでそちらを楽しみにする。

イベントのあとは @linyows から懇親会のチケットを譲っていただいたので、無事懇親会へ潜入。@hitode909 くんと同じテーブルで、例のシールを頂いたり、良い時間だった。最終的には @fujiwara さんや @motemenさんが @hsbt と話すために集まってきてくれて、何か知らんけどすごい人たちに囲まれる感じだった。

その後は最後にテーブルに付いていたメンバーと数人でペパボの社食の黒田へ。途中から参加した @tagomorisさんが終始元気で笑ってしまった。

そんな感じでほとんど酒を飲んでいた僕の初YAPCでしたが、言語に対する参加者の気持ちがすごくポジティブで最高だなと思った。少なくともPerlって昔ほどは盛り上がっていないと思ってはいたんだけど、中の人達が本当に誇りを持ってやっているし、日本でPerlってまだまだ余裕でイケるんだなと肌感として感じた。そして何より酒がうまい!!!1

次の沖縄も参加できるように何かしらの謎技術を生んで、トーカーに選ばれるように頑張りたい。

2016年を振り返る

今年を振り返ると、何と言ってもSTNSだった。STNSのinitial commitは2016/01/03 3:30なので今年の冬休みにSTNSを書いていたんだと思う。
それをきっかけに第5回ペパボテックカンファレンス〜インフラエンジニア大特集〜PHPカンファレンス福岡で話す機会が得られたし、これまで社内に閉じていたOSS活用が初めて社外に広がった初めてのプロダクトであった。また自分の中でこれまで、これは仕様だから出来ないと諦めていた壁を初めてブレイク・スルーできた機会でもあり、「技術的に出来ないことはそんなに無い」という自身の言葉に説得を与える出来事でもあった。

ペパボの中ではチーフテクニカルリードに就任し、これまでとは違ったチーム・ビルディングやメンターとしての振る舞いが求められるようになったが、そんなにやりきれた感じはない。自分自身が謙虚に向き合えきれてなかったところと、感情コントロールが出来きれない部分があるのでそれが如実に出たところではあったと思う。この点についてはもっとやれるので改めて学問と向き合うことで謙虚に来年やっていきたい。

プライベートでは非常に楽しかったことも多かったし、感情的になってしまうこともあったが、概ね楽しかった。それは関わってくれた皆さんや、一年近く同居していた方に感謝したい気持ちがある。

来年に向けては、@udzura@matsumotoryが隣で純粋な技術開発をしているのを傍目に、僕には別にやるべきことがあると思いながら、そこに全くアプローチ出来ていないのは本当に悔しいので、来年はもっと自身の仕事を抽象化したソフトウェアに落とし込んで、ペパボを盛り上げつつ、世界にアプローチできるようなエンジニアになりたいと思う。

今年もお世話になりました。

年末なので福岡で自分がよく行くお店を振り返る

どうも皆さんこんばんは。ナイスガイことカキフライ大好き@pyama86です。
この記事はpepabo Advent Calendar 2016の7日目の記事です。

エンジニアなので、何か技術的な記事を書こうと思ったのですが、それは破壊的イノベーションではないと思いとどまりました。
僕はペパボに入社する前は週に3回合コンをデプロイしていて、定時に帰れるしエンジニア最高!といっていた経歴があるので、そんなころに見つけた、忘年会シーズンに役立つ、福岡グルメの紹介でもしようかなと思います。
日常使いのお店を中心に紹介するので福岡に出張などございましたら是非ご活用ください。

ここは大名のプラザホテルの地下にあるこじんまりとしたイタリアンです。コースもリーズナブルで、ワインリストも手ごろなので、客単価6000円~8000円くらいで楽しめます。ギャルソンのお兄さんが面白く、接客も丁寧なので便利。

ビストロ高木の姉妹店です。熟成肉を中心に、こなれたイタリアンを楽しめます。ビストロ高木と同様、がぶ飲みワインを提供しており、安めのワインをロックで飲むのが最高。

赤ワインと焼き鳥のお店。客単価は焼き鳥屋にしてはちょっと高めです。ピノ・ノワールと焼き鳥の相性が最高っぽいです。レバーのパテもワインと相性良くて最高。

フレンチベースなお店。その日のハウスワインが16種類くらいあって、グラスでいろいろなワインを飲める。ここは何といってもフォアグラハンバーグ。いつも2個くらい食べてる気がする・・・。近所にオーナーの奥さんがやっているニュージランドワインの専門店もあって、そちらと梯子してもグッド。

ここは僕がツイートしていることが多いので、ご認識の方もいるかと存じますが、ウニクリームパスタが最高。もともとは今泉に住んでるころパスタ・ロッソという系列店が近所にあって、そちらに通っていたのですが、閉店になってしまい、パスタ・パスタに足を運ぶようになりました。パスタ・ロッソの頃と味は違うものの、これはこれでということで、いつも白ワインと、ウニクリームパスタ大盛と機械的に注文している。

天神から少し離れ、桜坂の住宅街にあるレストラン。客単価はかなり高めですが、一軒家でほぼ貸し切り状態でディナーを楽しめます。配膳もすごく気を使ってるし、特別な日に使うとよい日になると思います。

定期的に通う韓国料理屋さん。大名店がおすすめ。スタッフは留学生が多くて、若い人が多い気がする。メインのコプチャンチョンゴルはほどほどで、ソカルビがおいしい。

僕がよく行ってる酒峰の系列店。酒峰より安く、日本酒を楽しみつつ季節のものを食べられる。飲み放題とかもできるけど、そんなに高くないので好きなお酒の飲むのがよさそう。ほんとに日本酒楽しみたいなら、酒峰に行くと、飲んだことない日本酒が楽しめてよい。

言わずもがな。長友さん最高。かっこいいし、きれいで速い。

こちらもベッタベタではありますが、中洲のきれいめな居酒屋。何食べてもおいしいので、外したくないときはとりあえずここで。

メニューになくてもなんでも作ってくれるお店。客単価は8000円くらい。おいしいし、日本酒も種類豊富なので、福岡でおいしいもの!と思ったら先のせいもん払いと、予約が取れたほうで・・・くらいな温度感でよい。

最後に

思いついたところを順に書いていたらきりがなくなってしまいました。福岡は食べ物がおいしいことで有名です。しかし、刺身など素材のまま食べるならたぶん九州の田舎のほうがおいしいと感じることが多いんじゃないかなと思うので、ぜひ近県にも足を運んでもらいたいと思います。
これから年末でお酒を飲む機会が増えてくると思いますが、デブ・オプスと天一中毒には皆さまぜひお気をつけださい。

ペパボのホスティング事業部のチーフテクニカルリード(イケメン)に就任しました

 少々時間が経ちましたが、9/1よりGMOペパボ株式会社ホスティング事業部のチーフテクニカルリード(CTL)に就任しました。
チーフテクニカルリードの役割や位置づけについてはEC事業部のCTLに就任した、初めてのペパボの社員旅行で共に73点のカレーを作ったくんさんがブログに書いたとおりです。

ペパボのエンジニア組織がもう一段階先に進むために、事業部そして所属するエンジニアと共に更に成長することが最大のミッションとなります。

 成長ということに関しては青天井の僕ではありますが、各所から職位が上がることより、大人になってしまうのではないか?と心配されていますが、この前も出会って3分位の相手を激怒させてしまったのでその心配はしばらくなさそうです。

 さて、CTL就任については僕自身は実は7月上旬くらいから内定していたこともあり、ここ2ヶ月くらいその体で振舞っていたので、あまりこれからどうこうということはないのですが、振る舞い始めた当初は、自分自身のコードを書く時間は確実に減るので個人としてのアウトプットが減ることに対するもやっとした気持ちは多少ありました。しかし、自分自身が作用することで組織のアウトプットを増やすことが一番必要なことなので、ある程度区切りがついたかなと思います。何より1日は24時間あるわけで、「ちょっと職位が変わったからコード書く時間ないんすよ〜」って半分くらいは自分に言い訳してるだけだなと思うようになりました。

 最後に、僕が今後やっていく領域はレンタルサーバサービスのロリポップ!Heteml、ドメイン総合サービスのムームードメインの3つです。まだまだ進化過程にあるホスティング業界で、技術に対して誠実に、着実にサービスを成長させていくつもりなので、今後の僕にご期待ください。