タイトル

Need for Answer

2015年8月1日土曜日

pebble timeを買ってはいけない理由(を無理やり考える)のまき

pebble timeが一般発売されましたね!
早速購入してみましたので、pebble watchと比較したレビューをしようかな!と思います。

Pebble watchのレビューはこちら⇒
Need for Answer: あえてこのタイミングでPEBBLE WATCHをつかってみたのまき

公式のWebで購入して到着までの期間は、11日でした。だいたい2週間をみればいいんじゃないかと思います。受け取り時の注意なのですが、pebble timeは関税(1200円)がかかります。用意しておきましょう。

ということでパッケージ!kickstarter版とは異なりますね!


バンドを比較すると、止め輪が2つになってたり、エッジが微妙に異なってますね!

バネ棒は22mmで前作と変わりません。バネ棒がバンドから外せないので、バンド交換するときはバネ棒を調達する必要があります。



背面!充電端子が背面になりました。


ということでやっとタイトルの話をします。

下の方に微妙な点を並べてみましたが、私はそんな気にしてないのでマイナスと考えてなかったりします。気になる人もいるかと思いますので。

まず、pebble timeはpebble watchよりも画面が暗いです。特に待機時の画面が暗い&液晶がガラスの奥にあるので、周りが暗くなるとそうとうみえづらいです。

まぁシェイクすれば画面が明るくなるんで、そんなに支障はないですが。


充電端子が背面です。普通に使ってると問題ないのですが、背面を遮るバンドを使っているとこんな感じになります。めんどい。


といっても充電は5~7日間隔で十分なので、そこまでストレスじゃないです。


あと微妙にどうでもいい変更点として、watch face変更がめんどくさくなりました。『盤面をコロコロ切り替えてた』という人は、ストレスなんじゃないかと思います。まぁボタンの上下が過去未来のタイムラインに割り当てられたので、しょうがない話ですね。

あとは『現時点(2015年8月現在)ではiOSしかもってないと日本語フォント適用できない』とかめんどくさいこともあるのですが…。


ということで色々書いてみたのですが、pebble timeでカレンダー連携がすごく良くなったので、微妙な不満点を完全に払拭できると思います。

安い買い物とは思いませんが、スマートフォンを便利にする投資としてはいいんじゃないかなーと思います!

2015年7月4日土曜日

nginx_luaでhtmlを書き換えたい!のまき

レスポンスボディ、書き換えてますか!

…唐突ですが、OSSとか使ってるとちょっとした修正、加えたいってあると思うんですよ。

パッチ当てるのも面倒くさいなーという時、「リバースプロキシでレスポンスボディを書き換えてしまう」という方法もありますよーという話です。実現する選択肢は色々あるのですが、今回はnginx_luaで実現しました。

やってることは、「nginxでリバースプロキシしたhttp_bodyを、luaスクリプトで書き換え」という感じです。こんなかんじで設定すれば、Apacheで動いてるAPサーバーをSPDY対応させつつ書き換えられますね!

 server {
    listen 443 ssl spdy;

    ssl on;

    ssl_certificate your_server.crt;
    ssl_certificate_key your_server.key;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    add_header Alternate-Protocol 443:npn-spdy/3;
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";

    location / {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto https;


      proxy_pass http://localhost:80;

        body_filter_by_lua
        '
        replacestr = "$1http://www.google.com/url?q=$2"
        ngx.arg[1] = ngx.re.gsub(ngx.arg[1],"(href=\\")(https?.*?\\")", replacestr)
        ';
    }
 }


2015年6月19日金曜日

golangでHTTPのbodyを読み捨てたい!…のまき

golang書いてる人だったら、httpリクエストをひたすら繰り返すアタックツール、書きますよね!

…ということでソースをそのまま公開すると「アタックを繰り返すプログラムを公開し続けるだけのヤンチャなプログラマー」になっちゃうので、その際学んだことを書こうかな?というお話。

http接続処理のとこだけ抜粋するんですが、重要なのは「バッファ読み捨て」というところです。

なんでここが重要なの?という話なのですが、バッファを読み捨てないと「http接続が完了する前に、Client側でTCP接続を切断しちゃうから」なのです!

ちなみにバッファ読み捨ての行をコメントアウトしても、レスポンスコードは取得できたりします。

