30分でDockerの雰囲気をつかむ(Macの場合)

はじめに

30分くらいでDockerの雰囲気をつかむ(Macの場合)

インストーラーのダウンロード(15分)

ダウンロードする。150MBくらい。
https://github.com/boot2docker/osx-installer/releases

Online TutorialをTry it !(同時進行)

15分で集中してがんばる。英語。
The best way to understand Docker is to try it!

インストールする(15分)

15分でインストールする。
Installing Docker on Mac OS X
コマンドはひと通り実行する。

まとめ

雰囲気だけを手っ取り早くつかめた。


あんちょこ
  • バージョン確認
$ docker version
  • コンテナイメージの検索
$ docker search hoge
  • コンテナイメージの取得
$ docker pull fuga
  • echoコマンドの実行
$ docker run fuga echo "hello world"
  • pingのインストール
$ docker run fuga apt-get install -y ping
  • コンテナ情報の表示(lで最近のコンテナのみ表示)
$ docker ps
$ docker ps -l
  • 変更をコミット
$ docker commit ID piyo
$ docker run piyo ping google.com
  • イメージ情報の表示
$ docker inspect ID

Apache SparkでTwitter Streaming

はじめに

Apache Sparkを利用してTwitter Streamingを取得する。
題材はampcampHands-on Exercisesを活用する。
Hands-on Exercisesはシリーズ物でEC2で稼働させたり、クラスタHDFSが必要みたいだけど、それらなしでがんばる。

前提条件

必要なもの

  • Sparkのインストール
  • Scala
    • ダウンロードして適当なディレクトリで解凍、パスを通す
  • TwitterのConsumer key (API key), Consumer secret (API secret), Access token, Access token secret
    • ここで取得できますよ
  • amplab/trainingが提供しているソースコード
    • ダウンロードして適当なディレクトリで解凍する、以降ここが作業ディレクトリ
  • Javaのバージョンは1.8.0_05だとうまく動かないので1.7.0_60へダウングレード

不必要なもの

JavaScalaのパスメモ

