PONCOTSU

インフラ領域を主にあれしてます

go run と go buildの違い

f:id:tacmac:20160919223213p:plain:h200

Ruby書いているとパッケージだとか、コンパイルだとかにはほとんど無縁なので、golangの最初の最初、としてpackage・import踏まえつつ、go run と go buildの違いを整理していきます。

パッケージ(package)とは

Goでは、すべてのプログラムが何かしらのパッケージに所属している。パッケージはいわばスコープのようなもの。 原則として以下のルールが存在する。

  • 1つのファイルに複数のパッケージを設定してはならない
  • 1つのディレクトリに複数のパッケージをおいてはならない↲
  • package mainにあるmain関数がエンドポイントとされている(ここから処理が始まる)
package main

import "fmt"

func main() {
  fmt.Printf("hello world!\n")
}

コード1: hello.go

import とは

読み込む必要のあるパッケージを宣言するところ。なお、プログラムの中で使われないパッケージは自動で検出され、除いてくれと叱られる。そこらへんの厳密性をスキップしたい場合は、パッケージの左に _ (アンスコ)をつけるとスキップしてくれる。パッケージ1つだけ読み込むのであればコード1のような表記で良いが、複数ある場合は以下のようにしたほうがよい。

import (
  "fmt"
  "testing"
)

コード2

プログラムを実行する

基本的には、go run hoge.goもしくはgo build hoge hoge.go | ./hogeとすることで実行することができる。

go build

goはコンパイル型言語なので、CやJavaのように基本的にはコンパイルする必要がある。

go build [コンパイル後のファイル名] [コンパイルしたいファイル名]

コンパイルし、コンパイル後のバイナリファイルを実行するには

./[コンパイル後のファイル名]

と叩くだけで良い。 なお、オプション無しでgo buildを叩くと、自動的にmainパッケージを読み込み、main関数があるファイルを特定し、そのファイル名を使ったバイナリファイルが生成される。go buildをすると、基本的にはカレントディレクトリ以下をスコープにして読み込んでコンパイルするファイルを決めるので、カレントディレクトリ以下にあるファイルが読み込まれない、といったことはない。

go run

コンパイルして実行するのがだるい、というニーズ?に答えた命令。自動的にコンパイル・実行してくれる便利なコマンド。go run hoge.goとするだけでプログラムを実行することができる。ただ、ここで注意しておきたいのがgo buildのようにカレントディレクトリ以下の全ファイルを読み込むわけではないということです。go run hoge.goと打つと、基本的にはimportされたパッケージだけを読み 同階層にmainパッケージに所属する別の関数などがあるとそれは無視されてしまう。

Site Reliability Engineeringとは何か?より具体的に考えてみる

結論から先にまとめると、安心安全なシステム開発・時代の変化に沿った運用ができるエンジニアリングが、つまりはSREだということ。この点、要素分解して、もっと現場に落とし込む方法について書いていきます。

SRE本でベンジャミン・トレナー・ソロスが伝えてること

SRE本の中では、SREって深いコンピュータサイエンスの知識が必要だし、ソフトウェアエンジニアリングの経験も必要だから、すんごい求められるものが多くかつ重要なんです、といった話を延々としているのだが、要するにSREってなにか?というところでいうと、可用性・レイテンシ・パフォーマンス・効率・変化への対応・監視・緊急対応・キャパシティコントロールに責任を持ち、対応していうことだということがわかる。すごく観点が多いし、実に教科書的な回答のような印象をぼくは受けました。

基本情報処理技術者試験にも載っているRASISを軸にするとわかりやすいかも

RASIS(ラシス)という用語があります。これは基本情報技術者試験でも出てくる基本的な用語です。これはなにかといいますと、

用語(英語) 用語(日本語) 意味 主な指標となるもの
Reliability 信頼性 システムが正常に動作していること MTBF
Availability 可用性 必要に応じて、いつでもシステムを利用できること 稼働率
Serviceability 保守性 障害の早期発見・迅速な復旧ができること MTTR
Integrity 保全 誤作動がなく、システムが壊れにくいこと 障害発生数
Security 安全性 不正アクセスなどでシステムが壊されないこと・データの漏洩がないこと 発生件数