…なんでかはioutilのソースを読むといいんじゃないかなーと思います!

// HTTP接続
func httpRequest(tr *http.Transport) {

        // HTTP接続
        client := &http.Client{Transport: tr}
        r, err := client.Get(url)

        if err != nil {
                fmt.Println(err)
                return
        }

        // Body Close処理
        defer r.Body.Close()

        // バッファ読み捨て
        io.Copy(ioutil.Discard, r.Body)

        // レスポンスコード
        response := r.StatusCode
        fmt.Println(response)

}

2015年6月17日水曜日

golangでfluentdのストレステストツールを書きましたのまき

fluent-attacker-rpsという、Fluentdサーバーに負荷をかけるツールを作りました!fluentdサーバーにいっぱいデータ登録したいときに使って下さい!

…というと2行でお話終わっちゃうので、一応使い方とか説明しようかなーと。

go run fluent-attacker-rps.go -h 192.168.0.1

という感じで実行すると、こんな出力がされます。

=====================================
Insert Keys=> 3000 RPS Set => 300 Message Length => 1000
=====================================
0 loop - TaskSet Done.
300 loop - TaskSet Done.
600 loop - TaskSet Done.
900 loop - TaskSet Done.
1200 loop - TaskSet Done.
1500 loop - TaskSet Done.
1800 loop - TaskSet Done.
2100 loop - TaskSet Done.
2400 loop - TaskSet Done.
2700 loop - TaskSet Done.
3000 Task - All Job Done.
=====================================
Exec Time => 10.389512Sec Real RPS => 288.752743rps(96.250914%)
=====================================

