EC2上でLVMによるディスクの統合

Amazon EC2で、Instance StoreタイプのLarge Instanceにした場合、使えるディスクの容量は、850GBとなっている。
だけど、dfのコマンド叩いてみても、/ と /mnt 合わせても、420GB程度にしか見えない。
どういうことかと、さんざん調べた結果、/mnt にマウントされてる、/dev/sdb の他に、/dev/sdc ってのがあって、
それを、適当なとこにマウントすれば、合わせて、820GBになるとのこと。

確かに、合計サイズとしては、850GBなんだけど、どうしても420GB×2じゃ、都合が悪かった。
そこで、2つのディスクを1つのディスクに見せかけて何とか、デカイ容量にしようと企んだ。


LVM2を使ってやったので、以下は、その作業ログ。
環境は、Ubuntu 10 Server(x86_64)。

  • まずは、LVMをインストール
$ sudo apt-get install lvm2
  • モジュールのロード
$ sudo modprobe dm-mod
  • 物理ボリューム(PV)の作成
$ sudo pvcreate /dev/sdb 
  Can't open /dev/sdb exclusively.  Mounted filesystem?   #マウントされんじゃねーの?って怒られた

# マウント解除
$ sudo umount /mnt

# 改めて、/dev/sdb と /dev/sdc  のPV作成
$ sudo pvcreate /dev/sdb 
  Physical volume "/dev/sdb" successfully created
$ sudo pvcreate /dev/sdc
  Physical volume "/dev/sdc" successfully created

# 確認
$ sudo pvscan
  PV /dev/sdb                      lvm2 [419.97 GiB]
  PV /dev/sdc                      lvm2 [419.97 GiB]
  Total: 2 [839.93 GiB] / in use: 0 [0   ] / in no VG: 2 [839.93 GiB]
  • ボリュームグループ(VG)の作成
# vkvsって名前で、/dev/sdv と /dev/sdc でグループ作成
$ sudo vgcreate vkvs /dev/sdb /dev/sdc 
  Volume group "vkvs" successfully created

# 確認
$ sudo vgs
  VG         #PV #LV #SN Attr   VSize   VFree  
  vkvs   2   0   0 wz--n- 839.93g 839.93g
  • 論理ボリューム(LV)の作成
# lkvsって名前で、LV作成(サイズは、適当に)
$ sudo lvcreate -L 835G -n lkvs vkvs
  Logical volume "lkvs" created

# 確認
$ sudo lvscan
  ACTIVE            '/dev/vkvs/lkvs' [835.00 GiB] inherit
$ sudo mkfs.ext3 -j /dev/vkvs/lkvs
  • さて、いよいよマウントしてみる
$ sudo mount /dev/vkvs/lkvs /mnt

$ df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/sda1              9.9G  1.4G  8.0G  15% /
〜〜略〜〜
/dev/mapper/vkvs-lkvs  822G  201M  780G   1% /mnt

よし。成功だー!
あとは、残作業。


  • fstab に書き込んで、次回起動時からマウントされるように設定
$ cp /etc/fstab /etc/fstab.old

$ emacs /etc/fstab
# /etc/fstab: static file system information.
# <file system>                                 <mount point>   <type>  <options>       <dump>  <pass>
proc                                            /proc           proc    nodev,noexec,nosuid 0       0
/dev/sda1                                       /               ext3    defaults            0       0
/dev/vkvs/lkvs                                  /mnt            auto    defaults            1       2      # <= 追記
  • module を起動時に、loadされるように設定
$ sudo emacs /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

# LP: #450463
acpiphp
dm-mod       # <= 追記
  • 再起動してみる
$ sudo reboot

$ df -h
Filesystem             Size  Used Avail Use% Mounted on
/dev/sda1              9.9G  1.4G  8.0G  15% /
〜〜略〜〜
/dev/mapper/vkvs-lkvs  822G  201M  780G   1% /mnt

やった。これで、次回起動時から(AMI作ってたら?Rebootしても?)850GBに近い容量のディスクをマウントした状態で使えるぞ!

第3回 HTML5+α勉強会@福岡

