こんにちは、ランサーズのtomohiroです。最近はバス釣りにはまっています。大人になって始める趣味ののめり込み具合は半端ないですね。
ランサーズでは、数ヶ月前にリリースしたQuantにおいて、データ分析を行うために Redshift を使用しています。ただし、Redshiftに入れているデータのソースはサービスで使用している RDS Aurora になるため、Aurora から Redshiftへデータを同期する必要があります。単純な MySQL の export/import と違い、いくつか制約があるので一筋縄では行かない時もありますが、そんな物なんとでもなります。
今回は、色々と Redshift の運用で使っていたツールやはまった罠等を軽く紹介したいと思います。
そもそも私はMySQLでの運用・開発経験が中心で、Redshift(postgresqlも含め)をほぼ触った事なかったので、基本的な所でつまづいたりもしてますが、暖かく見守っていただけると嬉しいです。
まずはデータの同期からです。これが出来ないと何も始まりません。
グーグル先生に「mysql redshift データ コピー」で調べると、見慣れない “AWS Data Pipe…” の文字。色々他の結果もあさりますが、AWSが用意している物なら、と思いちょっと深掘りする事にしました。
こうして AWS Data Pipeline というサービスに出会ったのですが、簡単に説明しますと、データの変換と移動を自動化するツールです。しかも 「RDS から Aurora へのコピー用テンプレート」という物が用意されているため、設定値を埋めていくだけでだいたいできちゃいました。できちゃいましたとか言ってますが、実際は慣れるまで少し時間がかかりました。
AWS Data Pipeline でテンプレートを選ぶとpipeline設定画面に移るのですが、その見た目が上の画像になります。画面左側にはデータフローが自動的に設定されて、画面右側に各データフローブロックの設定入力項目が並ぶので、地道にひとつひとつ記入していきます。自由度が高い分、記入する項目が多いので、わりと面倒です。(テーブル単位なので、複数テーブルを同期する場合は複数Pipeline設定する必要があるみたいです。これ間違ってたらショックです。。。これまでの苦労が)
実は上の AWS Data Pipeline を実行すると、裏では m1.small EC2インスタンスが立ち上がり、よしなに RDS から S3 データをエクスポートし、よしなに変換をかけつつ S3 から Redshift にデータをインポートしていきます。(すいません、細かい挙動まで追ったわけではないので、微妙に実際とは違うかもしれないです)そのため、EC2がRDSとRedshiftにアクセス出来るようにセキュリティーグループを用意・指定する必要があったり、ダンプデータを保存するS3のパスを準備する必要があります。
Data Pipeline は複数のタスクで成り立っているのですが、複数タスクによってデータフローが作られるので、直前のタスクの成功をトリガーに順番にタスクを実行されます。そのため、途中で失敗してもリトライするように設定でき、リトライ上限に行くと、実行を途中でキャンセルします。
Pipelineは単発で手動実行する事も可能ですが、スケジューラーを設定する事も出来てcronのような使い方も可能です。弊社では一日に一回テーブル同期のバッチを実行しています。(冬眠pipelineも放置していると月いくらとお金がかかるみたいなので、気をつけてください)
無事テーブルを連携出来てから数日、Data Pipeline が ”disk space full” 的なエラーでコケてました。最安のRedshift構成で走らせていたので、 160GBしかディスク容量がないのはわかっていたのですが、さすがに埋まるには早かったので焦りました。
結論、postgresql無知な自分が知らなかったのは、VACUUMとANALYZEが必要だったと言うこと。大量行の挿入・変更・削除を行うと即時にディスク容量が開放されないらしく、crontab で VACUUMとANALYZEを実行するシェルを回すようにしています。
ディスク容量問題でいうと更に続きがあり、同期中のあるテーブルが100GBくらいの大きさになった時、Data Pipeline が同じく、”disk space full” 的なエラーをたまに吐くようになりました。Redshiftのperformanceグラフを見る限り、空き容量は 200GBくらいありそうで、容量がいっぱいになるっておかしくないか?って思っていました。
これもまた私の無知(ドキュメント読めやって話し)だったのですが、Redshift のデータのインポートに使う COPY コマンドはデータソースの約2.5倍ほどの空き容量が必要との事。そりゃ、あっと言う間に同期できなくなりますよね。ちなみに、Redshift の UNLOAD や COPY コマンドはローカルファイル等使用出来ず、すべてのファイル操作は S3 経由になります。それまでの Aurora や MySQL の運用ではサーバーから、うりゃって mysqldump やインポートをやっていたので、新鮮でした。だいぶ S3 まわりの権限設定等の勉強になりました。それはまた別に日に話すとします。。。その日が来る事があれば。
こうなると、このまま全更新をするのはそもそも無謀なので、差分更新する事にしました。Data Pipeline の InsertMode という設定があって、”OVERWRITE EXISTING(プライマリキー、ソートキー、ディストキーを使って、既存行を上書く)”という設定にしていたので、後は取得するデータを絞るだけ。これは、DataNodes の SrcRDSTable > Select Query に WHERE分を追加するだけです。これだけで無事、差分更新出来ました。
もっと早くやっときゃよかった。
他にも色々 Redshift 使ってやってるんですが、まとまりがなくなってきたのでこの辺にしようと思います。
自分は Data Pipeline なるものを今回初めて知り、本当にこれが最適解だったのかは定かではないのですが、とりあえずは運用は回っています。この他にも、Redshift の運用でいろんなシェルスクリプトや、 rails のタスクも動いていたりしますが、その話しもまた別の機会があれば書きます。
駄文長文、最後まで読んでいただきありがとうございます。
こんにちは、ランサーズのtomohiroです。
ランサーズでは、自社で開催する勉強会で、 『WeekendLancers(週末ランサーズ)』というイベントを開催してきたのですが、少しご無沙汰になっていました。今回改めて再開しようと調整した結果、平日の夜(4月23日木曜日)になったため、weekday ランサーズとして開催する事になりました。
そして、記念すべきを第1回を私が登壇する事に。
今回のテーマは「開発体制・開発プロセスについて」。
どの会社も成長に伴い、色々試行錯誤しつつ、色んな仕組みや施策を取り入れているようです。
登壇していただいた企業はどこも「自動化」と「情報の集約」はやっているような印象を受けました。例えば、ランサーズでは、「情報の集約」にchatwork と言うツールを使っています。
各社ツールは違えど、アプローチは似ているんだなと感じました。
詳細はぜひ登壇資料をご覧いただければと思います!
ランサーズのエンジニアのtomohiroです。
自分が普段使っているツールのひとつ、tmuxを紹介します。特に新しくはないですが、他の人の使い方も気になるんじゃないかなと思ったので、書いてみます。
1つのターミナルで複数の仮想端末を扱えるようになります。
この「1つのターミナル」をtmuxではsessionと呼んでいます。理由は後ほど。
ご存知の通りtmuxのプロセスが立ち上がるので、セッションの永続化ができ、突然ネットワークが切断されたり、窓を間違えて閉じたりしても、その状態から復帰が可能になります。
ちなみにtmuxは terminal multiplexer(ターミナルマルチプレクサ)の略です。名前の通り、1つのターミナルをマルチプレックスします。
似たソフトに GNU screen 等もありますが、個人的には tmux を使用しています。いくつか違いをピックアップすると以下の通りです。
tmuxはデフォルトで画面の横分割、縦分割が出来ます。
(今はわかりませんが、tmuxに似た screen だとデフォルトで縦分割出来ない)
tmux は仕組み上、tmuxはサーバーのように動きます。1つのセッションが立ち上がると、tmuxサーバーのインスタンスが立ち上がります。
tmuxサーバーは複数のセッションを管理出来るようになっていて、セッション間の行き来が楽になります。
# epel が入ってないとダメだったと思います $ sudo yum install tmux # tmux用の設定ファイルを作成 $ vim ~/.tmux.conf # .tmux.conf # これは自分の使ってるconfです。(前の上司にもらった物、ほぼそのまま使ってます)参考までに # ちなみに、基本的にキーバインドをスクリーン準拠にしてます。 # 後、自分は Ctrl + t 派の人間です。 # # # # # # # # # # # # # # # # # # # # # # # # # ---------------------------------------------------------------------- # Window / Session Options # ---------------------------------------------------------------------- set-window-option -g utf8 on #set-option -g mouse-select-pane on set-option -g base-index 0 # CopyMode vi set-window-option -g mode-keys vi # ---------------------------------------------------------------------- # Keybind # ---------------------------------------------------------------------- # Prefix to C-t set-option -g prefix C-t unbind-key C-b bind C-t send-prefix # ---------------------------------------------------------------------- # Window / Pane # ---------------------------------------------------------------------- # Open current pane to new window bind ! break-pane -d # Hirozontally / Vertically split pane unbind - bind - split-window -v unbind | bind | split-window -h # move to upper / right / down / left pane unbind k bind k select-pane -U unbind l bind l select-pane -R unbind j bind j select-pane -D unbind h bind h select-pane -L # resize pane unbind K bind K resize-pane -U 8 unbind L bind L resize-pane -R 8 unbind J bind J resize-pane -D 8 unbind H bind H resize-pane -L 8 # ---------------------------------------------------------------------- # screen compatibile settings # ---------------------------------------------------------------------- # go to prev window unbind C-t bind C-t last-window # copy mode bind Escape copy-mode # rename window bind A command-prompt "rename-window '%%'" # list(choose) window unbind '"' bind '"' choose-window # ---------------------------------------------------------------------- # etc # ---------------------------------------------------------------------- # show clock :p bind z clock-mode
tmux new -t <session_name>
tmux a -s <session_name>
(↓ここから下はすべてtmux画面内のキーバインド)
Ctrl + t -> c
次:Ctrl + t -> n
前:Ctrl + t -> p
横:Ctrl + t -> –
縦:Ctrl + t -> |
プリセットのレイアウト: Ctrl + t -> space
左:Ctrl + t -> h
右:Ctrl + t -> l
上:Ctrl + t -> k
下:Ctrl + t -> j
Macでiterm2をお使いの方は、iterm2のメニューに 「Shell」 > 「tmux」という項目があるみたいですね。最初まったく使い方がわからなかったのですが、ちょっと調べた結果ここまでわかりました。
下記のように、 -CC オプションをiterm2で、tmuxを使えるみたいです。
$ tmux -CC $ tmux -CC attach
コマンドを打つと、iterm2のウィンドウが別途開きます。tmuxの操作をmacネイティブのiterm2で出来る事が売りみたいですね。
tmux慣れているとあんまり恩恵を感じないですが・・・
tmuxの使い方の話、いかがでしたか?
tmux.confいじりまくりで、全然デフォルトと違うじゃないかって突っ込まれそうですが、もしscreenと共存する必要があるならばかなりスムーズに移行出来るのではないでしょうか。
先日、社内勉強会をする事になり、そのお題としてデザインパターンをやったので、内容を少し共有しようと思います。自分はデザインパターンをあんまり勉強していなかったので、この機会にデザインパターンに触れてみようと思いました。そこでお題を「(自分も)デザインパターン入門」に。ソフトウェアでデザインパターンを初めて取り上げたと言われる Gang of Four(GoF) の書籍「オブジェクト指向における再利用のためのデザインパターン」で紹介されている23種類のパターンの内から2つピックアップして、rubyで実装してみる事にしました。
ソフトウェアの開発で言うデザインパターンとは、開発中に頻繁に直面する問題に対する解決策をパターン化し、名前をつけた物。更に言うとノウハウを蓄積し、再利用しやすいように定義付けをしたパターンになります。単純にノウハウを貯めるだけではなくノウハウに名前が付くため、議論もしやすくなり、結果的に意思の疎通も容易になります。
ただし、デザインパターンは銀の弾ではありません。あくまでも過去の設計者達が気づいた設計パターンをまとめた物に過ぎません。そのためデザインパターンを覚えれば何でも開発出来るようになるわけでも無ければ、給料があがるわけでもありません。技術者としての知見と技術的引き出しが広がり、結果的にスピードを持って開発が出来るようになり、給料があがる事はありえます。
知らず知らずの内に誰かが定義したデザインパターンを使っている事も多々あります。逆に言語やフレームワークによっては使用が推奨されないパターンも存在します。結局、コードの書き方はある程度経験によって左右され、最終的には適材適所。引き出しを多く持っている事に越した事はないので、歴史から学び、ひとつでも多くの適材適所を増やせるようデザインパターンを知識に取り入れると良い事があるのではないでしょうか。
上で紹介した著書の名前にもあるように、オブジェクト指向に大きく関わるところもあるのですが、今回はそこには深く踏み込みません。今回は「あ、こんなコード見た事ある」って気付きを得るところから始めようかと思います。
早速ですが、今回ピックアップしたふたつのパターンは Template(テンプレート) と Strategy(ストラテジー) です。似ているようで異なるパターンだったので、ちょうどいいかなと思い取り上げてみました。
日本語に訳すと、
テンプレート → 型紙
ストラテジー → 戦略
パターン的にいうと
テンプレート → ある型紙をベースに処理を書き、必要に応じて処理の変更する
ストラテジー → 処理の流れを指定し、ステップ毎に内容を選択出来るようにする
よくある、車の例で説明すると、
テンプレート → 基本的な車の定義がされていて、それに変更等を加える事によって新しい物を作って、新しい車の定義を作る
(1)その複製を作る(継承)
(2)必要に応じてパーツを付け替えたり、改造したりする
ストラテジー → 車のシャーシが用意されていて、各パーツに何を当てはめるか指定していく。必要に応じてリアルタイムで変更が可能(例:タイヤを付け替える)
(1)シャーシとパーツを用意する
(2)パーツを付け替えて、必要なスペックにする
重要なポイントは、処理の定義を自ら持つのか(テンプレート)、処理流れだけを持ち、処理の定義自体は外のオブジェクトに移譲するのか(ストラテジー)だと思っています。
では実際にコードで説明してみます。
基本的にrubyを多く使ってきているので、rubyで書いています。
今回は定型文のレポートを作成するスクリプトを題材にしています。(Design Patterns in Ruby という本を読んでいたので、それにかなりインスパイアされていると思います。題材もそうだったかも ^^;)
当初はテキストレポートのみ必要だったのが、途中からHTMLレポートも必要だと言われ、レポート自動生成スクリプトを作る事にしたという想定です。
まずはかなり単純なスクリプトを書いてみました。
# -*- coding:utf-8 -*- # # class Report def initialize(opt = {}) @title = opt[:title] @data = opt[:data] end def output_report puts "==============================" puts "#{@title}" puts "==============================" puts "------------------------------" @data.each do |d| puts d end puts "------------------------------" puts "EOF" end end report = Report.new({ title: 'Report 2014-06', data: ['りんご', 'ごりら', 'らっぱ', 'パイソン'] }) report.output_report
単純にputsを並べているだけですね。もしHTMLレポートを作りたければ全部書き換えればいい話しです。今あるクラスをコピペして、必要な部分を書き換える。
=========================================================
次にtemplateパターン
# -*- coding:utf-8 -*-
#
#
class Report
def initialize(opt = {})
@title = opt[:title]
@data = opt[:data]
end
def output_report
pre_document
body_start
header
table_start
table_data
table_end
body_end
post_document
end
def pre_document
# raise “abstract method: #{__method__}”
end
def body_start
# raise “abstract method: #{__method__}”
end
def header
raise “abstract method: #{__method__}”
end
def table_start
raise “abstract method: #{__method__}”
end
def table_data
raise “abstract method: #{__method__}”
end
def table_end
raise “abstract method: #{__method__}”
end
def body_end
# raise “abstract method: #{__method__}”
end
def post_document
raise “abstract method: #{__method__}”
end
end
class HtmlReport < Report def pre_document puts "" end def body_start puts "
” def header
puts “
”
end
def table_start
puts “
#{d} |
”
end
def body_end
puts “”
end
def post_document
puts “