終わりましたね!fluentdサーバーにどんなデータが来ているかといいますと、こんな感じです!
2015-06-17T11:48:19+09:00       test.tag        {"ID":"0","md5":"1cea7c2ef3b6019d774fd46a90ef127b","strings":"zrv5xl4igns0qvm6rdki5jq5qrq6wfko3gahmk41idbh5udjk6hvus3wjw1659x51fu7oe6xfc6c163s6ee7stunspm2drdcaap4mgk0khexs17chdg5hjzx4u15h7hc5ui3i256hfon1i294fh9e3dlatpfeks5o8b8lyj8lgp7oqzmsyme94qc88btpahp51ua5lbzt606p76lnxmpj7y7z0hmcb0oic8fmm0km0zg97ag4orm4scql1qvgp5b2av0o8om5k2bc5wpdutvgb22n2alf0e4tf7v42v0h9rd20ye2y3lkj5cczegurle8socvwlz9wjg7379b37w1958kpryai16yqjgxno39g7u3i1xky4oqaeuhmr2aeu0of5yhabakwgrp94oxtjlhncof5lqasudwgvmkdzh75jwia2milduhy05tf0cszg99kqoqixwpu2bsuy4vqaopu1e5x9f9ba5bsvz31a4zzt97ybs92taaalqvp4y9bsrjhc0fxwxxmdd9a89e6hldttqap08za7xmcuq8a2bvczmg1n21t0do78qeg0c79as2tpujxwyrraxijjhjsnap1kfh702jkrjlqv8v6ik6u2ys7z2b5xhh66jhtx9fnj571igv8yedtosb050omt6h62rcyaibk4gcuj6iez2g70kol9zrfiwow7o17467qrf14wwxoskavqw0t64azei1kbzsm5uncb3nspwb6tyjmyopef6yprxbvtylsx18h34rw2x3v69dh3eqv28jc1z2pnny8qgrjle5fdn2pvjuby9197f3kr3f6r031j651zb9egbqtqzgncvim02i33wbs20msvrmt1cldkwkd7qhac39e6u0hoes0e6yh9g24idnclqkwx72vbrdb5ziu425qm58j6e8rcs9nyqyevb33idwhvruhna2wo7pgkqnwgyfkv6n0laavw09t06lo1pc0s82gxexgfznroazqlc"}
2015-06-17T11:48:19+09:00       test.tag        {"strings":"j4t29f6dyejou4h320ggfxi7u4f4kzr3kzxv9u852pzqw8ft238fdqmr42eha0g826nn2vyu79n2wmjtuj17lc1n0jpbqw8bnpcie3csc34ixkiaeuy6n1xczg3uvk11h1lh3kd005xepund2bz2xpj0fha4c4h3acqxvns5x7p6wtes87trldkn8ze51qhhzrql41kx1sxcg4m6aidc406qldco4d6g6k8enbk6oblmyb6v9txdq6aigpn13thgnshi0c5yremnrw2l7bbee8jccqqvpwe035ov8oqk84xzsr2wg1kzgj4xiudg1zxajdn4q661hy4qh6f8bfqa9v4nedn2c1x5nsinkgsr3zw8t6hzdl0bxapt0aysf0qap6ak7x1k2ec09ucxz98u59yjx7b49l5tv7x8xde9bm8e503ayl51ojtmgapu5227mucnlqyr4v78xvvdta85z3160a06my9ndhmyrlboghl025cqda74dpfrbuxjguu2eamhujzeimfpcd91as0fbxj31conls96yby622i9le6cnoj54vjdstj75cg6mksguush2hg39kjs75j1nd46jjyuioxlz8cesedc00i2zg8apipzodmosp69eo0alxkxkr3xnz0u9n9hcbyan3wywiu8efr729y73afwerc8yji8ioaxivs71d3143tzk02b7toaea4j7bdz2snmqrodjtabvnwe5l90ivxl8oflae4cvkiafcvkwwi4nlh3vw98os4ftskbgvj7b6he2rtags1isqh1fszd9379upustge9gvp8pgl25gcw7xu2lre6jkx11i306gckvf5k8m6mr4iufbax80m25zyyjlac7tlty4mg24t1h7pacwo7tzf3s4vtubi7aisupo30x1w3yjlmlxiojz5ckmsp1sppntm173uqi9fw6kydxfikyzpd0iaa3sctuqigemjwq72skxsbwjhrzj8q391wjslw","ID":"1","md5":"93464e057d8babe65f77801432dc27fe"}
2015-06-17T11:48:19+09:00       test.tag        {"ID":"2","md5":"d4a115141322905aa3e21dc8ea91349c","strings":"8x0pwax2q60gbdlzbe0hq7zp5w57zt03g6qq0y6a7g9x6a9wzhjmhxx30hjtbok4wnlxgczusrenbtwbyus89ihz1czpbr75g1djbmdbfoq6c6me5xrh3w5t01bfkrccw0kiharjc1c3rb73g74d7mkvjxqk0htgkrkrr23innjjdzybn4l5q4g62d8vfpbk6reycp22jv1aavza6z8egcrh8jboewllr5dvvif8tiouqil0ncvkzpugp3s4hakzvob1b1t83lf97adwuh5177vcu54ek816vslydwqkvhseblxzpf7lwjn5te9p0t4zgoy3txhn9paswxce6rp6f8ozrldxcc0sv96o5kn1s2z6negjc12s11406z0fxpa01ybhqxtovmmiix867x8ebfoi86lcp4upo6xplwpj0kvzhaiq1o6yo2z0gh9fd6z5od0201yy6c9hk5b9eflcv72kd8wg2sric04vl43o0kv0yc3hmc4v4xcgnra0iqreipdu0fiop2je5xl8npg3gryqv27504vvu5lrtimyxhy6sqjazrrz19od263tl4mbwqlvxx0dlb7unr3563p01symis6p2pc8pkyuhgs0zb9q4lukvdqnnk2uqu42dl488drbvhs7iypxkgqxk049n5ofuj42fik7v7mmanwliw4bdei6a2q5hw1ws9kn9sl9h74dg264gtmh2ybvl0xpk0dcgxdun0ksz0aa5uoruswt49v2xs3iaf7edl3jju0u7a4cq1v8ocrb1k4hxqdninhjuxha9kdztkx2uzxiec56fpqyf66m519vnv11dff0s3rnn5f2o72amhyybl5mf5yv3bx185usi4re6rpq0sasf2dem6rb99zk9fgg2gpqrxzarm810si24bfoear4iuey45b4dqfk4p0thyypc5ii2o19a107uthif4tr0qlad44atr9xaw0nq7ehpkhawl6sy06thl6084ri13us"}

RPSとか投稿数とか調整できますので、「fluentdサーバーのスペック決めるのどーすんだろ?」とか「ログがロストしてないんだろか?」とか実験するといいんじゃないかなーと思います!