今回も始まりましたHTML5
いやー、1月って忙しいですよね。そんな言い訳からはじめました。
みなさん、ごめんなさい。。予定してた内容の半分でのLTでしたが、
Web Socketsには、多くのニーズや興味があり、途中でサーバー側の
デバッグしている間にも、多くの議論が行きかってました。
結果的には、良いセッションになった!?(笑)

そんなこんなで、調査不足なんぞもありましたが、参加者の皆さん、ありがとうございました。

次回は、他の方の会話も含めて、もっとプロトコル寄りな議論ができそうです。
ただし、次回は、マークアップ側の勉強会の予定ですので、その辺はLTにて。

第2回 HTML5+α勉強会@福岡

参加してきました。
今回は、メインでやらせてもらいましたが、直前までデモ作ってたりしました・・
そのせいで、LTを先にやってもらうなど、皆さんには、感謝の至り。
id:re_shikajiro さん、id:kimpo さん、ありがとうございました。

そんなこんなで、調査不足なんぞもありましたが、参加者の皆さん、ありがとうございました。


まだ先かもしれないけど、クラウド技術の発展によって、オフラインアプリケーションの重要性は増してくると思ってます。

MA5とクロスドメイン

http://mashupaward.jp/に作品応募しました。
1.5ヶ月程前のHTML5@福岡の勉強会の懇親会の中で、MA5参加しようって話になって、実装し始めたのが、応募の締め切り2日前・・(なにかと思うけど、追い詰められるまでやらないの何とかしなきゃw)
結局、そんなこんなで、想定したものは、作れず妥協しまくった結果、なんか普通のWebアプリになっちゃいましたが、なんとか応募締め切り4分前に応募が完了できました。
でも、『参加したことに意義がある』と勝手に思ってます。(次回こそ)

さてさて、そんな中で、各種APIを使うのがMashupですが、FlexAPIで実装したこともあり、Flashのセキュリティエラーに幾度となくAPIが利用できない場面に遭遇しました。
それは、使いたいAPIドメインに"crossdomain.xml"が設置されていなかったり、APIドメイン自体には設置されてるけど、レスポンスで返ってきた値の中の画像のURL先ドメインには、設置されてなかったりと、実装中、一番苦しみました。

また、出来たアプリケーション(swfファイル)をサーバーにデプロイすると、ローカル環境では、OKだけど、NGだったりと。。

前置きが長くなりましたが、サーバーにFlexアプリケーションをデプロイする際には、以下のようにFlex側のコードには、"crossdomain.xml"のURLを指定して読み込ませるのが、楽チンのようです。(というか指定しなくてもいけるか分かんないけど)

  Security.loadPolicyFile("http://ドメイン名/どこか/crossdomain.xml");

この一番のメリットは、"corssdomain.xml"の設置箇所が、ドメイン名の直下でない場合です。
実際の"crossdomain.xml"のある場所を指定できるのです。
いつかどこかで困った際には、思い出してください(笑)

Flex開発では、UI設計に気をつけて!

拝啓、Flexを始めて採用しようとしているWebアプリケーション開発者の方々へ。


ActionScriptが、他の言語と違う点として、後付で、UI系の言語実装を追加したのではなく、UI系ありきで、設計された言語といわれています。
そして、これを実感したのは、Flexを始めて採用したプロジェクトをやったときの話・・

画面設計時に、ButtonやCanvasなんかの配置としての画面構成は、概ね決まっていました。
ですが、コンポーネントの階層までは、意識しておらず、つまりは、平面1枚の画面構成だけが、決まっている形でした。

そして、イベントを拾うコンポーネントは、どの階層のコンポーネントで、やるかは深く考えずに、対象コンポーネントに登録して、実装していった結果。。。

といった具合に、メンテナンス性が抜群に悪いモノが出来てしまったのでした。
(加えていうなら、View部分以外にも、問題はあったんだけど、それはまた別のお話)