export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "1.7"`
export SCALA_HOME=/usr/local/bin/scala-2.11.1
export PATH=${JAVA_HOME}/bin:${SCALA_HOME}/bin/:$PATH
ソースコード
  • build.sbt
name := "Tutorial"

scalaVersion := "2.10.0"

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-streaming" % "0.9.0-incubating",
  "org.apache.spark" %% "spark-streaming-twitter" % "0.9.0-incubating"
)

提供ファイルのScala Versionは2.10。
それを2.10.0に変更する。

import org.apache.spark._
import org.apache.spark.SparkContext._
import org.apache.spark.streaming._
import org.apache.spark.streaming.twitter._
import org.apache.spark.streaming.StreamingContext._
import TutorialHelper._

object Tutorial {
  def main(args: Array[String]) {
    
    // Location of the Spark directory 
    val sparkHome = "インストールしたSparkディレクトリを指定"
    
    // URL of the Spark cluster
    val sparkUrl = "local"

    // Location of the required JAR files 
    val jarFile = "target/scala-2.10/tutorial_2.10-0.1-SNAPSHOT.jar"

    // HDFS directory for checkpointing
    // ローカルディレクトリに変更する
    val checkpointDir = "./hdfs/checkpoint/"

    // Configure Twitter credentials using twitter.txt
    TutorialHelper.configureTwitterCredentials()

    val ssc = new StreamingContext(sparkUrl, "Tutorial", Seconds(1), sparkHome, Seq(jarFile))
    val tweets = TwitterUtils.createStream(ssc, None)
    val statuses = tweets.map(status => status.getText())
    statuses.print()
    ssc.checkpoint(checkpointDir)
    ssc.start()
  }
}

Twitter情報を埋める

consumerKey = 
consumerSecret = 
accessToken = 
accessTokenSecret = 
実行
$ sbt/sbt package run
まとめ

とりあえずOK

Apache Sparkをとりあえず動かしてみる

はじめに

Apache Spark 1.0.0 をとりあえず動かしてみる。
スタンドアローン環境でHello World! 的なSparkの初めの一歩を実行する。

前提条件

Javaがインストールされていること。

$ java -version 
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
ダウンロード

こちらから

解凍
$ tar zxvf spark-1.0.0.tgz
$ cd spark-1.0.0
インストール

Scalaのインストールなど必要なモジュールを導入。

$ ./sbt/sbt assembly
動作確認

Sparkを対話モードで起動する。

$ ./bin/spark-shell

無事に起動したら、READMEファイルを読み取って色々操作してみる。

scala> val textFile = sc.textFile("README.md")  //ファイル読み取り
textFile: org.apache.spark.rdd.RDD[String] = MappedRDD[1] at textFile at <console>:12

scala> textFile.count()  //ファイルの行数を数える
res0: Long = 127

scala> textFile.first()  //ファイルの最初の行
res1: String = # Apache Spark
まとめ

Apache SparkのHello World! 的なことは簡単にできた!

RabbitMQに これでもか ってくらいデータ入れてみる

はじめに

RabbitMQ 3.3.1に限界までデータ入れてみるとどうなるか試してみた。

結論

リミッターが効いて設定値以上はデータを受け付けなくなる。

リミッターを設定する

管理画面にアクセスする。
http://192.168.X.X:15672/

f:id:moyomot:20140519211032p:plain

Disk space項目の48 MB low watermarkがリミッターの設定値になる。
(low watermark = 干潮時の最低水位標)
この値を越えるとキューのデータがはけるまで、キューにデータが入らなくなる。

設定ファイルは

/etc/rabbitmq/rabbitmq.config

を使用する。
ただし、Ubuntuにインストールした時は、configファイルが存在していなかったので
バイナリのRabbitMQを別途ダウンロードして、その中の

/etc/rabbitmq/rabbitmq.config/rabbitmq.config.example

をリネームして利用した。

リミッターが48MBであるため、検証しやすい、でかい値に変更してみる。
変更箇所はdisk_free_limit

%% {disk_free_limit, 50000000},
   {disk_free_limit, 4500000000}

設定変更後、MQ再起動。

$ sudo rabbitmqctl stop
$ sudo rabbitmq-server start -detached

f:id:moyomot:20140519214458p:plain
問題なければ、low watermarkが変更される。

データ投入

MQへの接続にはBunnyを用いる。
参考サイトをもとに作成したサンプルプログラム。

require "rubygems"
require "bunny"

str = "abcdefghijklmnopqrstuvwxyz"

conn = Bunny.new("amqp://admin:password@192.168.X.X:5672")
conn.start

ch = conn.create_channel
q  = ch.queue("bunny.test.limit")
x  = ch.default_exchange


100000000.times do |i|
  x.publish(str, :routing_key => q.name)
  puts i if i % 1000 == 0
end
conn.close

プログラムを実行して、データ容量が設定値をオーバーすると、管理画面は次のようになる。
f:id:moyomot:20140519220010p:plain
Disk spaceが赤色表示されてるね。

まとめ

RabbitMQ 3.3.1に限界までデータ入れてみると、もうムリとデータを受け付けなくなる。
(うろ覚えだけど、旧バージョンはこのような仕組みなくて、MQ落ちてた気がするんだよね)

RabbitMQ 3.3.1の管理者画面にログインできない

はじめに

RabbitMQのクラスタリング機能を検証したいなーと思い、
Ubuntu ServerにRabbitMQ 3.3.1をインストールして見ました。

インストールは非常に簡単で、
インストールガイド通りに実施すれば難なくできます。
Erlangを別途導入する必要はありますが、Ubuntuの場合、apt-getで一発です。

また、RabbitMQはManagement Plugin、要はWeb管理機能をプラグインで導入できます。
これもコマンド一発で導入できます。

ところが、この管理画面にログインできなかったので、その解決策をメモしておきます。

問題点

管理画面にログインできない
http://192.168.X.X:15672/

Management PluginにはUsername:guest、Password:guestで
ログインできると記述されている

ログ

下記ログにはログイン失敗時に次の記述が追記される

/var/log/rabbitmq/rabbit@rabbit1.log
webmachine error: path="/api/whoami"
"Unauthorized"
解決策

エラーログでGoogle検索するとStack Overflowの記事がヒットしました。

Can't access RabbitMQ web management interface after fresh install

バージョン3.3.0以降はlocalhost以外からはguest:guestでログインできなくなったみたいです。。。
(ガイドに書いといてくれよー)

よってStack Overflowにも書いてあるように、次のようにすればアカウントを追加できます。

$ sudo rabbitmqctl add_user admin password
$ sudo rabbitmqctl set_user_tags admin administrator
$ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
結論

Stack Overflowありがとー

MRIとRubiniusで排他制御

はじめに

Matz's Ruby Interpreter(MRI)とRubiniusで排他制御したマルチスレッドプログラムを実行し、結果を比較します。
実行時間計測、CPUコア使用状況を見ていきます。

  1. MRI排他制御なし
  2. MRI排他制御あり
  3. Rubinius排他制御なし
  4. Rubinius排他制御あり

の4つを比較します。

準備
  • Rubyのバージョン
$ ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]
  • Rubiniusのバージョン
$ rbx -v
rubinius 2.2.6.n110 (2.1.0 c004ced8 2014-04-20 JI) [x86_64-linux-gnu]

Rubiniusのインストールはこちらから
http://rubini.us/doc/ja/getting-started/building/

variable = 0

threads = 5.times.map do
  Thread.new do
    1000000.times do
      variable += 1
    end
  end
end

threads.each(&:join)

puts variable
variable = 0
mutex = Mutex.new

threads = 5.times.map do
  Thread.new do
    1000000.times do
      mutex.synchronize do
        variable += 1
      end
    end
  end
end

threads.each(&:join)

puts variable

メインスレッド以外にスレッドを5つ作成し、
それぞれのスレッドで百万回、足し合わせる処理を行います。
Mutexクラスのsynchronizeメソッド排他制御します。

MRIの実行結果 排他制御なし
  • 実行時間計測
$ time ruby multi_thread.rb 
5000000

real	0m0.500s
user	0m0.476s
sys	0m0.020s

はやいです。
topコマンドしても意味ないくらい一瞬です。

  • CPUコア使用状況
%Cpu0  : 14.8 us,  2.7 sy,  0.0 ni, 82.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  5.7 us,  1.7 sy,  0.0 ni, 92.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  6.7 us,  0.7 sy,  0.0 ni, 92.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  6.8 us,  0.7 sy,  0.0 ni, 92.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   3957672 total,  1806896 used,  2150776 free,   100764 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,   864556 cached

topコマンドから1を押すとコアごとのCPU使用率を見ることができます。

MRIの実行結果 排他制御あり
  • 実行時間計測
$ time ruby synchronized_multi_thread.rb 
5000000

real	0m57.339s
user	0m30.708s
sys	1m20.836s

遅くなりました。
後述のRubinius排他ありと同じくらい時間かかります。
システム時間に大分かかってますね。

  • CPUコア使用状況
Tasks: 232 total,   1 running, 231 sleeping,   0 stopped,   0 zombie
%Cpu0  : 16.2 us, 36.9 sy,  0.0 ni, 46.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 17.5 us, 32.8 sy,  0.0 ni, 49.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 11.5 us, 31.0 sy,  0.0 ni, 57.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  : 13.8 us, 30.5 sy,  0.0 ni, 55.3 id,  0.0 wa,  0.0 hi,  0.4 si,  0.0 st
KiB Mem:   3957672 total,  1791912 used,  2165760 free,   100168 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,   858356 cached
Rubiniusの実行結果 排他制御なし
  • 実行時間計測
$ time rbx multi_thread.rb
2344231

real	0m1.903s
user	0m6.032s
sys	0m0.044s

MRI排他制御なしより遅いです。
競合してます。

  • CPUコア使用状況
Tasks: 234 total,   1 running, 233 sleeping,   0 stopped,   0 zombie
%Cpu0  : 46.3 us,  1.7 sy,  0.0 ni, 52.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 48.3 us,  1.0 sy,  0.0 ni, 50.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 60.1 us,  1.3 sy,  0.0 ni, 38.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  : 48.2 us,  0.3 sy,  0.0 ni, 51.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   3957672 total,  1886912 used,  2070760 free,   101468 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,   890144 cached

コアをたくさん使用してますね。

Rubiniusの実行結果 排他制御あり
  • 実行時間計測
$ time rbx synchronized_multi_thread.rb
5000000

real	0m54.607s
user	0m46.080s
sys	1m9.592s

MRI排他制御ありと同じくらい時間かかりました。
競合もしていません。

  • CPUコア使用状況
Tasks: 234 total,   1 running, 233 sleeping,   0 stopped,   0 zombie
%Cpu0  : 23.4 us, 30.9 sy,  0.0 ni, 45.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 22.0 us, 33.2 sy,  0.0 ni, 44.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 18.6 us, 28.8 sy,  0.0 ni, 52.6 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  : 18.6 us, 27.0 sy,  0.0 ni, 54.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   3957672 total,  1991948 used,  1965724 free,   102420 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,   904304 cached

排他制御していない時と比べると活用率は下がりますね。

まとめ
  • 排他制御ありの場合はMRIとRubiniusで同じくらいの実行時間になる
  • 排他制御しないと期待通りの結果を得られない場合があるので、そもそもやばい

MRIとRubiniusでマルチスレッド

はじめに

Matz's Ruby Interpreter(MRI)とRubiniusでマルチスレッドプログラムを実行し、結果を比較します。
実行時間計測、CPUコア使用状況を見ていきます。
複数回実行して、平均を取るなど真面目に検証はしていません。

準備
  • Rubyのバージョン
$ ruby -v
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]
  • Rubiniusのバージョン
$ rbx -v
rubinius 2.2.6.n110 (2.1.0 c004ced8 2014-04-20 JI) [x86_64-linux-gnu]

Rubiniusのインストールはこちらから
http://rubini.us/doc/ja/getting-started/building/

  • 検証に用いるプログラム
variable = 0

threads = 5.times.map do
  Thread.new do
    100000000.times do
      variable += 1
    end
  end
end

threads.each(&:join)

puts variable

メインスレッド以外にスレッドを5つ作成し、
それぞれのスレッドで1億回、足し合わせる処理を行います。
スレッドセーフではありません。

Rubyの実行結果
  • 実行時間計測
$ time ruby multi_thread.rb 
500000000

real	0m43.034s
user	0m42.688s
sys	0m0.052s

MRIはGVLが実装されているので、競合状態は発生しないですね。

  • CPUコア使用状況
Tasks: 235 total,   1 running, 234 sleeping,   0 stopped,   0 zombie
%Cpu0  : 45.6 us,  0.3 sy,  0.0 ni, 54.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  5.4 us,  0.7 sy,  0.0 ni, 94.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 20.3 us,  2.3 sy,  0.0 ni, 77.4 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  : 41.6 us,  0.3 sy,  0.0 ni, 58.1 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   3957672 total,  2745588 used,  1212084 free,   220392 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,  1298312 cached

topコマンドから1を押すとコアごとのCPU使用率を見ることができます。

Rubiniusの実行結果
  • 実行時間計測
$ time rbx multi_thread.rb
198985546

real	6m1.643s
user	22m39.488s
sys	0m1.408s

MRIと比較すると遅いです。
競合しまくりです。
スレッドセーフでないプログラムを作成したかいがありました。
マルチスレッドの場合、user値は合計値になるのでreal値よりも大きくなることがあるのですね。

  • CPUコア使用状況
Tasks: 234 total,   1 running, 233 sleeping,   0 stopped,   0 zombie
%Cpu0  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   3957672 total,  2120944 used,  1836728 free,   205068 buffers
KiB Swap:  4104188 total,        0 used,  4104188 free,   998288 cached

コアをたくさん使用してます。

まとめ
  • MRIのほうがはやい
  • Rubiniusはコアをフル活用してくれた(が、遅い)
  • MRIはGiant VM lockを実装しているので、同時に実行されるネイティブスレッドは常にひとつのため、このプログラムでは競合状態を発生できなかった