追記)念のため言っておきますが、Newで作った接続を使いまわしていないのは「大量のTCP接続来たらどうなるのかなー?」という試験のためです!アホの子をみるような目でソースを見るのはやめてね!

2015年6月12日金曜日

golangでRPSをそれなりっぽく実装するのまき

golang書いている4割位の人が悩む問題として、「RPS(Requests Per Second)をどうやって実装するか?」があると思います。…多分。

ということでこんなかんじで実装しましたよ、というお話。
ちなみにコードのほとんどはmattn氏のBig Sky :: Golang の channel の使い所 : の引用です。

以下サンプルコード。

// RPSから間隔を計算
func calcInt(x int) int64 {
        return int64(1 / float64(x) *1000 *1000)
}

func main() {
    // Channel宣言
    task := make(chan int)        // TaskQue用
    taskquit := make(chan bool)   // SetTask停止用
    workerquit := make(chan bool) // JobWorker停止用

    // WaitGroup作成
    wg := &sync.WaitGroup{}

    // Job Worker
    go func() {
    loop:
        for {
            select {
            case <-taskquit:
                workerquit <- true
                break loop
            case job := <-task:
                wg.Add(1)
                なんかの処理(job)
                wg.Done()
            }
        }
    }()

    // SetTask Worker
    go func() {

        // RPS間隔計算
        interval := calcInt(rps)
        sleepWait := time.Duration(interval) * time.Microsecond

        for i := 0; i < key; i++ {
            task <- i
            time.Sleep(sleepWait)

            // Log Print
            if i%rps == 0 {
                fmt.Printf("%d loop - TaskSet Done.\n",i)
            }
        }
        taskquit <- true
    }()

    // WaitGroup終了まで待つ
    wg.Wait()

    <-workerquit
}

2015年6月4日木曜日

ErastiCache for RedisでFailOverが発生すると何がおこるのか?のまき

これからタイトルどおりのお話をするのですが、Multi-AZ構成を取っていたとしても何がおこるか知らない人多いんじゃないでしょうか?AWSのドキュメント見ても、挙動の記載が無いのです。

結論から言うと、2パターンあります。
  1. Read Replicaがprimaryに昇格し、旧primaryはread replicaとして同期
  2. 自身の持っているイメージからデータを復元(read Replicaが使えない場合)
1から説明しますと、Multi-AZのRead Replicaが存在する場合は素直に切り替わります。これはDNSで切り替わるため、Primary Endpointに紐付いたNodeが、新しいprimaryに切り替わリます。その際、降格したread replicaはデータが空の状態で同期を開始します。

問題は2です。primaryがread replicaに降格するのですが、そのタイミングでデータをローカルにバックアップします。正確に言うと、こんなかんじの流れです。
  1. 障害検知したタイミングで、データをローカルにバックアップ
  2. 再起動
  3. データが空の状態でredisが起動
  4. 新primaryに問題ない場合はread replicaとして起動し、primaryからデータ同期
  5. 新primaryに問題がある場合はprimaryとして起動し、1.からデータを復元
何が問題か?という話なのですが、1~5の間は『read,writeがロックされた状態』になります。つまり長時間redisにアクセス出来ない状態になります。

…大変っすね!


2015年5月28日木曜日

New ReicのScalability analysisって何?

New Relic使ってますか!

というか、New Relicの「REPORTS」項目、見てますか!
今回はその中の、「Scalability analysis」について解説しようかな、というお話。

…「Scalability analysis」とは、読んでそのままの意味でスケーラビリティ分析をしてくれるものです。つまり「インフラがボトルネックになっているか?」がわかるのです!すごい!

では、読み方。2つのキャプチャを見てみましょう。




このグラフから何を読みとくか?というと、「rpm(Requests Per Minutes)が上昇しても、応答速度にムラが無いか?」です。横軸がrpm、縦軸が平均応答速度です。「右端のカラーチャート」と「グラフ内の点」を照らし合わせると、「いつのアクセスなのか?」がわかります。つまり何時頃にはどれくらいのrpmだったのか?がわかります。

そもそもの話ですが、rpmはユーザーアクセス数に比例します。具体的には「夜中は少なく、昼は多い」ということになります。こういった時刻ごとの変化も一目瞭然ですね。

