kenju's blog

About Programming, Mathematics, Security and Blockchain

How to Install Raspberry Pi 3 with Headless-mode & Setup Tips

tl;dr

  • Raspberry Pi 3にHeadless-modeでインストールする方法
  • wpa_supplicant.confWiFIの設定を書き込むことで起動時に無線LANに接続することも可能
  • Raspberry Pi起動後はソフトウェアのアップデートなどを行っておく

動作環境

  • macOS
  • RASPBIAN STRETCH LITE(Minimal image based on Debian Stretch)
    • Version:September 2017

Workflows

  1. https://www.raspberrypi.org/downloads/raspbian/ から最新版のRaspbian LITE版をダウンロード
  2. Headless-modeなので、GUI操作は不要のためLITE版でOK
  3. SDカードにダウンロードしたRaspbianを書き込み
  4. SSH接続するために、boot partitionに空のsshファイルを作成する
  5. cd /Volumes/boot && touch ssh

起動時に無線LANに接続しておくための設定

boot partitionnにwpa_supplicant.confを作成し、以下の内容を書き込む

ctrl_interface=/var/run/wpa_supplicant
country=JP
network={
    ssid="***SSID***"
    psk="***password***"
    key_mgmt=WPA-PSK
    proto=WPA WPA2
    pairwise=CCMP TKIP
    group=CCMP TKIP WEP104 WEP40
}

SSH接続方法

  • arp -aなどでRaspberry PiのIP Addressを取得
    • raspberrypi.localで接続可能
  • デフォルトのID/PWはpi@raspberry
ssh pi@raspberrypi.local

接続後にしておくべきこと

  • update
  • ホスト名の変更
  • Timezoneを日本に
  • 固定IPアドレス
  • パスワード変更 or SSH鍵ログインに変更

Update

sudo apt-get update && sudo apt-get -y upgrade && sudo apt-get -y dist-upgrade && sudo apt-get -y autoremove && sudo apt-get -y autoclean

# reboot after updating all dependencies
sudo reboot

ホスト名の変更

sudo raspi-config

した後で出る設定画面で、「2. Hostname」から設定する。

別のMachineから、設定してあるホスト名を確認する場合、arp -aで割り当てられているホスト名を確認すれば良い。IP Addressがわかっている場合は、dig -xでも良い。

Timezoneを日本に

これも同じく

sudo raspi-config

で設定。

固定IPアドレス

cat /etc/dhcpcd.confすると、固定IP設定を追加する場合のサンプルが載せてある:

# Example static IP configuration:
#interface eth0
#static ip_address=192.168.0.10/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
#static routers=192.168.0.1
#static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1

これを参考にしながら、自分の環境に合わせてIPアドレスを固定しておく

interface eth0
    # IP Address
    static ip_address=192.168.x.x
    # default gateway
    static routers=192.168.x.1
    # DNS
    static domain_name_servers=192.168.x.1 8.8.8.8

パスワード変更 or SSH鍵ログインに変更

パスワード変更

sudo passwd pi

SSH鍵ログインに変更

TBD

Pull-Requestのレビュー時と作成時に意識していること

Pull-Requestをレビューするとき

最近よく気をつけていることは

  • 開発文化の醸成に意識する
  • わからないことはわからないままにしておかない
  • 重要なPRは必ず手元で検証を加える

の三つ。

開発文化の醸成に意識する

エンジニアの文化があまり醸成されていない現場でPull-Requestをレビューする時には、この観点を気をつけている。自分がリーダーやそれに準ずる役割でソースコードの品質に責任を持っている場合、自分のPR上でのコメント一つ一つがその後のPRの品質に影響する。

例えば、雑なコメントやエラー処理の中途半端なロジック、コピペをPR上でゆるくレビューしているとする。そうすると、そのチームに入ったばかりの人や新人が、「PRにあげるソースコードの品質はこんなもんでいいのだ」と錯覚してしまう。そうして、ソースコードの品質に対して雑なスタンスがチームの文化として醸成されていってしまう。

