初心者エンジニアのシステム構築失敗談

102
初心者エンジニア システム構築 失敗談 @Spring_MT 13114日月曜日

Upload: makoto-haruyama

Post on 09-Dec-2014

3.044 views

Category:

Documents


1 download

DESCRIPTION

 

TRANSCRIPT

Page 1: 初心者エンジニアのシステム構築失敗談

初心者エンジニアの

システム構築失敗談

@Spring_MT

13年1月14日月曜日

Page 2: 初心者エンジニアのシステム構築失敗談

Profile

13年1月14日月曜日

Page 3: 初心者エンジニアのシステム構築失敗談

@Spring_MTEngineer

13年1月14日月曜日

Page 4: 初心者エンジニアのシステム構築失敗談

13年1月14日月曜日

Page 5: 初心者エンジニアのシステム構築失敗談

福岡RRuubbyy会議0011

13年1月14日月曜日

Page 6: 初心者エンジニアのシステム構築失敗談

福岡RRuubbyy会議0011

13年1月14日月曜日

Page 7: 初心者エンジニアのシステム構築失敗談

初心者エンジニアの

システム構築失敗談

@Spring_MT

13年1月14日月曜日

Page 8: 初心者エンジニアのシステム構築失敗談

初心者??

13年1月14日月曜日

Page 9: 初心者エンジニアのシステム構築失敗談

・前職でエンジニアに転向� その前までは一切コード書いてないんです。。。

営業とかもやってたんですよ

・エンジニア歴 22年半くらい

・ruby歴はちょうど一年

13年1月14日月曜日

Page 10: 初心者エンジニアのシステム構築失敗談

なので

・gitしか使ったことない......

・utf8しかしらない........

13年1月14日月曜日

Page 11: 初心者エンジニアのシステム構築失敗談

エンジニアの

ゆとり世代

13年1月14日月曜日

Page 12: 初心者エンジニアのシステム構築失敗談

前の環境

13年1月14日月曜日

Page 13: 初心者エンジニアのシステム構築失敗談

言語フレームワーク

perl独自フレームワーク

テストはあんまりない >>__<<

13年1月14日月曜日

Page 14: 初心者エンジニアのシステム構築失敗談

DDBB関連

databaseは複数

joinは基本しない

masterとslave

autoincrement使わない

13年1月14日月曜日

Page 15: 初心者エンジニアのシステム構築失敗談

新しい環境

13年1月14日月曜日

Page 16: 初心者エンジニアのシステム構築失敗談

なんもない。。。。

13年1月14日月曜日

Page 17: 初心者エンジニアのシステム構築失敗談

13年1月14日月曜日

Page 18: 初心者エンジニアのシステム構築失敗談

00からスタート

13年1月14日月曜日

Page 19: 初心者エンジニアのシステム構築失敗談

フレームワーク

13年1月14日月曜日

Page 20: 初心者エンジニアのシステム構築失敗談

・テスト周�りの環境が揃ってる

・新しくjoinする人((学生含めて))の学習コストが低い

13年1月14日月曜日

Page 21: 初心者エンジニアのシステム構築失敗談

Rails

13年1月14日月曜日

Page 22: 初心者エンジニアのシステム構築失敗談

実際はやってみたかっただけ

13年1月14日月曜日

Page 23: 初心者エンジニアのシステム構築失敗談

Railsで

アプリ作る

13年1月14日月曜日

Page 24: 初心者エンジニアのシステム構築失敗談

はじめの一歩

13年1月14日月曜日

Page 25: 初心者エンジニアのシステム構築失敗談

課題

13年1月14日月曜日

Page 26: 初心者エンジニアのシステム構築失敗談

・複数DB対応

・master  slave振り分け

・採番(sequence)

・belongs_toの扱い

13年1月14日月曜日

Page 27: 初心者エンジニアのシステム構築失敗談

えっ。。。

13年1月14日月曜日

Page 28: 初心者エンジニアのシステム構築失敗談

いきなり大きいこと考えすぎ

でもこの時は必要だと思ったんです。。。。

13年1月14日月曜日

Page 29: 初心者エンジニアのシステム構築失敗談

大規模病 >>__<<

13年1月14日月曜日

Page 30: 初心者エンジニアのシステム構築失敗談

複数DBの対応master・slave振り分け

13年1月14日月曜日