さて「rpmが上昇」ということは、「1台のサーバーで対応するユーザー数が上昇」ということです。…ということは「インフラリソースが不足すると、応答速度が遅くなる」と考えられます。逆に考えると、「応答速度が安定しているということは、インフラリソースは充足している」事になります。

ということで結論としては、「線グラフが水平」「点が集中して上下の幅が少ない」というのが、インフラリソースが充足しているいい感じ、になります。

右肩上がりや、点がバラバラになっている場合は、どこかにボトルネックがあるという事ですね。

2015年5月23日土曜日

golangでredisに超大量にデータを入れ続けるプログラムを書きましたのまき

件名通りなのですが、redisにダミーデータを入れ続けるだけのgolangプログラムを書きました!
みんなもつかってね!

…なーんてプログラム使う人居ないと思うので、書いてた時に学んだことを共有しようかなというお話。


■コンソール出力すると極端に遅くなる
golangが早いのはご存知なことだと思うのですが、思ったよりコンソール出力が遅いです。
超大量データを処理する際、毎行ログ出力するのは無駄が多いです。

100行に一回出力とか間引きした方がいいですよ、ということですね。


■Network I/Oはコネクションプーリング等の工夫が必要
処理が早いということで、CPU以外の部分にもボトルネックが来る可能性があります。
redisへのアクセスを毎回切断していたら、あっという間にTCP接続を使い切ってしまいました。

コネクションを使いまわす、を早い段階で考えたほうがいいですね。


■ifでgoroutineを呼び出すときに、ループ数が極端に多いと落ちる
goroutineはループに入る前にスレッド(みたいなもの)を事前に用意するっぽいです。10万ループとかをgoroutineで非同期化すると、「signal: killed」で落ちます。

…ということでどうするかという話なのですが、「gorc」いうパッケージを使うと回避できます。goroutineの同時並列実行数に制限がかけられるため、リソースを使い切るのが回避できます。すごい。

※追記)sync.Poolとかsync.Cond使うとsyncでもスロットル制御出来る気がします!書いたこと無いけど!


package main

import (
  "crypto/md5"
  "crypto/rand"
  "encoding/hex"
  "flag"
  "fmt"
  "github.com/garyburd/redigo/redis"
  "github.com/mr51m0n/gorc"
  "math/big"
  "runtime"
  "strconv"
  "time"
)

var (
  pool *redis.Pool
  host string = "localhost:6379" // redis-server接続情報
  key int = 150000 // 投入するKEYの数
  val int = 10000 // 文字列の長さ
)

// redis ConnectionPooling
func newPool(server string) *redis.Pool {
  return &redis.Pool{

    MaxIdle: 3,
    IdleTimeout: 240 * time.Second,

    Dial: func() (redis.Conn, error) {
      c, err := redis.Dial("tcp", server)

      if err != nil {
      return nil, err
    }
    return c, err
  },

  TestOnBorrow: func(c redis.Conn, t time.Time) error {
    _, err := c.Do("PING")
    return err
    },
  }
}


// val用にrandomな文字列を生成する
func random(length int) string {
  const base = 36
  size := big.NewInt(base)
  n := make([]byte, length)
  for i, _ := range n {
    c, _ := rand.Int(rand.Reader, size)
    n[i] = strconv.FormatInt(c.Int64(), base)[0]
  }
  return string(n)
}


// gorc
var gorc0 gorc.Gorc


// メイン処理
func main() {
  runtime.GOMAXPROCS(runtime.NumCPU())

  flag.Parse()

  // Timer Set
  start := time.Now()

  // redis Pooling Start
  pool = newPool(host)

  // Redis DataInsert
  for i := 0; i < key; i++ {
    gorc0.Inc()
    go setredis(i, val)

    gorc0.WaitLow(100)
  }


  // Log Print
  fmt.Print(key)
  fmt.Printf("Keys - Set Done.\n")

  // Timer Print
  end := time.Now()
  fmt.Printf("%f秒\n", (end.Sub(start)).Seconds())
}


// stringからmd5から作る
func GetMD5Hash(text string) string {
  hash := md5.Sum([]byte(text))
  return hex.EncodeToString(hash[:])
}


