« 2011年10月 | トップページ | 2011年12月 »

2011年11月

2011年11月27日 (日)

Mongorilla: Object Document Mapper for MongoDB

Mongorillaについて

Mongoidの弱点を克服するために作成したObject Document Mapper.
名前の由来は、Mongoと娘の好きな動物のgorillaを掛けあわせた。

インストール

gem install mongorilla

ソース
github

長所

  1. 今のところ、わずか300行ちょっとの小ささ。
  2. シングルサーバ、Master/Slave、ReplicaSetに対応。
  3. 単純な処理はMongoidと変わらず、複雑な処理も対応。
  4. クエリ発行時に接続失敗しても、指定回数リトライできる。
  5. findクエリに対してMasterとSlaveのどちらを参照するか指定できる。

短所

  1. リレーション関連は自分で管理する必要がある。
  2. 各フィールドの型も自分で整合性を保証する必要がある。

sample

require 'mongorilla'
# クラス名をunderscore化+複数形にしたcollectionが作成される
class User
  # クラス名+ Fieldsの定数に使用するフィールドをsymbolで定義
  UserFields = [:_id,:name,:password,:logs,:log_count]
  # Mongorillaを使うことを宣言
  include Mongorilla::Document
end
#アプリ起動時1回のみ呼び出す必要(設定ファイルに基いてDBに接続している)
Mongorilla::Collection.build(File.expand_path("../config.yml",__FILE__))
#ユーザデータをDBに登録し、登録したレコードを呼び出す
user = User.create(:name => "morita",:password => "pass")
#非同期で作成したい場合
User.create({:name => "morita",:password => "pass"},{:safe => false})
#複数ユーザ同時に作成したい場合
users = User.create([{:name => "morita",:password => "pass"},{:name => "yoshida",:password => "hello"}])
#IDで検索する場合 1オブジェクトのみ返る
u = User.find(user.id)
#属性で検索する場合 条件に一致したオブジェクトすべてがArrayで返る
us = User.find({:name => "morita"})
#オプションをつける。 :master => trueのみ独自(master DBから検索)。
#それ以外はmongo driverに等しい。
us = User.find({:name => "morita"},{:master => true,:limit => 3})
#件数を調べる。(find.countだとレコードをすべてObjectに変換した後、countしてしまうため)
count = User.count({:name => "morita"})
#属性の変更 DBにはsaveを実行するまで更新されない。 
u.name = "mora"
#属性の変更 DBにはsaveを実行するまで更新されない。
u.push("logs","oooo")
#属性の変更 DBにはsaveを実行するまで更新されない。p u.logs => ["oooo","aaa"]
u.push("logs","aaa")
#属性の変更 DBにはsaveを実行するまで更新されない。p u.log_count => 2
u.inc("log_count",2)
#上記の変更がDBに反映される(デフォルトは同期)
u.save
#属性の変更 DBにはsaveを実行するまで更新されない。p u.log_count => 1
u.inc("log_count",-1)
#条件を指定して更新。この場合は条件を満たさないため失敗
ret = u.save({:log_count => {"$gt" => 10}})
#false
p ret
# 2 失敗した場合は、元のデータに戻される
p u.log_count
# $pullの実行 ただしpullの場合はオブジェクトに反映されない(複雑だから。) p u.logs => ["oooo","aaa"]
u.pull("logs","oooo")
# 上記に合わせて、件数を減らす
u.inc("log_count",-1)
# RELOADの指定は、レコードの更新が成功した場合に、更新したレコードをDBから取り出して、
# オブジェクトの内容を更新する。$pullを使用した場合はオブジェクトとDBのレコードの間に
# 不整合ができるため、行うほうがいい。RELOAD以外は、SYNC(デフォルト)、ASYNC(非同期)がある
ret = u.save({:log_count => {"$gt" => 1}},Mongorilla::Document::RELOAD)
# pullをしてreloadしたことにより、"oooo"が取り除かれた。["aaa"] 
p u.logs

設定ファイル

Mongorilla::Collection.buildに渡す設定ファイル(yaml形式)のフォーマット

Single Serverの場合

host: localhost #任意
port: 27017     #任意
database: dev   #必須

Master/Slaveの場合

host: localhost     #必須
port: 27017         #必須
database: dev       #必須
slaves:             #必須
  - host: localhost #必須
    port: 27018     #必須


Replica Setの場合

hosts:
  - - localhost #HOST
    - 27017     #PORT
  - - localhost
    - 27018
  - - localhost
    - 27019