Page 31: 初心者エンジニアのシステム構築失敗談

方針 ・DB + master、slave毎にModelのクラスを作る

・Controllerで明示的にDBアクセス先を指定する

13年1月14日月曜日

Page 32: 初心者エンジニアのシステム構築失敗談

class  TestMasterShard  <  ActiveRecord::Base    self.abstract_class  =  true    establish_connection  "#{ENV['RAILS_ENV']}_test_master"end

class  FooMaster  <  TestMasterShard    self.table_name  =  'foo'    attr_accessible  :name    validates  :content_id,  {presence:  true}end

production_test_master:    username:  test    password:  testdevelopment_test_master:    username:  test    password:  testtest_test_master:    username:  test    password:  test

13年1月14日月曜日

Page 33: 初心者エンジニアのシステム構築失敗談

・テストではまる

・明示的に書いたほうがトラブルが少なそう

octopus

13年1月14日月曜日

Page 34: 初心者エンジニアのシステム構築失敗談

   #  config.include  RSpec::Octopus    config.before  do        shards  =  ActiveRecord::Base.connection_proxy.instance_variable_get(:@shards)        @connections  =  shards.values.map(&:connection)        @connections.each  do  |connection|            connection.increment_open_transactions            connection.transaction_joinable  =  false            connection.begin_db_transaction        end    end

   config.after  do        @connections.each  do  |connection|            if  connection.open_transactions  !=  0                connection.rollback_db_transaction                connection.decrement_open_transactions            end        end    end

production_test_master:    username:  test    password:  testdevelopment_test_master:    username:  test    password:  testtest_test_master:    username:  test    password:  test

13年1月14日月曜日

Page 35: 初心者エンジニアのシステム構築失敗談

View

Controller Model

UserController UserMaster

UserSlave

master

slave

FeedMaster

FeedSlave

master

slave

GroupMaster

GroupSlaveslave

FeedController

GroupController

master

13年1月14日月曜日

Page 36: 初心者エンジニアのシステム構築失敗談

採番sequence

13年1月14日月曜日

Page 37: 初心者エンジニアのシステム構築失敗談

アプリ内で一意のIDを発行する

方針

13年1月14日月曜日

Page 38: 初心者エンジニアのシステム構築失敗談

・IDがわかれば、それに紐付くデータが一意に決まる

・重複が起きない

ex)) user_id ++ コンテンツ((feed  or  image  or  ...))のID

13年1月14日月曜日

Page 39: 初心者エンジニアのシステム構築失敗談

class  Sequence  <  SequenceShard    self.table_name  =  'seq'

   def  self.generate(model)        result  =  self.connection.execute(            "UPDATE  seq  SET  id=LAST_INSERT_ID(id+1)"        )        id  =  self.connection.last_inserted_id(result)  

or  raise  RuntimeError        return  id    end

end

production_test_master:    username:  test    password:  testdevelopment_test_master:    username:  test    password:  testtest_test_master:    username:  test    password:  test

13年1月14日月曜日

Page 40: 初心者エンジニアのシステム構築失敗談

belongs_to

13年1月14日月曜日

Page 41: 初心者エンジニアのシステム構築失敗談

今回は複数DBを想定したので使わないことにしました>>__<<

方針

13年1月14日月曜日

Page 42: 初心者エンジニアのシステム構築失敗談

課題

・Controllerからはmaster slaveを意識せずに使いたい

13年1月14日月曜日

Page 43: 初心者エンジニアのシステム構築失敗談

いきなりこの時点でスケールを考えている。。。

そもそも考慮する必要があったのか?

13年1月14日月曜日

Page 44: 初心者エンジニアのシステム構築失敗談

自分で見えない敵を作ってた。。。

13年1月14日月曜日

Page 45: 初心者エンジニアのシステム構築失敗談

大規模病 >>__<<

13年1月14日月曜日

Page 46: 初心者エンジニアのシステム構築失敗談

第二期

13年1月14日月曜日

Page 47: 初心者エンジニアのシステム構築失敗談

課題

・Controllerからはmaster slaveを意識せずに使いたい

13年1月14日月曜日

Page 48: 初心者エンジニアのシステム構築失敗談

・モデルを2つに分ける

** データベースとテーブルの抽象化((masterとslave毎にクラスがある))

** master/slaveの抽象化

方針