だから、初期の立ち上げ時には細かいTypoやnitsについても積極的に言っていく。特にLinting Toolも入っていないような段階では、そうしたレビュー指摘一つ一つがLinting Toolの指摘の代わりの役割を果たす。

ソースコードの本質的に関わらない箇所についてはほとんどコメントしない、という考え方もある。特にサービスの開発速度を優先する場合、ビジネスの成長を優先する場合、この考え方は往往にして真だ。しかし、「エンジニアの文化を醸成する」という使命を持ってあるチームにジョインしているとすると、意識レベルで「ソースコードの品質に対する無意識レベルでの意識」を醸成するためには、初期の立ち上げ時のこうした地道な努力も時には必要だと考えている。

わからないことはわからないままにしておかない

相手が大先輩だろうが新人だろうが関係なく、わからないことはまず調べた上でPR上で聞く。

そうすると、

  • そのPRが原因で本番サービスがこけたりするような障害に当たっても、当事者意識を持ってあたることができる
  • 同じ疑問を抱えた人が他にいるかもしれず、その場合はチーム全体の時間の節約になる
  • (開発現場によってだけど)単なるコピペで終わらせてPRを出した本人がよくわかってない場合も稀にある。そうした場合の質担保になる

ということ。

一番意識しているのは、「当事者意識を持ってPRにあたる」こと。

「PRを作った本人の責任」という責任放棄的なスタンスだと、サービスの真の成長に対して貢献するエンジニアとしては望ましくない。というか、ありえない。自分がレビューしたPRの実装ミスでサービスがこけたら、それはPRを出した人ではなくレビューをした自分の責任である。

だからこそ、「わからないコード」がmergeされるのはエンジニアとして恐怖であり、そこを徹底的に潰さないといけない。恥とか遠慮とか無用の長物である。

重要なPRは必ず手元で検証を加える

見ただけでは動作が検証できないことがある。環境によって動かなかったりすることもある。

先に書いた「当事者意識を持ってPRにあたる」というスタンスから考えると、自分の手元で動作検証をするのは当然のようにやるべきだと考えている。

とはいえ、自分の開発タスクもあるので、どのPRをどこまで細かく検証するかは、選択と集中である。

Pull-Requestを作るとき

基本的には以下の記事に書いてあることを大事にしている

techlife.cookpad.com

そのほかには

  • パッと見た人が「自分はこのPRをレビューすべきなのかどうか」と「レビューするならどの観点でレビューすべきなのか」がわかる
    • デザイナーやフロントエンドエンジニアにデザインやCSSを見て欲しいのか?CSSはざっくりといいのでロジックを見てほしいのか?など
  • 後から見た人が情報を追えるようにする
    • Slack, Issuesへのリンクを貼る
    • コメントを書く時はcommitやPRへのリンクも貼る(が、やりすぎると技術的負債になるのでほどほどに)
    • git blameで追えない部分をフォローする意味

あたり。

動画配信におけるHTTP Live Streamingの概要について

動画配信プラットフォームを設計している。

Streaming/Download2種類の配信方法がある

配信方法には大きく分けるとStreaming/Downloadの2種類 + 他の動画プラットフォームを利用する手法が考えられる。

  • Streaming
  • Download
    • Pre Download
    • Progressive Download (On-Demand Download)
  • 他の動画配信プラットフォームに動画をUploadしてiframeで読み込む

今回は、他の動画配信プラットフォームに依存しない Streaming/Download それぞれの配信方法を見ていくこととする。

Streaming配信は

  • 都度再生に必要なデータを転送する。
  • クライアント側にデータのダウンロード保存が不要
  • 大容量高画質動画でも配信可能

Download配信はさらに2種類に分けられる。

Pre Download配信は

  • 再生前に全てのコンテンツを一括ダウンロードする
  • プレイ中は通信環境が悪かったり未接続でも問題ない

一方のProgressive Downloadは

  • クライアント側でダウンロードと再生を並行して処理する
  • 「擬似ストリーミング」と呼ばれることもある

Download配信共通の特徴としては

  • コンテンツの著作権によっては2次配布の問題が生じる

Streaming配信の実現手法

Streaming配信を実装する場合、SaaSを利用するか自前で配信サーバーを運用するかの2種類