では、次に、以下のサンプルコードを試してみてください。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        creationComplete="init()" 
        layout="absolute">

    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            
            private function init():void {
                exeButton.addEventListener(MouseEvent.CLICK, buttonClick);
                msgLabel.addEventListener(MouseEvent.CLICK, labelClick);
                mainCanvas.addEventListener(MouseEvent.CLICK, canvasClick);
                mainPanel.addEventListener(MouseEvent.CLICK, panelClick);
            }
            
            private function buttonClick(event:MouseEvent):void {
                Alert.show("button");
            }
            
            private function labelClick(event:MouseEvent):void {
                Alert.show("label");
            }
            
            private function canvasClick(event:MouseEvent):void {
                Alert.show("canvas");
            }
            
            private function panelClick(event:MouseEvent):void {
                Alert.show("panel");
            }
            
        ]]>
    </mx:Script>
    
    <mx:Panel id="mainPanel" title="『ここはパネル』" width="100%" height="100%" layout="absolute">
        <mx:Canvas id="mainCanvas" width="80%" height="80%">
        
            <mx:VBox height="20%" borderColor="blue" borderThickness="2">
                <mx:Label text="階層構造は以下の通り" />
                <mx:Label text="<panel ⇒ canvas ⇒ label ⇒ button>" />
                
                <mx:Spacer height="100%" />
                
                <mx:Label id="msgLabel" text="『ここはラベル』" />
                <mx:Button id="exeButton" label="ボタン"/>
            </mx:VBox>
            
        </mx:Canvas>
    </mx:Panel>

</mx:Application>

Flexというか、ActionScript3では、イベントを発生させると、最上層のコンポーネントであるstageから順に最下層にあるコンポーネントまで、全てイベントを通知し、最下層に到達したら、さらに逆の順を辿って、最上層のstageまで通知が返っていく仕組みになっています。(上記のサンプルコードは、それが少し体感できるものじゃないかと思います)

では、想像してみてください。仕様上、このサンプルコードで書かれたコンポーネントの全てに、マウスのクリックイベントが必要だった時のことを。。

あなたなら、どうやって、それぞれのコンポーネントでクリックイベントを拾って実装しますか?w


と、何か、変な話になってしまいましたが、私の経験からは、少なくとも以下の点を考慮した設計をやった方がよい気がします。

この辺、Webディレクターの方々には、当然のことなんでしょうけど、Webアプリケーション開発者の視点から伝えたかったのは、Flex(RIA)開発の際には『UI設計は、しっかりやろう』ということです。

FlexでViewStackの子コンポーネントのインスタンス生成のタイミング

Flexで「ViewStack」を使って子コンポーネントを複数の画面として、切り替える場合には、その子コンポーネントの、creationCompleteを利用して、対象となる子コンポーネントを参照するのが、理想的です。(というか、そうでないと、インスタンス生成のタイミングがわかんないし。。)

で、creationCompleteを利用して、参照できない場合、子コンポーネントの「callLater」で対象のFunctionを呼び出したりするっていう手も、あるけれど、毎度、callLaterで参照するわけにも行かないので、ViewStackに、creationPolicyの属性を設定してあげよう。

<mx:ViewStack creationPolicy="all" >

これで、ViewStackのインスタンス生成時に、子コンポーネント達のインスタンスも生成されます。

Flex + Ruby (on Rails) でAMF通信とHTTP通信

クライアント側をFlexにし、サーバーをRailsで作成した通信に、
AMF通信とHTTP通信をそれぞれやってみました。

  • Railsプロジェクトを作成

Project Name : FlexServer
Use Database : sqlite3

rails FlexServer -d sqlite3

Rails Plugin : rubyAMF

ruby script/plugin install http://rubyamf.googlecode.com/svn/tags/current/rubyamf
  • rubyamf_config.rb の編集

> config/rubyamf_config.rb

ClassMappings.translate_case = true
ClassMappings.assume_types = true
  • 確認

サーバー起動

ruby script/server

http://localhost:3001/rubyamf/gateway

  • user の Controller/Model/View を生成

scaffold(rubyamf_scaffold もあるけど、今回は、利用せず)

ruby script/generate scaffold user
  • migration ファイルを修正

> db/migrate/xxxxxx_create_users.rb

