投稿者「tomohiro」のアーカイブ

いつもマイクを使う場面で思うこと

tomohiro|2016年12月08日
開発よもやま
こんにちは。最近ニジマスを釣りに行って、爆釣で8匹食べて当分はニジマスは食べなくていいかなって思っているtomohiroです。

 

そんな私が日頃思っていながら、なかなか吐き出せずにいた事をせっかくの機会に吐き出そうと思います。すいません、あんまりウェブ関係ない話しになってしまいますが。

 

弊社では当番制で朝会を行っていて、全社への共有や弊社の行動指針である Lancers Way の話しをしたりしています。その時にマイクを小さなアンプに挿して使っているのですが、たまにマイクを持ちながら「キィィィン」って甲高い鳴らせている方がいたりして、「ああああ、なぜそうなっているか教えてあげたい。そして二度とないようにしたい」っていつも思っていながら、何も言わないままでした。そこで今回のブログを機会として吐き出そうと思います。いや、実際はそこまで思い詰めてないです。大丈夫です(笑)

 

ご存知の方も多いかと思いますが、この甲高い音が出る現象をハウリングって言います。ググればすぐに出てくるので改めて説明する必要もないかもしれないですが、ハウリングというのは、スピーカーが発している音をマイクが拾って、更にその音がスピーカーから発されて・・・という無限ループが発生し、音が増幅された結果「キィィィン」という甲高い音が発生します。当然、「キィィィン」以外にも、「ボォォォン」等低音が増強される事もあります。その時の音響等によって変わります。

 

ハウリングが発生するメカニズムを知れば、その発生を防げる、あるいはすぐに対処出来る物です。先程言った通り、原因は音がスピーカーとマイク間で延々と増幅され続ける事にあります。そこで、ハウリングを防ぐ方法を簡単にまとめると

 

1) 音量を適切に調整する
2) マイクをスピーカーに向けない
3) ハウリングを抑える仕組みを入れる

 

上の解決手段について考えていた時にふと思ったのですが、エンジニアとしては(3)の選択肢まではパッと思いつかないといけないんじゃないかって事です。ちなみに、このへんの知識は趣味を通じて得た物であって、音響の専門家とかではないので、ざっくりとした表現は多めに見ていただけると幸いです。

 

(1), (2) は発生しうる問題に絆創膏を貼る形ですが、これは根本解決ではなかったりします。ある程度音量の上下が許されたり、スピーカーの配置の自由が効く場所は良いんですが、これがマイクとスピーカーが固定になってしまうと不便きわまりない。ある一定の音量以上になるとまともに使えなくなるとかスケールしない設計のアプリみたいな物ではないかと。

 

(3) の実現方法はいったん置いといて、何かやり方はあるはずなのでは?と考えをめぐらす事にエンジニアの存在意義があると思っています。エンジニアの仕事は問題を解決する事だと思っているので。(当然、問題が起きないように事前に考えるのも仕事ですが)
実際に使われている物としてはエコーキャンセラだったりFBSだったりと存在するわけなんですが、それを見つけに行く(あるいは作る)発想に至る事って大事だなと思います。

 

今回で言うとニジマスを8匹食べると言う選択肢を取りましたが、他にもっと幸せになる食べ方がなかったかを考えるべきだったのでは?と反省しています。

 

本当にまとまりのない文章でしたが最後まで読んで頂きありがとうございました。

RDS Aurora から Redshift のデータ同期事情

tomohiro|2016年10月14日
Aurora

こんにちは、ランサーズのtomohiroです。最近はバス釣りにはまっています。大人になって始める趣味ののめり込み具合は半端ないですね。

ランサーズでは、数ヶ月前にリリースしたQuantにおいて、データ分析を行うために Redshift を使用しています。ただし、Redshiftに入れているデータのソースはサービスで使用している RDS Aurora になるため、Aurora から Redshiftへデータを同期する必要があります。単純な MySQL の export/import と違い、いくつか制約があるので一筋縄では行かない時もありますが、そんな物なんとでもなります。
今回は、色々と Redshift の運用で使っていたツールやはまった罠等を軽く紹介したいと思います。