func init() {
  gorc0.Init()
}


// redisにデータを投入するだけの処理
func setredis(k, v int) {

  c := pool.Get()
  defer c.Close()
  defer gorc0.Dec()


  vals := random(v)
  keys := GetMD5Hash(vals)


  c.Do("SET", keys, vals)


  // 100処理ごとにログ表示(非同期なので順番が適当)
  if k%100 == 0 {
    fmt.Print(k)
    fmt.Printf("Keys - Set Done.\n")
  }
}

2015年5月4日月曜日

koboのKoboReader.sqliteをメンテナンスするのまき

電子書籍リーダのkobo使ってますか!
長期間使っていると不安定になりますよね!

…というのは、書籍データの中身をsqliteというファイルに保存しているのですが、『電子書籍データを読み込む度に肥大化し続ける』という困った設計になってます。

今回のお話は、このファイルをシェイプアップする方法です。
Windowsの『PupSQLite .NET Framework4』というソフトを使います。

まずkoboデバイスの「.kobo/KoboReader.sqlite」というファイルを一旦HDDにコピーします。
PupSQLiteに先ほどのKoboReader.sqliteを読み込ませます。

するとこんな画面が出ますので「SQL入力」を押して、タブをオープンします。


さて、ここからはSQLを使います。
『ウィンドウに下のSQLを入力して、稲妻ボタンを押す』という流れです。



件数を確認してみましょう。
select count(*) from content ;
select count(*) from content where ___UserID='cbz_user';

多分すごい数字(数千~数万)が出てきたと思うので、レコードの削除をします!
delete from content where ___UserID='cbz_user';

先ほどのSQLをもう一度流してみましょう。成功していればレコード数が減少しているはずです。
select count(*) from content ;
select count(*) from content where ___UserID='cbz_user';

レコード数は減ったので、膨れ上がったファイルをシェイプアップします。画面上にある「最適化」ボタンを押してください。見た目には変わらないのですが、ファイルサイズが縮小されます。


これでPupSQLiteでの作業は終了です。

あとはkoboの.koboディレクトリにKoboReader.sqliteを書き戻してあげれば作業完了です。

2015年4月23日木曜日

freeboardで華麗にダッシュボードるのまき

いきなりですがダッシュボード作ってますか!KPIとか表示したくないですか!

RubyですとDashingとかあると思うですが、運用つらいです!(ダッシュボード作ってみるとわかるんじゃないかな)

ということで今回オススメするのがfreeboardです。利点は「ブラウザのみで動くので、サーバーが不要」という一言につきます。あとGUIベースで気軽に編集できるとこですかね。

もう少し詳しく説明しますと、freeboardは「HTML+Ajaxで動く静的ページ」です。つまり『freeboardのソースをPCのローカルに置けば、ブラウザが外部データソースを定期的に取得する』という事です。簡単に図解。


ということで「外部データソースを作るだけでダッシュボード作り放題だぜ!」というのがこの話で訴えたいことなのですが、一つ注意する事があります。

それは「外部データソースが出力するレスポンスヘッダにAccess-Control-Allow-Origin:*がないとデータ取得できない」ということです。なんで?と言われますとAjaxの決まりだからとしか言い様がないのですが…。

これさえ気をつければ気軽にデータソースサーバー作れますね!

あえてこのタイミングでPEBBLE WATCHをつかってみたのまき

さて、2015年4月24日といえばAppleWatchの発売日ですね。これでAndroid WearとApple Watchと、スマートウォッチデバイスが揃ったわけですね。

…という2大巨頭の間で、Samsung GearやらSmartWatch(SONY)やらという独自規格が乱立している中で「PEBBLE WATCH」という商品があるのをご存知でしょうか?

実はこの製品は2013年から出荷されているのですが、思ったより話題になってない(気がする)ので紹介してみようかなと。




特徴はこんな感じです。
  • 安い(99USD/送料込)
  • Android、iOS対応
  • 電池が7日間持つ
  • 電子ペーパー採用で、太陽光下でも問題なく閲覧できる
  • 日本語対応(Cryingneko氏のご対応)
  • 防水なので、手洗いや雨など気にしなくていい
  • バイブ、ジャイロセンサーを備えている
  • モノクロ