def self.up
   create_table :users do |t|
     t.string :firstName
     t.string :lastName
     t.string :nickName
     t.integer :age, :limit => 3
     t.string :email, :default => 'anonymouse@gmail.com'
   ・・・・
  • DBとテーブルを生成
rake db:create
rake db:migrate
  • UsersControllerの編集

> app/controllers/users_controller.rb

def index
  @users = User.all
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @users }
    format.amf  { render :amf => @users }
  end
end
  • mimeTypeの設定と修正

split ってメソッド を to_s に委譲(delegate)します(通信時エラーになるので)
> config/initializers/mime_types.rb

Mime::Type.register "application/x-amf", :amf
Mime::Type.delegate :split, :to => :to_s
  • crossdomain.xmlの設定

セキュリティエラーでるので。。
> public/crossdomain.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM 
                "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
    <site-control permitted-cross-domain-policies="all" />
    <allow-access-from domain="*" />
</cross-domain-policy>
  • UserList.mxmlの実装

最後に、FlexMXMLの実装
> src/UserList.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        creationComplete="init()" 
        layout="absolute">
    
    <mx:Script>
        <![CDATA[
            import mx.rpc.http.HTTPService;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            
            private var amfFormat:Boolean;
            
            private function init():void {
                getAmfButton.addEventListener(MouseEvent.CLICK, getListForAmf);
                getHttpButton.addEventListener(MouseEvent.CLICK, getListForHttp);
            }
            
            // AMF通信
            private function getListForAmf(event:MouseEvent):void {
                this.amfFormat = true;
                
                var request:RemoteObject = this.userService;
                request.index();
                request.addEventListener(ResultEvent.RESULT, onResult);
                request.addEventListener(FaultEvent.FAULT, onFault);
            }
            
            // Web通信
            private function getListForHttp(event:MouseEvent):void {
                this.amfFormat = false;
                
                var request:HTTPService = new HTTPService();
                request.url = "http://localhost:3001/users.xml";
                request.resultFormat = HTTPService.RESULT_FORMAT_E4X;
                request.send();
                request.addEventListener(ResultEvent.RESULT, resultHandler);
                request.addEventListener(FaultEvent.FAULT, faultHandler);
            }

            private function resultHandler(event:ResultEvent):void {
                trace("onResult : " + event.result);
                if (amfFormat) {
                    userList.dataProvider = event.result;
                    msgLabel.text = event.result.toString();
                } else {
                    userList.dataProvider = event.result.user;
                    msgLabel.text = event.result.user.toString();
                }
            }

            private function faultHandler(event:FaultEvent):void {
                trace("onFault : " + event.fault);
                msgLabel.text = event.fault.faultString;
            }

        ]]>
    </mx:Script>
    
    <mx:RemoteObject id="userService"
                     destination="rubyamf"
                     endpoint="http://localhost:3001/rubyamf_gateway/"
                     source="UsersController" />

    <mx:VBox width="100%">
        <mx:DataGrid id="userList" width="100%">
            <mx:columns>
                <mx:DataGridColumn dataField="id" headerText="ID"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="firstName" headerText="FirstName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="lastName" headerText="LastName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="age" headerText="Age"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="nickName" headerText="NickName"></mx:DataGridColumn>
                <mx:DataGridColumn dataField="mail" headerText="Mail"></mx:DataGridColumn>
            </mx:columns>
        </mx:DataGrid>
        
        <mx:Button id="getAmfButton" label="Get for Amf" />
        <mx:Button id="getHttpButton" label="Get for Http" />
        
        <mx:Label id="msgLabel" />
    </mx:VBox>

</mx:Application>

Rails側のformatに対応したボタンをそれぞれ準備しました。
Rails側の

    format.amf  { render :amf => @users }

が、Flexの「Get for Amf」のボタンに対応し、

    format.xml  { render :xml => @users }

が、Flexの「Get for Http」のボタンに対応してます。

  • 実行

データを多く準備して、レスポンスを計測してみると、どちらが早いか検証できると思います。
やって見た方は、是非、レスポンスタイムとか教えて欲しいっす。