13年1月14日月曜日

Page 49: 初心者エンジニアのシステム構築失敗談

UserLogic

Logic Data

UserMaster

UserSlave

FeedMaster

FeedSlave

GroupMaster

GroupSlave

FeedLogic

View

Controller Model

UserController

FeedController

GroupController

master

slave

master

slave

slave

masterGroupLogic

13年1月14日月曜日

Page 50: 初心者エンジニアのシステム構築失敗談

Model  Data・DBへのアクセスを管理する層

・connectionの設定、SQLを管理のみ

13年1月14日月曜日

Page 51: 初心者エンジニアのシステム構築失敗談

1

class  TestMasterShard  <  ActiveRecord::Base    self.abstract_class  =  true    establish_connection  "#{ENV['RAILS_ENV']}_test_master"end

class  FooMaster  <  TestMasterShard    self.table_name  =  'foo'    attr_accessible  :name    validates  :content_id,  {presence:  true}

   default_scope  where(is_deleted:  0)    scope  :hoge,  lambda  {  |foo|  where('bar  =  ?',  bar)  }end

production_test_master:    username:  test    password:  testdevelopment_test_master:    username:  test    password:  testtest_test_master:    username:  test    password:  test

13年1月14日月曜日

Page 52: 初心者エンジニアのシステム構築失敗談

Model  Logic

・Model Dataを用いて、master/slaveの処理をまとめる層

13年1月14日月曜日

Page 53: 初心者エンジニアのシステム構築失敗談

class  BaseLogic    include  ActiveModel::MassAssignmentSecurity    include  ActiveRecord::AttributeAssignment    include  ActiveModel::Conversion    include  ActiveModel::Validations    extend  ActiveModel::Naming    extend  ActiveModel::Translation

   def  persisted?;  false;  endend

class  TestLogic  <  BaseLogic    attr_accessor  :foo    attr_accessible  :foo    

   def  get_test_one        TestSlave.get_one    endend

13年1月14日月曜日

Page 54: 初心者エンジニアのシステム構築失敗談

UserLogic

Logic Data

UserMaster

UserSlave

FeedMaster

FeedSlave

GroupMaster

GroupSlave

FeedLogic

View

Controller Model

UserController

FeedController

GroupController

master

slave

master

slave

slave

masterGroupLogic

13年1月14日月曜日

Page 55: 初心者エンジニアのシステム構築失敗談

課題

・複数のテーブルをまたいでデータを処理する場合、どこにその処理を書くのかが不定

(Model  Logic  or  Controller)

13年1月14日月曜日

Page 56: 初心者エンジニアのシステム構築失敗談

現在

13年1月14日月曜日

Page 57: 初心者エンジニアのシステム構築失敗談

課題

・複数のテーブルをまたいでデータを処理する場合、どこにその処理を書くのかが不定

(Model  Logic  or  Controller)

13年1月14日月曜日

Page 58: 初心者エンジニアのシステム構築失敗談

ControllerとModelの間に一層((Context))を追加

サービス層に近い

方針

13年1月14日月曜日

Page 59: 初心者エンジニアのシステム構築失敗談

View

Controller Model

UserControllerUserMaster

UserSlave

UserLogic

Logic Data

Context

UserContext

FeedMaster

FeedSlave

FeedLogic

GroupMaster

GroupSlave

GroupLogic

FeedController

GroupController

FeedContext

GroupContext

master

slave

master

slave

slave

master

DBのデータを適切な形で受け渡すのみ

ユーザーのしたいことを実現する処理の流れ

13年1月14日月曜日

Page 60: 初心者エンジニアのシステム構築失敗談

Model Data

・DBへのアクセスを管理する層

・connectionの設定、SQLを管理するだけに留める

13年1月14日月曜日

Page 61: 初心者エンジニアのシステム構築失敗談

Model Logic

・Data層をコントロールする層

・一つのテーブルに一つ

・受け持つテーブルのデータの処理に関してのみ責任を負う

13年1月14日月曜日

Page 62: 初心者エンジニアのシステム構築失敗談

Context・ ユーザーのしたいことを実現するための処理の流れを実装する

-->>ユーザが操作する内容ごとに実装

・Controllerと11::11対応させる

13年1月14日月曜日

Page 63: 初心者エンジニアのシステム構築失敗談

Controller

・Contextで作成されたデータをViewに受け渡す