database: dev

内部実装について

Mongorilla::Documentをinclude指定された際に、指定されたフィールドごとにgetterとsetterを動的に作成している。
getterはメソッド呼びだし時にinitialize時に渡されたMongoのレコード(@docに保存)に対してフィールド名でアクセスした結果を返している。
setterは@changesに@changes["$set"][フィールド名] = 変更された内容をセットして、@docの内容を更新している。
saveを呼び出した時は、@changesの内容を用いてupdateしている。
複雑な更新をしたい場合は、Obj#changesで@changesを取得して変更し、@docの内容を更新する。
フィールドにセットするデータをチェックしたい場合は、def フィールド名= のメソッドをオーバーライドする。
リレーションの管理方法は、また今度。

| | コメント (0) | トラックバック (0)

Mongoidの限界について

Mongoidの限界

  1. 条件指定のupdateができない。
  2. $incと$pushが同時に使えない。
  3. Hash,Arrayのフィールドに対して、一部のキーのみの更新ができない
  4. save時に参照する必要のないHas_oneの関連のクエリを発行
  5. 変更したオブジェクトに対してreloadを実行すると不整合になる

条件指定のupdateができない

アイテム購入時に、金額が$200以上保持している場合のみ、アイテムを付与するといった
ことができない。アプリケーションが1プロセスの場合は、事前に取得したレコードの金額
を比較することで対処できるが、複数プロセスの場合は、事前に取得したレコードの内容
と更新時のレコードの内容が等しいとは限らないため、更新時に$200以上の場合のみアイテム
付与といったことをMongoDBでする必要がある。

$incと$pushが同時に使えない

Arrayでデータを保存していて、配列のサイズが10以下の場合のみ更新するという場合、
配列のサイズをに対して$gtや$ltなどの比較演算子が使えない($sizeで一致の場合は使える)
ため、Arrayのサイズを記憶するフィールドを別に持つ必要があり、その場合、$pushと$incを
同時に発行する必要がある。

Hash,Arrayのフィールドに対して、一部のキーのみの更新ができない。

{'a' : 1}の値があるフィールドに'b' : 2のデータを追加して更新すると{'a' : 1,'b': 2}とすべての
データで更新してしまうため、他のプロセスが更新したデータを上書きしてしまう。

save時に参照する必要のないHas_oneの関連のクエリを発行

データサイズを小さくするために、あまり参照されないデータは、has_oneの関係で外出しに
するが、関連元のレコードをsaveする際に、外出しにしているhas_oneのレコードにfindの
クエリを発行するため、せっかく外出しにした意味がなくなる。

変更したオブジェクトに対してreloadを実行すると不整合になる

上記の理由により、MongoDriverから直にデータをDBを更新し、Mongoidのオブジェクトを
整合性を取るために更新した内容にセットした状態で、そのオブジェクトにreloadを実行すると

同じレコードが重複したりする。

まとめ

MongoidはActive Modelをincludeしていて、ActiveRecordに慣れたユーザが簡単に導入できるという利点がある。 ただ、高負荷がかかり、データの不整合が許されないような現場で使用するには問題がある。 その対応策として、MongorillaというObject Document Mapperを自作した。 次回はその紹介をしたい。

| | コメント (0) | トラックバック (0)

2011年11月15日 (火)

MongoDBをアプリで使う時に気をつける点

ソーシャルゲームのアプリにMongoDBを使っていて困った点

1. joinがないため、マスタデータの参照が多いページのレスポンスが遅い

2. 複数collectionにまたがって更新が必要な場合に、ShutDown,バグ等により中途半端にコレクションを更新して、データの不整合が発生することがある。

3.集計関数には、MapReduceを使う必要があるが、リアルタイムで行うには負荷が重い。

4. Mongoidがレースコンディションに弱い。
a.条件を指定した更新ができない。
b. incとpushを同時に行うとようなAtomicな操作を行えない。
c. HashやArrayに対して、pushではなく、全体をセットしてしまう。

上記の弱点は、1作目で発覚したため、2作目以降は下記の対応を行った。

1.に関しては、マスターデータをMongoDBに格納するのではなく、Hash形式にしてAmazon:S3にUploadして、Webサーバ起動時にS3からDownloadして参照できるようにした。
わざわざS3を使う訳は、管理画面でマスターデータを登録するようにしているため。管理画面でデータの更新をするとそのデータがS3にUpされるので、次回のWebの起動時に反映される。