HLS Protocolについて

AppleiPhone/iPadなどの端末上でメディアを再生するために標準化を進めたプロトコル

https://developer.apple.com/jp/documentation/StreamingMediaGuide.pdf

もともと回線が不安定なモバイル端末での高いUXでの動画視聴を目的としたプロトコルだから、それを意識した"Adaptive bitrate streaming"といった仕様が取り入れられている。

  • HTTPプロトコルを用いた配信が可能
  • Adaptive bitrate streamingを使うと、回線状況に応じて最適な画質の動画を配信することができる

導入事例

Cookpad

Cookpadの料理動画がAWS上にHLS配信サーバーを構築して運用している。エンコードのワークフローにElastic Transcoderを使って入る点や、クライアントからのUpload周りの要件とそれに対する実装方法が参考になる。

techlife.cookpad.com

Adaptive bitrate streamingについては以下の記事でも少し言及がある。理由はわからないが、「TS ファイルは色々な試行錯誤の結果、 5 秒単位で作成」とのこと。

techlife.cookpad.com

ゆうちょ銀行のワンタイムパスワード生成機を分解してみた

分解してみた。

「トークン(ワンタイムパスワード生成機)」について|ゆうちょダイレクト

わかったこ

f:id:itiskj:20171011162939j:plain

  • VASCO社提供
  • 型番はDP275_N3
  • 2014/03/27 日に作られたっぽい

SRE Meetup Tokyoに参加してきた

connpass.com

なぜ参加したかったか

  • SRE本を読んだ上で、監訳者から背景や内容の補足が聞いて視野を広げたかったから
  • 第一線のSREngineerとして働くエンジニアの実践的な経験が聞きたいから
  • 他のSREngineerと交流し、最近の現場の温度感や課題感を話し合って見たかったから

参加してどうだったか

  • SRE本読むきっかけが作れてよかった
    • なかなか長めの本だったので、自分は章のタイトルだけ読んで面白そうなか章だけ読んだ
  • Error Budgetの考え方について実践的な話が聞けた
    • サービス作る上では、ビジネス的理由とのトレードオフとかあるだろうからな。。
  • SLOを重要視している中の人の声を聞けた
    • 本にも書いてあったけど。改めて強調されるとその大切さが身にしみた感じ
  • 学生時代のアルバイトでお世話になって、今FinTech系でSREしている先輩エンジニアと偶然久々にお会いできたのがすごく嬉しかった
    • 今お金のデザインでTHEOのSREやってる先輩
    • また、偶然にもその先輩が書いたコードを来月から触ることになるので、色々仕事の時の話とかも聞けた

MurmurHashとは何か

背景

RubyのHashTableの実装が知りたくて、ソースコードを読んでいた時に、"MurmurHash"という単語に出会った。何かよくわからなかったので、調べて見た。

https://github.com/ruby/ruby/blob/c08f7b80889b531865e74bc5f573df8fa27f2088/st.c:

/* This hash function is quite simplified MurmurHash3
 * Simplification is legal, cause most of magic still happens in finalizator.
 * And finalizator is almost the same as in MurmurHash3 */

MurmurHash is…

Implementations

他の言語はWikipedia | Implementationsを参考にされたい。

C/C++

https://github.com/aappleby/smhasher

本体。SMHasherの一環として開発されている。src/MurmurHash3.cppが最新バージョンの実際の実装。プラットフォームごと(つまり、プロセッサのビットごと)に最適化された実装が3パターン用意されている

  • void MurmurHash3_x86_32()
  • void MurmurHash3_x86_128()
  • void MurmurHash3_x64_128

https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp

Ruby

https://github.com/ksss/digest-murmurhash

こちらの作成された背景に関しては、以下のブログ記事に詳しい:

http://ksss9.hatenablog.com/entry/2013/12/01/233837

JavaScript

https://github.com/garycourt/murmurhash-js

An optimized JavaScript implementation of the MurmurHash algorithms.

こちらのPoCを元に、ライブラリとして公開しているのが以下のレポジトリ:

https://github.com/perezd/node-murmurhash