…という感じで、スマートウォッチとして必要最低限機能を揃えていると思います。スペック紹介おしまい。

実際使ってみた感想としては、『スマートフォン通知を手元で確認できるのは、想像以上に便利』という一言につきます。

『手元のバイブで通知を見逃すことが無い』というのはセールスポイントだと思うのですが、なにより『その通知に反応するべきかどうか』を即座に判断できるのが、ストレスが溜まらないことに気がついたのです。

つまり『通知が来たからスマホを取り出す』『気がついてないかもしれないからスマホを確認する』という、『漠然とした面倒さ』から開放されるんです。

満員電車内とか読書中・PC操作中などのちょっと手が放せない状況で非常に有効ですし、スマートフォンをかばんにいれている人とかも便利に使えるんじゃないかなーと。

正直な話Android WearでもApple Watchでもいいと思うのですが、『ちょっとお試しで使ってみたい』という気軽さで購入できるのがPebble Watchのいいところなんじゃないかな―と思います。

2015年4月17日金曜日

json_rest_serveを公開しましたのまき

GItHUB => json_rest_server

オンメモリKVSサーバーが欲しくなって、コード書きました。
特徴としてはこんな感じです。
  • golang
  • HTTP REST APIなので、クライアントはcurlとかでも大丈夫
  • オンメモリで高速動作
  • スレッドセーフ
  • 一応管理機能もついてる
と、機能を限定してる感じですね。

…で、これで何がしたかったの?という話なのですが、fluentdのデータをダッシュボードで可視化する時のストレージにしたかった、ということなのです。べんり。


2015年4月13日月曜日

fluent-plugin-in_http_healthcheckをリリースしましたのまき

Rubygems => fluent-plugin-in_http_healthcheck
GitHUB => fluent-plugin-in_http_healthcheck

『HTTPリクエストに対し、HTTPステータスコード200を返すだけ』のfluentdプラグインを作りました!

ELBとかGoogle Cloud Computingのロードバランサー配下に、fluentd配置したいとき使うといいんじゃないかな―と思います!というかそれ以外使い道あるんでしょうか!

…ということで一応解説しますと、fluentd標準の『in_http』プラグインは『jsonまたはmessagepack』以外のデータが投稿されるとエラーを返すのですね。なので、L7レイヤーでサービス監視しているロードバランサーには、何らかの応答(status:200)をする必要があるのです。

ということで、『fluentdとしてはなんのデータも処理しないプラグイン』が必要ということでした。

2015年4月9日木曜日

fluent-plugin-json_serializerをリリースしましたのまき

Rubygems => fluent-plugin-json_serializer
Source => GitHUB

fluentdのレコードを一つのkeyにまとめるだけという、fluentd filter pluginを書きました。Rubygemsに公開しておきましたので、使ってみてください!

…というgem開発にDockerを使うととても便利だったというお話。

  1. 未インストール状態に、簡単に復元できるのでクリーンインストール試験が簡単
  2. とりあえず動かない時、Dockerfile内のソースを修正できる
  3. 「gem使ってみたけど違うな―」という時に未インストール状態に戻せる
  4. 複数バージョンのfluentdでテスト出来る

という感じで『とりあえず手を動かしてみよう!』と気軽に作るにはいいんじゃないかな―と思いました。

2015年4月6日月曜日

awscliでS3バケットにあるファイルを、パターンマッチでダウンロードしたいのまき

AWS S3でバケットに収納したログをダウンロードしたい時、awscliを使う事があると思います!その時、ファイル名を指定してダウンロードしたいなーという時のお話。

下記のようにバケット内にログがいっぱいあるとき、パターンマッチでダウンロードしたいということですね。

2014-01-01.log
2014-01-02.log
2014-01-03.log
2014-01-04.log
(中略)
2015-04-01.log
2015-04-02.log
2015-04-03.log
2015-04-04.log

でこれをダウンロードするときなのですが、excludeオプションで全部除外しないとだめなのです。全ファイルがダウンロード対象になってしまいます。

あとはincludeオプションでパターンマッチかければ大丈夫!

 aws s3 cp s3://[bucket-name] [local-dir] \
    --recursive \
    --exclude "*" \
    --include "*2015-04-*" 