そもそも私はMySQLでの運用・開発経験が中心で、Redshift(postgresqlも含め)をほぼ触った事なかったので、基本的な所でつまづいたりもしてますが、暖かく見守っていただけると嬉しいです。

Aurora から Redshift への同期

まずはデータの同期からです。これが出来ないと何も始まりません。
グーグル先生に「mysql redshift データ コピー」で調べると、見慣れない “AWS Data Pipe…” の文字。色々他の結果もあさりますが、AWSが用意している物なら、と思いちょっと深掘りする事にしました。

こうして AWS Data Pipeline というサービスに出会ったのですが、簡単に説明しますと、データの変換と移動を自動化するツールです。しかも 「RDS から Aurora へのコピー用テンプレート」という物が用意されているため、設定値を埋めていくだけでだいたいできちゃいました。できちゃいましたとか言ってますが、実際は慣れるまで少し時間がかかりました。

AWS Data Pipeline の中身

data_pipelineAWS 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 のタスクも動いていたりしますが、その話しもまた別の機会があれば書きます。

駄文長文、最後まで読んでいただきありがとうございます。

Web系ベンチャー各社の開発体制・開発プロセスについて | Weekdayランサーズ勉強会

tomohiro|2015年05月08日
イベント/登壇

11059590_894115540646182_8369955511228765931_n

こんにちは、ランサーズのtomohiroです。

ランサーズでは、自社で開催する勉強会で、 『WeekendLancers(週末ランサーズ)』というイベントを開催してきたのですが、少しご無沙汰になっていました。今回改めて再開しようと調整した結果、平日の夜(4月23日木曜日)になったため、weekday ランサーズとして開催する事になりました。

そして、記念すべきを第1回を私が登壇する事に。

開発体制・開発プロセスについて

今回のテーマは「開発体制・開発プロセスについて」。

どの会社も成長に伴い、色々試行錯誤しつつ、色んな仕組みや施策を取り入れているようです。

登壇していただいた企業はどこも「自動化」と「情報の集約」はやっているような印象を受けました。例えば、ランサーズでは、「情報の集約」にchatwork と言うツールを使っています。

各社ツールは違えど、アプローチは似ているんだなと感じました。

詳細はぜひ登壇資料をご覧いただければと思います!

登壇資料

tmux screen capture

複数ターミナルを操作するときの決定版!tmuxの使い方

tomohiro|2014年11月28日
DevOps

ランサーズのエンジニアのtomohiroです。
自分が普段使っているツールのひとつ、tmuxを紹介します。特に新しくはないですが、他の人の使い方も気になるんじゃないかなと思ったので、書いてみます。

tmux(terminal multiplexer)とは

1つのターミナルで複数の仮想端末を扱えるようになります。
この「1つのターミナル」をtmuxではsessionと呼んでいます。理由は後ほど。
ご存知の通りtmuxのプロセスが立ち上がるので、セッションの永続化ができ、突然ネットワークが切断されたり、窓を間違えて閉じたりしても、その状態から復帰が可能になります。

ちなみにtmuxは terminal multiplexer(ターミナルマルチプレクサ)の略です。名前の通り、1つのターミナルをマルチプレックスします。

tmux screen capture

tmux使用イメージ

なぜscreenではなくtmuxなのか?

似たソフトに GNU screen 等もありますが、個人的には tmux を使用しています。いくつか違いをピックアップすると以下の通りです。

画面分割

tmuxはデフォルトで画面の横分割、縦分割が出来ます。
(今はわかりませんが、tmuxに似た screen だとデフォルトで縦分割出来ない)

tmuxサーバー構成

tmux は仕組み上、tmuxはサーバーのように動きます。1つのセッションが立ち上がると、tmuxサーバーのインスタンスが立ち上がります。
tmuxサーバーは複数のセッションを管理出来るようになっていて、セッション間の行き来が楽になります。