cellsを使って、uriで表現されている処理のみを実装するようにしている

13年1月14日月曜日

Page 64: 初心者エンジニアのシステム構築失敗談

View

・データを描画する

・ここにロジックは書かない

13年1月14日月曜日

Page 65: 初心者エンジニアのシステム構築失敗談

View

Controller Model

UserControllerUserMaster

UserSlave

UserLogic

Logic Data

Context

UserContext

FeedMaster

FeedSlave

FeedLogic

GroupMaster

GroupSlave

GroupLogic

FeedController

GroupController

FeedContext

GroupContext

master

slave

master

slave

slave

master

DBのデータを適切な形で受け渡すのみ

ユーザーのしたいことを実現する処理の流れ

13年1月14日月曜日

Page 66: 初心者エンジニアのシステム構築失敗談

課題

・validationをどうする?

13年1月14日月曜日

Page 67: 初心者エンジニアのシステム構築失敗談

Validation

13年1月14日月曜日

Page 68: 初心者エンジニアのシステム構築失敗談

・Railsは22つのvalidation

が一緒になってる

13年1月14日月曜日

Page 69: 初心者エンジニアのシステム構築失敗談

・ユーザーが入�力した値のチェック

・DBに格納する前のデータのチェック

13年1月14日月曜日

Page 70: 初心者エンジニアのシステム構築失敗談

今の構成

13年1月14日月曜日

Page 71: 初心者エンジニアのシステム構築失敗談

View

Controller Model

UserControllerUserMaster

UserSlave

UserLogic

Logic Data

Context

UserContext

FeedMaster

FeedSlave

FeedLogic

GroupMaster

GroupSlave

GroupLogic

FeedController

GroupController

FeedContext

GroupContext

master

slave

master

slave

slave

master

DBのデータを適切な形で受け渡すのみ

ユーザーのしたいことを実現する処理の流れ

13年1月14日月曜日

Page 72: 初心者エンジニアのシステム構築失敗談

Contextが入�ったことでvalidationでエラーが起きた時のARオブジェクトの受け渡しをどうするか?

13年1月14日月曜日

Page 73: 初心者エンジニアのシステム構築失敗談

Contextでは複数のARオブジェクトが格納されて、その中からvalidationエラーをまとめる。。。。

13年1月14日月曜日

Page 74: 初心者エンジニアのシステム構築失敗談

正直面倒

13年1月14日月曜日

Page 75: 初心者エンジニアのシステム構築失敗談

Validation・ユーザーが入�力した値のチェック

・DBに格納する前のデータのチェック

13年1月14日月曜日

Page 76: 初心者エンジニアのシステム構築失敗談

分ける!

13年1月14日月曜日

Page 77: 初心者エンジニアのシステム構築失敗談

DBに格納する前のデータのチェック

今まで通りARのvalidateを使う

13年1月14日月曜日

Page 78: 初心者エンジニアのシステム構築失敗談

ユーザーが入�力した値のチェック

??

13年1月14日月曜日

Page 79: 初心者エンジニアのシステム構築失敗談

ユーザーが入�力した値のチェック

リクエストを受けとった直後が望ましい

13年1月14日月曜日

Page 80: 初心者エンジニアのシステム構築失敗談

controllerのbefore_filterでやる

13年1月14日月曜日

Page 81: 初心者エンジニアのシステム構築失敗談

・ユーザーが入�力した値のチェック

==>> Controllerのbefore_filter

・DBに格納する前のデータのチェック

==>> Model

13年1月14日月曜日

Page 82: 初心者エンジニアのシステム構築失敗談

before_filterで

Validation

13年1月14日月曜日

Page 83: 初心者エンジニアのシステム構築失敗談

DataValidatorを書きました

13年1月14日月曜日

Page 84: 初心者エンジニアのシステム構築失敗談

13年1月14日月曜日

Page 85: 初心者エンジニアのシステム構築失敗談

DataValidator

ARのvalidatorとほぼ同じバリデーションロジックを実装しています

13年1月14日月曜日

Page 86: 初心者エンジニアのシステム構築失敗談

params  =  {foo:  'foo',  bar:  'bar'}

validator  =  DataValidator::Validator.new(    params,    {foo:  {length:  {is:  4}}},    {bar:  {presence:  true,  format:  {with:  /\A[a-­‐zA-­‐Z]+\z/}}})