NGiNXのアクセス元を、GoogleMapにレンダリングするのまき

NGiNXのアクセス元を可視化する方法を実験してたら、うまくいったので資料化してみました!結構使い道あるんじゃないかな−と思います!たぶん!


2015年4月1日水曜日

fluentdにHTTPヘルスチェックを返答させるのまき

(2015/04/13:RubyGem化しました)

Google Compute Engineの微妙な困りどころとして、「ロードバランサーのヘルスチェックがHTTPプロトコルかつstatus:200を返答しなくてはならない」というのがあります。

つまり『サーバーがHTTPを返答させる必要が無くても、ヘルスチェックのためにHTTPを返答させる必要がある』ということです。

…ということで、みんな大好きfluentdにヘルスチェックを返答させちゃおう!というおはなし。

方針としてはデフォルトで入っている「in_http」プラグインを使って、サブクラス化しちゃうという作戦です。

 module Fluent
  class HttpHealthCheckInput < HttpInput
    Plugin.register_input('http_healthcheck', self)
    def on_request(path_info, params)
      begin
        return ["200 OK", {'Content-type'=>'text/plain'}, ":) < Hello!"]
      end
    end
  end
end

これをfluentdに読み込ませます!念のため、既存のin_httpも動くか確認します。
 
<source>
  type http_healthcheck
  port 8889
  bind 0.0.0.0
</source>

<source>
  type http
  port 8888
  bind 0.0.0.0
  body_size_limit 32m
  keepalive_timeout 10s
</source>


チェックしてみましょう!
 
root@hoge:/etc/google-fluentd/catch-all-inputs.d# curl http://localhost:8889
:) < Hello!
root@hoge:/etc/google-fluentd/catch-all-inputs.d# curl http://localhost:8888
400 Bad Request
'json' or 'msgpack' parameter is required

2015年3月9日月曜日

NGiNX_Luaでバックエンドからのリターンコードで処理をわけるのまき

NGiNXのリバースプロキシ使ってますか!Apache+mod_wsgiの前段にNGiNXを置くとかあるんじゃないでしょうか!多分!

…ですが、とっても困るのがバックエンドサーバーで50xエラーが出ることがあるんですよね。困りますね。ということで、NGiNX_luaでリトライ処理するサンプルコードを書いてみました!

 upstream backend {
    server [proxy先URL];
}

server {
    listen 80 default;
    server_name 127.0.0.1 localhost;

    location / {
       content_by_lua '
         local STR = "/check"..ngx.var.uri
         local res = ngx.location.capture(STR)

         if res.status == ngx.HTTP_OK then
           ngx.say(res.body)
         else
           ngx.sleep(1)
           res = ngx.location.capture("/check")
           ngx.say(res.body)
         end
       ';
    }

    location /check {
      internal;
      rewrite /check/(.*) /$1 break;
      proxy_pass http://backend/;
  }
}

2015年2月18日水曜日

Google Compute Engine上にfluentdを立てて、BigQueryまでつなぎこんでみたのまき

Google Compute Engine上にfluentdを立てて、ログを収集してみました!
何がしたかったのかというと、モバイル端末のログを収集してBigQueryに突っ込んでみたかったんです!

まとめておいたので、みんなみてね!

2015年2月10日火曜日

EMLauncherのダウンロードURLの期限をメンテナンスするのまき

EMLauncher使ってますか!Testfrightが終了する今、EMLauncherはベータテスターにとって救世主のような存在ですね!

…EMLauncherの機能に、「QRコードでリンク先URLを共有」という機能があります。これはEMLauncherにログインできない人でも、ダウンロード先URLを共有出来るという便利な機能です。

なのですが、このURLって期間限定なんですよね。期間限定なのはいいんですが、期限を設定する方法がないんです!

ということでソースを直接修正しましょうということです。該当箇所はこちら。

        const URL_EXPIRE = 86400; ///< link_idの有効時間

2015年1月25日日曜日

figでudpを指定したいのまき

fig使ってますか!Docker使うのにとっても便利ですよね!

…fig.yml書いてると出る疑問は、「udpってどうやってポート指定するの?」ってことだと思います!
実は簡単で、portの後ろに書くだけです。

ports:
 - "3000"
 - "24224:24224/tcp"
 - "24224:24224/udp"