導入手順(tmux.conf)

# 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と共存する必要があるならばかなりスムーズに移行出来るのではないでしょうか。

Rubyでデザインパターン入門

tomohiro|2014年08月01日
Ruby

はじめまして。ランサーズのエンジニアのtomohiroです。

先日、社内勉強会をする事になり、そのお題としてデザインパターンをやったので、内容を少し共有しようと思います。自分はデザインパターンをあんまり勉強していなかったので、この機会にデザインパターンに触れてみようと思いました。そこでお題を「(自分も)デザインパターン入門」に。ソフトウェアでデザインパターンを初めて取り上げたと言われる 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 "”
end

def header
puts “

#{@title}


end

def table_start
puts “


end

def table_data
@data.each do |d|
puts “


end
end

def table_end
puts “

#{d}


end

def body_end
puts “”
end

def post_document
puts “”
end
end

class TextReport < Report def header puts "==============================" puts "#{@title}" puts "==============================" end def table_start puts "------------------------------" end def table_data @data.each do |d| puts d end end def table_end puts "------------------------------" end def post_document puts "EOF" end end report = TextReport.new({ title: 'Report 2014-06', data: ['りんご', 'ごりら', 'らっぱ', 'パイソン'] })report.output_report [/code] 今回はrubyの継承 Class < SuperClass を使っています。これでReportクラスを継承し、必要な部分を上書きした上でレポート生成としてテキストレポート生成とHTMLレポート生成のクラスに分けて作りました。 ========================================================= 最後にストラテジー [code language="ruby"] # -*- coding:utf-8 -*- # # # Report # Formatter # HtmlFormatter # TextFormatter # class Report def initialize(opt = {}) @title = opt[:title] @data = opt[:data] @formatter = opt[:formatter] end def formatter(hoge) @formatter = hoge end def output_report @formatter.output_report(self) end # attr_reader: title, data def title; @title; end def data; @data; end end class Formatter def output_report(context) pre_document body_start header(context) table_start table_data(context) 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(context) raise "abstract method: #{__method__}" end def table_start raise "abstract method: #{__method__}" end def table_data(context) 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 HtmlFormatter < Formatter def pre_document puts "”
end

def body_start
puts “”
end

def header(context)
puts “

#{context.title}


end

def table_start
puts “


end

def table_data(context)
context.data.each do |d|
puts “


end
end

def table_end
puts “

#{d}


end

def body_end
puts “”
end

def post_document
puts “”
end
end

class TextFormatter < Formatter def header(context) puts "==============================" puts "#{context.title}" puts "==============================" end def table_start puts "------------------------------" end def table_data(context) context.data.each do |d| puts d end end def table_end puts "------------------------------" end def post_document puts "EOF" end end report = Report.new({ title: 'Report 2014-06', data: ['りんご', 'ごりら', 'らっぱ', 'パイソン'], formatter: TextFormatter.new }) report.output_report report.formatter(HtmlFormatter.new) report.output_report [/code] まずはストラテジーのクラスがレポート出力の処理を行うオブジェクトを設定出来るようにしています。そして、基本的な処理の流れ(headerを書く、bodyを書く、…)を定義しています。 レポート出力処理をするオブジェクトをテキスト用とHTML用と用意して、必要に応じてその場で変更出来るようにしました。その結果、柔軟に対応出来るレポート生成スクリプトが出来ました。 いかがでしたでしょうか?意図せずに、「そういえばこんな設計した事ある!」って思った方もいたのではないでしょうか。その時は自分天才とか思っても、実際には過去にもこういう事を考えていた方がいたんですね。経験から学ぶ事は重要ですが、歴史から学ぶ事もかなり重要だと思います。もしすでにやっていなければ、改めて過去の偉人達の功績を振り返る時間を作ってみてはいかがでしょうか。ただちに影響はなくとも、将来ふとした瞬間に役に立つ日が来る事を信じて!