2.に関しては、Embeded Documentを活用し、なるべく1つのDocumentで更新が完了するよう心掛けた。
また、どうしても複数Documentの更新が必要な場合は、updateをsafe=>trueで呼び出し、確実に更新されたことを確認した後次のDocumentを更新するようにし、Documentの更新が途中までしか進まなかったとしても、対応可能なように設計。
例えばアイテム購入の場合は、アイテム所持情報にアイテムを追加し、ユーザ情報の金額を減らすという2つのDocumentの更新になるが、まずアイテム所持情報を更新の完了を確認してから、ユーザ情報の更新をするため、たとえユーザ情報の更新失敗しても、ユーザには不利益がでないようになるなど。

3.に関しては、AWSのSimpleDBはKVSでありながら、集計関数も使えるため、simpleDBを使用。集計関数を使いたい箇所はランキングなため、SimpleDB用のランキング用のライブラリを作成した。
ranking-simpledb
ただし、遅い。largeインスタンスでTop10表示が5.49req/sec。Topのみだと16.32req/sec。
理由は、Webサーバ側のCPU負荷。負荷試験をすると、CPUは次の値。user:67.55%,nice:0.0%,system:2.32%,iowait:0.0%,steal:27.98%,idle:2.15%
Webサーバを2台にすると、16.32req/sec→32.38req/secに
スループットが向上。

4.に関しては、更新時は、Mongoidではなく、Mongoドライバを使うようにした。

| | コメント (0) | トラックバック (0)

第14回 yokohama.rbに参加しました。

退職したため、求人サイトをチェックしていると、
18:00ぐらいにTwitterで"I'm at 神奈川地区
センター"とあり、これは、yokohama.rbが開催
されるのでは?とATNDをチェックすると、BINGO。
土曜日は仕事が入っていたので、スルーしていた。
久しぶりに参加できるので、これは楽しみと思い、
妻に時間がないから車で送ってくれないかとお願い
したところ、韓流のDVDがいいところのようで、
かなりいやそうだった。

「勉強会に出ているメンバーで、自分の会社に開発者
を募集しているとか、知り合いの勤めている会社が
募集しているよという話が聞けるかも知れないよ?」と
妻を説得し、急いで妻に車で送ってもらった。

開始18:30前に到着。
本来は18:00ごろに来て設営等の準備を手伝うべきと
ころだが、今回は許してくだしぁ。

自己紹介が始まり、仕事募集中をアピール。
Rubyのコミッターの方がいたり、プログラマを目指して
上京してきた方がいたり、これからRubyを学習したり
する方がいたりと層が幅広い。

@nagachicaさんから、Macのruby-coreaudioという
ライブラリのセッションが開かれたが、私はWindows
なため、不参加。

隣りに座っていた@u16suzuさんと仕事の話をしていた
ら、自社に問い合わせてくださることになった。本当あ
りがとうございます。

せっかくプログラマの方達といるので、ペアプロをした
いなと相手を探していたら、@u16suzuさんはモクモク
作業ですることを決めていたようなので、前に座っていた
@publichtmlさんに声をかけて、ペアプロ開始。

仕事では、PHPを使っていて、rubyはかじった程度という
話でirbが立ち上がったのを見て、感動されていた。

お題は、Hashの値の比較を文字列でもSymbolでも同じ
綴りだと同値だと見なすようなHashが欲しいというもの。
キーの場合は、HashWithIndifferentAccessという
ActiveSupportのクラスがある。
今回はキーではなく、値で同じことをしようという目論見。
最近は値にSymbolにするのはやめて、文字列に統一する
ようにしているが、''の2文字より:の一文字が楽だなぁと。

ペアプロしていて、クラス変数やインスタンス変数という
用語が通じず戸惑ったが、 説明すると、 あっJavaでいう
static変数のことですねやメンバ変数のことですねとすぐに
理解された。@publichtmlさんは、仕事はPHPをされている
そうだが、最近テストも書いているとおっしゃるだけあって、
飲み込みが早い。

実装案として、Hashクラスを継承するのではなく、内部で
hashを持ち、代入時に値がSymbolだったら、文字列にして
格納して、==で見るときに比較する値がSymobolだったら
文字列にすればと提案を受け、なるほどと思いその線でいく
ことになった。