unless  validator.valid?    @errors  =  validator.errorsend

@errors=>  {    foo:  ["is  the  wrong  length  (should  be  4  characters)"],    bar:  ["can't  be  blank",  "is  invalid"]}

13年1月14日月曜日

Page 87: 初心者エンジニアのシステム構築失敗談

・ユーザーの入�力値

==>> Controllerのアクション毎にDataValidatorを使う

・DBに格納する値

==>> ModelでActiveRecordを使う

13年1月14日月曜日

Page 88: 初心者エンジニアのシステム構築失敗談

Controllerでvalidationした後は、ユーザーの入�力値は正しい値としてみなし、DBに入�れる値をチェックする時にエラーになった場合はシステムのエラーとみなし例外で落とす

13年1月14日月曜日

Page 89: 初心者エンジニアのシステム構築失敗談

VVaalliiddaattoorr

VVaalliiddaattoorr

VVaalliiddaattoorr

View

Controller Model

UUsseerrCCoonnttrroolllleerr

UUsseerrMMaasstteerr

UUsseerrSSllaavvee

UUsseerrLLooggiicc

Logic Data

Context

UUsseerrCCoonntteexxtt

FFeeeeddMMaasstteerr

FFeeeeddSSllaavvee

FFeeeeddLLooggiicc

GGrroouuppMMaasstteerr

GGrroouuppSSllaavvee

GGrroouuppLLooggiicc

FFeeeeddCCoonnttrroolllleerr

GGrroouuppCCoonnttrroolllleerr

FFeeeeddCCoonntteexxtt

GGrroouuppCCoonntteexxtt

mmaasstteerr

ssllaavvee

mmaasstteerr

ssllaavvee

ssllaavvee

mmaasstteerr

DDBBのデータを適切な形で受け渡すのみ

ユーザーのしたいことを実現する処理の流れ

13年1月14日月曜日

Page 90: 初心者エンジニアのシステム構築失敗談

・この構成で落ち着いてます

・これ以上は手を入�れない予定

13年1月14日月曜日

Page 91: 初心者エンジニアのシステム構築失敗談

Railsやめちゃいなよってつっこみはなしです>>__<<

13年1月14日月曜日

Page 92: 初心者エンジニアのシステム構築失敗談

gem・data_validator

・rack_session_redis_store

・redis_json_serializer

13年1月14日月曜日

Page 93: 初心者エンジニアのシステム構築失敗談

ご清聴ありがとうございました!

13年1月14日月曜日

Page 94: 初心者エンジニアのシステム構築失敗談

時間があれば。。。。

13年1月14日月曜日

Page 95: 初心者エンジニアのシステム構築失敗談

画像・ファイルストレージ

13年1月14日月曜日

Page 96: 初心者エンジニアのシステム構築失敗談

・分散ファイルシステムを自前で作る?

・色々なアプリでAPIちっくに使いたい

13年1月14日月曜日

Page 97: 初心者エンジニアのシステム構築失敗談

画像・ファイルストレージ

・sinatraでappは作成

・閲覧権限等は本体で管理

・自前で分散ファイルシステム構築は難しいのでS3を使用

・Storage  Proxyパターン

Nginx

varnish

sinatra app

varnish

sinatra app

App(RoR)

AWS VPC

HTTP

S313年1月14日月曜日

Page 98: 初心者エンジニアのシステム構築失敗談

サーバー構成

13年1月14日月曜日

Page 99: 初心者エンジニアのシステム構築失敗談

オールAWS!

13年1月14日月曜日

Page 100: 初心者エンジニアのシステム構築失敗談

public

subnetservice

subnetutility

APP

DB

redis

worker

subnetstorage

subnetfluentd

deliver

worker

proxy

varnish+

sinatra

f f f

f f

f f

Watch

subnetnetwork

Gateway NATSSLの変換

13年1月14日月曜日

Page 101: 初心者エンジニアのシステム構築失敗談

その他・session storeにredis

・queue処理はfluentd + resque    =>  http://spring-­‐mt.tumblr.com/post/35097726578/fluent-­‐plugin-­‐resque

・fluentd  +  GrowthForecastを使った集計と可視化

13年1月14日月曜日

Page 102: 初心者エンジニアのシステム構築失敗談

13年1月14日月曜日