NOTE: This is a port of Gary Court’s excellent work, to a commonJS module that can be easily included into a node.js project or the browser. I take no credit for the implementation. I am simply making it easier to use for others.

ソースコード自体は複雑度は置いといて行数自体は少なく、node-murmurhash側のMurmus Hash 3の実装は、50行程度

NPMのダウンロード数は上記の方が多いが、↓のmurmurhash-nativeの方が開発が活発で筋が良さそう(あくまでぱっと見の印象。本番で使う場合はより詳細な検討必要)。

https://github.com/royaltm/node-murmurhash-native

This library provides Austin Appleby’s non-cryptographic “MurmurHash” hashing algorithm functions in a few different flavours.

Main References

http://tanjent.livejournal.com/756623.html

Murmur Hashが最初に公開された記事。 簡単なベンチマークとPoCが記されている。

Version 1は↓:

unsigned int MurmurHash ( const unsigned char * data, int len, unsigned int h )
{
    const unsigned int m = 0x7fd652ad;
    const int r = 16;

    h += 0xdeadbeef;

    while(len >= 4)
    {
        h += *(unsigned int *)data;
        h *= m;
        h ^= h >> r;

        data += 4;
        len -= 4;
    }

    switch(len)
    {
    case 3:
        h += data[2] << 16;
    case 2:
        h += data[1] << 8;
    case 1:
        h += data[0];
        h *= m;
        h ^= h >> r;
    };

    h *= m;
    h ^= h >> 10;
    h *= m;
    h ^= h >> 17;

    return h;
}

https://sites.google.com/site/murmurhash/

MurmurHash 2まで公式情報源として機能していた。2011年の"Update March 1, 2011 - The 32-bit variant of MurmurHash3 is finalized, and this page is deprecated.”で役目を終えた。

UPDATE - If you’re reading this via a link from Google or Reddit, please go here - http://murmurhash.googlepages.com. All future updates about MurmurHash will be posted there. (http://tanjent.livejournal.com/756623.html)

https://github.com/aappleby/smhasher

現在のMurmur Hash 3はGitHub repoで管理されている。非暗号ハッシュアルゴリズムのテストスイートであるSMHasherの一環として開発されている。

The SMHasher suite also includes MurmurHash3, which is the latest version in the series of MurmurHash functions - the new version is faster, more robust, and its variants can produce 32- and 128-bit hash values efficiently on both x86 and x64 platforms.

http://www.yosbits.com/wordpress/?p=1442

高速ハッシュアルゴリズムのまとめ。ざっくりまとめが読みたい時に重宝。

  • MurmurHash
  • CityHash
  • FarmHash
  • xxHash
  • SipHash

Zip Fileの構造詳細と分割の仕組みについて

tl;dr

  • Zip Fileを分割してユーザーに送信する仕組みを実装した際に、そもそもZip Fileは分割できるのか、なぜ分割できるのかについて理解するために調べた
  • Zip Fileを操作する時の基本的なLinux Commands例をメモ

構造

Zip Fileは、主に以下の3つの要素によって成り立つ:

  • Central Directory
  • Local Header
  • File Entry

f:id:itiskj:20170923085938p:plain

retrieved from https://en.wikipedia.org/wiki/Zip_(file_format)#Structure

Central Directory

  • Zipファイル内で各File Entryが位置するオフセットを持つことで、ファイルリストの表示速度をあげることができる(ファイルリストを参照する際に、線形探索するのではなく、Central Directoryのオフセットから一発で探索できるため)
  • 各File Entryの名前やメタデータも持つ
  • Central Directory内のFile Entryの順番は、アーカイブ内の実際の順番と関係なく、同じである必要はない

Local Header

  • 冗長性確保のため、Central Directoryが持つ情報と同じものを保持する
  • ファイルコメント、ファイルサイズ、ファイル名、続く「Extra」フィールドについての情報などを保持する

Extra Fields

  • 暗号化の手段、圧縮方式などを保存するフィールド

File Entry

  • 実際のファイルのデータ。圧縮されたり暗号化されたりしている。

Zip File分割の背景

もともとフロップーディスクなどの小さい記憶容量媒体に、大容量のZip Fileを保存する時、分散して保存できるような仕組みが必要だった、とのこと。