initializeで渡って来たHashの値のsymbolを文字列に格納する
ところまではTestを書いて通るところまで実装できた。
比較の処理のところで、[]の返却値と比較するから、比較する
値がSymobolだったら文字列にする戦略は無理では?と指摘を
うけたが、[]=を[]==と勘違いしてこのメソッドでいけると嘘を
答えてしまった。正しい指摘だったのに、ごめんなさい。
そんなのはないです。
大丈夫と経験者が言ってしまったら、初心者の方はそういうもの
かと思ってしまうので、本当に気をつけなければと思う。

結局、Hashを継承するのではなく、持っている関係なので、Hash
関連のメソッドをdelegateしないと駄目だよねとなって、delegate
の仕方を調査しているところでTimeUP。

その後家に帰って、続きを実装してみたのをgistにあげた。
実装
スペック
delegateの実装と、 []やvaluesで取り出した値にSymbolがあれば、
SimboledStringなる新たなStringクラスに変換し、そのクラスは==で
比較対象がSymbolだったら文字列に変換して比較するようにした。

ペアプロすると学ぶことが多くて勉強会向きな気がした。

| | コメント (0) | トラックバック (0)

2011年11月 6日 (日)

rubyによるAmazon EC2のインスタンスのセットアップ

Amazon EC2を使う利点

各種APIが公開されているため、プログラマブルにインスタンスのセットアップができるところにつきると思います。

他のクラウド(もちろんAmazon EC2も)は、Webブラウザ上でインスタンスの増減やロードバランサ等の設定ができますが、手作業が必要なため自動でスケーリングができません。

また、もしデータセンター(amazonではゾーンと呼ばれる)全体が障害に陥いったとしても、セットアップをプログラムで自動化しておけば、ゾーンのURLを書き換えて実行するだけで、同じ環境を違うゾーンに簡単に復元できます。

Amazon EC2 セットアップスクリプト

ubuntuの素のOSから、ユーザを作成し、memcachedをインストール設定、起動するまでのスクリプトを書いてみました。
使用しているライブラリは公式のruby sdkではなく、https://github.com/appoxy/aws を使っています。
理由は公式よりも機能が豊富だったから。
スクリプトは、インスタンスに、debian系のイメージを使用することが前提になっています。
なおこのスクリプト作成には、SoftwareDesign 2010年10月号 クラウド活用プログラミング入門 第5章 自動スケールアウトに挑戦という山崎 泰宏さんの記事をかなり参考にしました。

AWSのインストール

gem install aws

config.yml

admin_user: "ubuntu"
application_user: "app"
aws_access_key: "AWS ACCESS KEY"
aws_secret_key: "AWS SECRET KEY"
key_name: "ubuntu"
image_id: "ami-e49723e5"
instance_type: "m1.small"
pem_path: "ubuntu.pem"
key_pub: "ssh-rsa AAAAB3N?????????????????"

ec2_setup.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'aws'
require 'yaml'
require 'json'
require 'open3'

def create_ec2
  #EC2のインスタンスをTokyo regionで作成するように設定
  ENV["EC2_URL"] = "https://ec2.ap-northeast-1.amazonaws.com/"
  Aws::Ec2.new($config["aws_access_key"],$config["aws_secret_key"])
end

#EC2起動
def launch_instances(ec2)
    response = ec2.launch_instances($config["image_id"],
    {
      :min_count => $config["min_count"]||1,
      :max_count => $config["max_count"]||1,
      :user_data => $config["user_data"],
      :group_ids => [$config["security_group"]||"default"],
      :key_name => $config["key_name"],
      :instance_type => $config["instance_type"],
      :addressing_type       => nil,
      :kernel_id             => nil,
      :ramdisk_id            => nil,
      :availability_zone     => "ap-northeast-1a",
      :block_device_mappings => nil,
      :monitoring_enabled   => true
    })

    #作成したインスタンスのIDの配列を取得
    response.map{|instance| instance[:aws_instance_id]}
end

#インスタンスの起動完了を待つ
def wait_running(ec2,instance_ids)
  counter = 0
  unstart=true
  instance_dns_map = {}
  while(unstart)
    sleep 3
    counter += 1
    puts "*Status check...(#{counter})"
    instances = ec2.describe_instances(instance_ids)
    unstart = false
    instances.each do |instance|
      puts " Instance: #{instance[:aws_instance_id]} is #{instance[:aws_state]}"
      if instance[:aws_state] == "running"
        instance_dns_map[instance[:aws_instance_id]] = instance[:dns_name]
      else
        unstart = true
      end
    end
  end
  puts "All instances are running."
  instance_dns_map
end