を指します。
これに勝手な解釈を交えて自分なりのまとめ方をすると、SREとはRASISに運用という観点が追加されたものではないかと思います。 では運用の観点とはなにかと申しますと、DevOpsともよく言われる、運用フロー効率化のことです。なので、RASISに一つ、Operation(運用)という観点を付け加えるとよいのではないか、そう思いました。ROASISとかになるのかな...?(小声)

SREを現場に落とし込む

SREでぐぐると、各企業がSREをどんなふうに解釈して、どんな取り組みをしているのか、なんとなくざっくりわかります。わりと広義の意味では共通の部分が多いが、具体的な話でいうとバラバラだったりして、一体どういうことやねん?となりがちです。そこでこんな表をつくってみました。これで現場に落とせるはず。

観点 ゴール 自社の課題 打ち手 指標
Reliability システムが正常に動作していること     MTBF
Availability 必要に応じて、いつでもシステムを利用できること   稼働率
Serviceability 障害の早期発見・迅速な復旧ができること   MTTR
Integrity 誤作動がなく、システムが壊れにくいこと 障害発生数
Security 不正アクセスなどでシステムが壊されないこと・データの漏洩がないこと 漏洩件数
Operation (1) 頻度が高く、ストレスのないリリースができること (2) 手作業である必要がないものを自動化 リリース数・手作業/自動の割合

空白になっているところを埋めていくと、うまく出来ているところ、まだまだ改善すべきところがみえてくるはず。そこにビジネス観点・長期運用観点を持ってして優先度を定めると、自然とやるべきことが決まってくるのではないでしょうか。

昨今のリプレイス案件でハマるであろう、プロジェクトの進め方の注意点

まず背景から話すと、某企業の某プロジェクトで既存システムのリプレイスを行なっています。そこで得た知見を、特にプロジェクトの進め方について今の所の自分の考えをまとめておきます。

レガシーからナウでヤングでモダンなシステムに

リプレイスをするということは、大体において「既存システムを作り変えて、時代にあったシステムにすること」だと言えます。特にC向けであったりすると、既存サービスを動かしたまま、少しずつリプレイスを図り、最終的に全システムをリプレイスするといったこともありえます。今回はそのケースを体験できているのですが、ここで問題がありまして。

リプレイス案件はウォーターフォールアジャイル、どっちが向いているのか?

実際に進めていくにつれ、この二つの手法のどっちでやるべきなんだろうなぁともんもんと思っていたしだいです。既存システムの振る舞いは保守し、かつシステムや運用自体は新しいものにする、ということなので、「要件定義はある程度決まってる」かつ「あるべき論に立って、ミドルウェアや設計、運用などの新しくするものは新しくする」がごちゃごちゃしがちだと思うのです。これってウォーターフォールでやったほうがよさそうでもあるが、アジャイルでやっていくべきなのかもとも思う。経験がほぼない自分にとっては当初は判断しきれないことでした。

スクラムでやって気づいた問題点

事実、スクラムでチーム開発が始まりました。数ヶ月やってみて、今改めて振り返ると以下の問題点があると個人的に思います。

  • 機能や要素ごとに仕様調査・設計・実装することで、システムの闇にぶち当たり再見積もりしがち
  • ゴールまでの大まかな流れが見えづらく、直近1週間の仕様調査〜実装で手一杯

だんだんと、「あっ...これあかんやつやわ...某み◯ほ銀行問題に近そうやわこれ...」ってなってきて、改めてプロジェクトの進め方を考えるきっかけになり、こういう記事を書くまでに至ってます。

結論:ウォーターフォールで仮決め・アジャイルで柔軟に変更

ウォーターフォールの良いところは要件定義をしっかりして、完了までの期日を定義するところにあると思っています。そのために全体感を全員が把握する必要があるし、詳細仕様を早い段階で詰めていく作業をするので、抜け漏れが極力なくなりやすくなる。一方、よくない点は後戻りできないこと。どこかでこけた瞬間に地獄に変わる。だから誰かがデスマしなければならない状況などが生まれがち。 一方アジャイルだと仕様も期日も、開発体制やニーズに合わせて変更可能ってのが良いところで、特に未知の物をつくるのには向いている。 ここで、ではいわゆるリプレイス案件ではどれが最適?という話に戻るのだけども、個人的には