The .ZIP specification also supports spreading archives across multiple filesystem files. Originally intended for storage of large .ZIP files across multiple floppy disks, this feature is now used for sending .ZIP archives in parts over email, or over other transports or removable media.

Zip File操作のためのLinux Commands

分割・統合を含めて、Zip File操作の基本的なコマンド例の備忘録。

Create

$ zip my.zip file1 file2 file3
  adding: file1 (stored 0%)
  adding: file2 (stored 0%)
  adding: file3 (stored 0%)

Read

vimコマンドでzipファイルの中身を直接見ることができる。 コメントに書いてある通り、それぞれのFile Entryの中身を個別に見ることもできる。

" zip.vim version v27
" Browsing zipfile /path/to/my.zip
" Select a file with cursor and press ENTER

file1
file2
file3

Split

splitコマンドが使える。例えば5Mごとに分割する場合。

$ split -b 5M my.zip

creating file `xaa'

creating file `xab'

creating file `xac'

creating file `xad'

creating file `xae'

Join

catコマンドを使う。

$ cat x* > ~/joinedfile

Check

JoinしたZip Fileに問題がないかチェックする。

        -T
       --test
              Test the integrity of the new zip file. If the check fails, the old zip file is unchanged and (with the  -m
              option) no input files are removed.

実行例:

$ zip -T my.zip
test of my.zip OK

Extract

$ unzip mike.zip -d ~/output
Archive:  my.zip
 extracting: /workdir/output/file1
 extracting: /workdir/output/file2
 extracting: /workdir/output/file3

PostgreSQLのEXPLAIN命令でクエリの実行計画を読み解くための基礎知識

tl;dr

  • PostgreSQLでクエリの実行コストを把握するにはEXPLAIN, EXPLAIN ANALYZEを使う
  • EXPLAINはあくまで最適と推定された実行プランを表示しているのであり、実際のコストとは乖離する可能性がある
  • クエリチューニングを行うために、EXPLAINの出力結果が表示するプラン演算子の役割とコストの見方を理解しておく必要がある

PostgreSQLがクエリを実行する仕組み

そもそもPostgreSQLがどのようにクエリを実行するのか。 全体像は以下の通り。

f:id:itiskj:20170922123035p:plain

retrieved from https://www.slideshare.net/MikiShimogai/postgre-sql-explain

  • Parser: クエリの構文解析をし、パースツリー(要はAST。テーブル名やカラム名が実在するかわからないので、ローパースツリーとも呼ばれる)を作成、構文チェックも行う
  • Analyzer: DBにテーブルが存在するかどうかをチェック、存在したらテーブル名をOIDに変更するなどして、パースツリーをクエリツリーに変換
  • Rewriter: VIEWRULEを書き換え
  • Planner: クエリツリーを解析し、実行コストを見積もり、問い合わせの最適化を行う
  • Executor: Plannerで作成し決定した最小コストの問い合わせプランを時差しに実行

このうち、EXPLAINは、Plannerで見積もった実行コストを表示するためのコマンドである。

EXPLAINで得られる情報は推定値

実行コストの推定を表示させるためには、EXPLAINをクエリの前に付与して実行する。

> explain select * from public.users;
Seq Scan on users (cost=0.00..53.29 rows=2529 width=55)

ここで、

  • costが重要指標。左辺値が初期コスト(最初の行を返すまで)、右辺値が実行コスト(最後の行を返すまで)。すなわち、左辺値と右辺値の合計がトータルコスト
  • rowsは推定された行数。実際の値と大きくかけ離れている場合は、analyze/vacuumをするサイン

であることを理解しておくことが重要。

EXPLAIN ANALYZEで実際の情報を表示する

ここで、EXPLAINが表示しているのは、あくまでPlannerで見積もった実行コストを表示していることであることに注意。

実際の実行時間を表示させるには、EXPLAIN ANALYZEコマンドを使う。

> explain analyze select * from public.users;
-> Seq Scan on pg_proc (cost=0.00..100.23 rows=2823 width=692) (actual time=0.003..0.608 rows=2824 loops=1)

クエリチューニングの手始めにEXPLAINプラン演算子を理解する

ここで、実行計画の出力に含まれるSeq Scanというワードに注目したい。これは何かと言うと、クエリを実行するための内部的な処理の計算タイプ

例えば、スキャン動作についていうなら、Seq Scanはテーブルを最初から最後まで線形スキャンする最も基本的な演算子。インデックスが存在する場合は、Index Scanが使われる。

f:id:itiskj:20170922165204p:plain

retrieved from https://lets.postgresql.jp/sites/default/files/2016-11/Explaining_Explain_ja.pdf

pg_dumpでダンプしたファイルは約1/10のサイズになった

tl;dr

  • pg_dumpを用いてダンプしたファイルは、手元で確認する限りほとんど元データのおよそ1/10程度の大きさになることが多かった
  • とはいえ、これはあくまで今回自分の環境で計測した限りの話なので、この値は参考にせず、実際に手元で計測してください
  • 今後のために、実際に計測した手法をメモしておく

算出方法

一例として、ここでは特定のSchemaのデータをダンプする条件で考えて見ます。

まず、前提条件としてPostgreSQLのバージョンを確認しましょう。

# Versionは9.6.3
$  psql --version
psql (PostgreSQL) 9.6.3

今回は、my_db.my_schemaという特定のSchemaのみをダンプするとします。

$  psql my_db -c '\dn'
         List of schemas
      Name      |     Owner
----------------+----------------
 my_schema | me
 public    | me
(2 rows)

スキーマのサイズを測定する関数をpg_schema_size.sqlに用意しました。

# サイズを測定する関数
$ cat pg_schema_size.sql
-- https://wiki.postgresql.org/wiki/Schema_Size
create or replace function pg_schema_size(text)
returns bigint as $$
    select
        -- sum all table sizes in the specific schema
        sum(
            pg_total_relation_size(
                quote_ident(schemaname) || '.' || quote_ident(tablename)
            )
        )::bigint
    from
        pg_tables
    where
        schemaname = $1
$$ language sql;

select pg_size_pretty(pg_schema_size('my_schema'));

psql-cオプションで先のファイルを実行すれば、特定のSchemaのサイズがわかります。

$ psql my_db -c "`cat pg_schema_size.sql`"
 pg_size_pretty
----------------
 3000 kB
(1 row)

my_db.my_schemaをダンプして、そのサイズを見て見ましょう。

# ダンプします
$  pg_dump my_db -n my_schema -b > dump.sql

# ダンプしたファイルは「308KB」、つまり元のスキーマの1/10程度
$  du -h dump.sql
348K    dump.sql

redashでコホート分析を表示するSQL

redashでコホート分析を出力するSQLの書き方が少し癖のある書き方だったので、調べた内容をメモ。

結論

コホートグラフ描画に必要なのは、以下の4種類のカラム:

  • 基軸日
  • 基軸日からの経過日
  • 基軸日からの経過日におけるイベント数
  • 基軸日におけるイベント数のトータル(同じ基軸日にはデータが重複する)

カラム名は、それぞれ

  • cohort_date, date
  • day_number, day
  • value
  • total

とでもしておけばイメージがつきやすいのでは。

具体例

前提

「ユーザーの来訪頻度を把握する」ことを目的として、「1週間における全ユーザーのTOPページアクセス」をコホート分析するとする。

つまり、イベントは「TOPページアクセス」になる。

SQL出力結果イメージ

num cohort_date day_number value total
1 2017/9/1 1 800 1000
2 2017/9/1 2 600 1000
3 2017/9/1 3 550 1000
4 2017/9/1 4 300 1000
5 2017/9/1 5 150 1000
6 2017/9/1 6 200 1000
7 2017/9/1 7 10 1000
8 2017/9/2 1 2000 2500

たとえば「No.2」の行は、「2017/9/1日にTOPページにアクセスしたユーザー1000人の内、2日後の2017/9/2にアクセスした人は600人」ということだ。

最終的にこのようなテーブルを出力することをイメージすれば、コホートグラフが描画できる。

公式ドキュメント

redash.io