#know_hostsから削除
def remove_known_hosts(hosts)
  f = "#{ENV['HOME']}/.ssh/known_hosts"
  ssh_hosts = File.read(f)
  new_rec = ""
  ssh_hosts.each_line do|el|
    rec = el
    hosts.each{|host| rec = "" if el =~ /#{host}/}
    new_rec += rec
  end
  File.open(f,"w"){|f| f.write(new_rec)}
end

#コマンドを実行する(system関数使わないのは、標準出力や標準エラー出力を受けとりたいため。)
def act_command(command,env={})
  puts command
  out = err = status = nil
  Open3.popen3(env,command) do|stdin, stdout, stderr, wait_thr|
    stdin.close
    out = stdout.read
    puts out if out && out != ''
    err = stderr.read
    if !err || err != ''
      STDERR.puts(err)
    end
    status = wait_thr.value
  end
  [status.to_i,out,err]
end

#sshコマンドを発行する StrictHostKeyCheckingのオプションは初回アクセスで未登録のホストに対してもエラーを出さない
def ssh_command(host,command)
  ssh = "ssh -o StrictHostKeyChecking=no -i #{$config['pem_path']} #{$config['admin_user']}@#{host} '#{command}'"
  act_command(ssh)
end

#scpコマンドを実行 directionはtoはリモートにcopy.それ以外はリモートからコピー
def scp(host,orig,dest,direction="to")
  if direction == "to"
    dest = "#{$config['admin_user']}@#{host}:#{dest}"
  else
    orig = "#{$config['admin_user']}@#{host}:#{orig}"
  end
  scp = "scp -o StrictHostKeyChecking=no -i #{$config['pem_path']} #{orig} #{dest}"
  act_command(scp)
end

#SSH接続ができるようになるまで待つ
def wait_ssh_up(instance_dns_map)
  counter = 0
  unstart=true
  while(unstart)
    sleep 3
    counter += 1
    puts "*SSH Connection check...(#{counter})"
    unstart = false
    instance_dns_map.each do |k,v|
      begin
        code = out = err = nil
        timeout(3) do
          code,out,err = ssh_command(v,'echo "success"')
        end
        if err && err =~ /REMOTE HOST IDENTIFICATION HAS CHANGED/
          act_command("ssh-keygen -R #{v}")
          unstart = true
        elsif code == 0
          puts " Try to ssh to an instance #{k}:#{v} Success."
          unstart = false
        else
          puts " Try to ssh to an instance #{k}:#{v} Failure."
          unstart = true
        end
      rescue Timeout::Error => e
        puts " Try to ssh to an instance #{k}:#{v} Timeout."
        unstart = true
      end
    end
  end
  puts "All instances ssh ready."
end

#アプリケーション用ユーザの作成
def user_setup(host)
  ssh_command(host,"sudo useradd -d /home/#{$config['application_user']} #{$config['application_user']}")
  ssh_command(host,"sudo mkdir -p /home/#{$config['application_user']}/.ssh")
  ssh_command(host,"sudo echo \"#{$config['key_pub']}\" > /tmp/authorized_keys")
  ssh_command(host,"sudo mv /tmp/authorized_keys /home/#{$config['application_user']}/.ssh/")
  ssh_command(host,"sudo chown -R #{$config['application_user']}:#{$config['application_user']} /home/#{$config['application_user']}")
end

#memcachedのインストール
def memcached_setup(host)
  ssh_command(host,"sudo mkdir -p /mnt/memcached/log")
  ssh_command(host,"sudo chown -R #{$config['application_user']}:#{$config['application_user']} /mnt/memcached")
  #質問に対して全部yesで返答
  ssh_command(host,"DEBIAN_FRONTEND=noninteractive sudo apt-get install --assume-yes memcached")
  scp(host,File.expand_path("../memcached.conf",__FILE__),"/tmp/memcached.conf")
  ssh_command(host,"sudo mv /tmp/memcached.conf /etc/memcached.conf")
  ssh_command(host,"sudo /etc/init.d/memcached restart")
end
#==========#
# MAIN処理 #
#==========#
#設定ファイルの読み込み
$config = YAML.load_file(File.expand_path("../config.yml", __FILE__))
keys = %w(admin_user application_user aws_access_key aws_secret_key
        key_name image_id instance_type pem_path key_pub)
if (remain_keys = keys - $config.keys) != []
  raise "config error: lack of #{remain_keys.join(',')} settings"
end
#EC2マネージャインスタンス作成
ec2 = create_ec2

#EC2インスタンス作成
instance_ids = launch_instances(ec2)

#インスタンスの起動完了を待つ
instance_dns_map = wait_running(ec2,instance_ids)

#以前に同じアドレスの違うインスタンスにログインしている可能性があるため、know_hostsから削除
remove_known_hosts(instance_dns_map.values)

#SSH接続ができるようになるまで待つ
wait_ssh_up(instance_dns_map)

instance_dns_map.each{|k,v|
  #アプリケーション用ユーザの作成
  user_setup(v)
  #memcachedのインストール
  memcached_setup(v)
}

memcached.conf

-d
logfile /mnt/memcached/log/memcached.log
# memory
-m 1440
# Run the daemon as root. The start-memcached will default to running as root if no
# -u command is present in this config file
-u app
-l 0.0.0.0

config.yml

admin_user
用意されている初期ユーザ 。使用するamiによって異ります。ubuntuの公式のイメージだとubuntuですが、イメージによってrootだったり、bitnamiだったりと異るため注意が必要です。

application_user

インスタンスのサーバのアプリを実行するユーザ。

aws_access_key

AWSのアクセスキー(AWSのアカウントのセキュリティ証明書のページに記載されています

aws_secret_key

AWSのシークレットアクセスキー(AWSのアカウントのセキュリティ証明書のページの表示リンククリックで表示されます)

key_name

EC2の初期ログインに必要なキーペアの名前 Management ConsoleでEC2を選択して、Key pairsを選択して作成。awsのライブラリを使って作成することもできます。

image_id

作成するインスタンスのイメージID(ami)

instance_type

インスタンスの種類(m1.largeとかm1.small)

pem_path

keynameで指定したキーファイルへのパス

key_pub

自分の公開鍵の文字列 インスタンスのセットアップが終了すると、立ち上がったインスタンスにapplication_userの名前でログインできます。

min_count

立ち上げたい最小インスタンス数(任意)

max_count

立ち上げたい最大インスタンス数(任意)

ec2_setup.rb

create_ec2
デフォルトだとvirginiaのリージョンになるので、tokyoリージョンになるように設定。

launch_instances

availability_zoneの設定は、もしzone全体に障害が起きた時は、create_ec2のEC2_URLとこの値を変更します。
monitoring_enabledはセットすると、clowdwathを使って、詳細メトリックスが取れます。 モニタリングの値もawsのライブラリで簡単に取れるので、cron等でチェックして負荷が高い時は、 スケールアウトさせることも容易です。
min_countやmax_countで同じイメージのインスタンスを同時に複数立ち上げることができます。

wait_running

インスタンスをlaunchしても1〜5分ぐらいstatusがpendingのまま。pending時間はその時によってまちまち。

remove_known_hosts

インスタンスの上げ下げをしていると同じアドレスの別インスタンスにぶつかり、前回とfinger_printが 違うのでエラーになって、ssh接続ができなくなるのを避けるため。

wait_ssh_up

sleepをしながら、SSH接続が成功するまで待ち続ける。 StrictHostKeyCheckingのオプションは、初回のsshアクセスの際にknow_hostsに追加していいかのプロンプトを出させなくするため。

user_setup

初期ユーザはno passwordでsudoができて危険なため、ユーザを作成し、公開鍵も登録してセットアップ完了時にログインができるようにする

memcached_setup

sudoが使えるのでapt-getでいれればいいだけだが、依存パッケージがある場合はインストールしていいかのプロンプトが出力されてしまうので、DEBIAN_FRONTEND=noninteractiveの設定と--assume-yes のオプションをつけています。

memcached.conf

logfile-mの設定は必須。EC2のディスク容量のほとんどは、/mnt配下に割り当てられている。 例えばsmallは、160G中147Gが/mnt以下に割り当てられています。
memoryはデフォルト64Mなので、メモリが許す範囲に割り当てなおします。

まとめ

実際やってみると、簡単ということがわかると思います。 基本的には、アップデートの容易さや他のアプリでの使い回しも考えると、素のOSのamiを使って、サーバのインストール、設定までを行うスクリプトを作成するのが望ましいですが、Webサーバのような負荷に応じて頻繁にインスタンスの上げ下げをする場合は、必要なパッケージや設定がすでにインストールされた状態の独自にamiを作成することで、インスタンスの立ち上がりからサービス開始までの時間を短縮させる必要があると思います。

| | コメント (0) | トラックバック (0)

« 2011年10月 | トップページ | 2011年12月 »