ではないかと思うのです。 まとめると、最初の段階で出来る限り、既存仕様の抜け漏れをできるだけなくした状態で把握し、作る段階であるべき論に立って考えようってことです。

ゴールは明確に、やる理由を明確に

リプレイスをする理由ってのは、システム的には上記の通りだと思うのです。ただ、「リプレイスしよっか」となるのって、わりと時代に追い付きたい・世の中のニーズに合った開発体制に変えたいなどのビジネス要件がキッカケだったりするのかなとも思います。システム観点・ビジネス観点をごちゃごちゃにしていると、ゴールが定まらず、余計な設計や検討が大量発生してしまう。なので本来、何をゴールにするべきなのか、それをハッキリさせるべきなのだなぁと反省。次に活かす!
 
なお、この機会に、基本情報処理技術者検定の教科書本にある「システム開発技術と監査」という章を読み直したのですが、学生のころ読むとでは、浸透率が断然違うものなんだなと思いました。実際に働いて肌感覚でわかるものって多いのですね。

大量のデータを処理するときに知っておきたい前提知識

大量のデータを処理するとき、何の工夫もないまま設計していると、すごく結果出力までに時間がかかる。このことはなんとなく分かってはいるけども、なんとなくのレベルなので勉強してみた。

遅くなる理由

結果からいうと、大量データを素直に捌こうとすると、メモリだけでは賄いきれず、ディスクを読み込む必要が出てくるため。ディスクは物理的制約があり、メモリと比べると探索にすごい時間がかかるため。 ではなぜメモリは探索が速く、ディスクは遅いのか?

メモリは電気的な部品

もともと電気的な部品のため、物理的制約を受けないので、探索を高速に行なえる。その上、データを転送するためのメモリとCPUとのハブもかなり速い。結果として、メモリはディスクと比べ、105〜106ほど速くなるとのこと。

ディスクは物理的な操作が必要

一方ディスクは、円盤にデータを記録していくため、探索する際にヘッドを移動させ、円盤を回転させ、といった作業をしなければならない。その上、データを転送する際のディスクとCPU間のハブもメモリのそれと比べ低速。

SSD使えば速くなるのでは?

SSDは物理的な回転がないので、探索自体を高速化することができるが、CPUへのデータ転送のときのハブ自体は変わらないので、やはりメモリと比べると遅い。

大規模データを扱うときのコツ

1. いかにメモリ上で処理させるか

メモリとディスクを比べると、圧倒的にメモリのほうが速いというのは自明である。なので出来る限り、メモリ上で処理させようとするのは自然な流れ。 昨今の主な工夫の仕方としては以下のようなものがある

  • RedisのようなインメモリのDBを使う
  • OSレイヤーで、一回でディスクから読み取るデータ量を増やす(メモリにたくさんデータを置く)

2. いかに扱うデータ量を少なくするか

メモリ上で処理させる方針をとり、さらに高速に処理したいとなると、次は扱うデータ量をできるだけ少なくする方法を考える必要がある。主な方法としては圧縮技術を活用する、といったものがある。例えば、ディスクにはアプリケーションファイルをまんまおくのではなく、圧縮し一つのファイルとして作っておき、転送する際も圧縮された小さなデータを送信し、転送先では圧縮ファイルをメモリ上で読み込み、ビルドするといった手法などがある。

3. データ処理に強いアルゴリズムを知る

ディスクを使用するとなったとしても、線形探索を愚直にやったのでは遅くなるのは仕方がない。なので探索アルゴリズムについて基礎的でも良いので知っておき、探索アルゴリズムを用途に合わせて使いこなす、という工夫で高速化することもできる。

4. 検索エンジン活用という解決策を考慮する

DBだけではそろそろ探索処理を賄うにはきついってなってくると、ある検索条件に特化した検索エンジン的なシステムを用意して、それを利用するというのも一つの手。