ʍoɹɐɥsのブ口グ

ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็็็็็็็็็็็็็็็ ส็็็็็็็็็็็

温度センサの値をブラウザから見れるようにする(1)

温度センサの定期的な取得と保存はできているので、とりあえずWebサーバが必要。僕はここ数年ずっとnginx+uwsgiを使っていて、Python側ではbottleを使って書いている。置く場所も/srv/http以下に置くことにしてる。フロントエンドで使うライブラリはすべてbower経由で入れる。こういうふうに決めといちゃうと楽。

作業リポジトリは/home/以下のどっか、というかどこでもいいのだけど、別にある。そのプロジェクトのbinにはdeployというスクリプトがあって、これを実行すると必要なものを/srv/http/hogeに全部コピーして、適切な所有権(http:http)を設定し、そこにpushdしてbower installなどを実行、それから/etc/nginx/vhosts/hogeや/etc/uwsgi/vassals/hogeも更新してデーモンをreloadするようになってる。nginxはinclude、uwsgiはvassalで切り分けてる。ナウいことするならコンテナで切り分けるのもありなんだけど、さすがにRaspberryPiではつらい。

uwsgiの設定ファイル(yaml)はこんな感じ。もちろんこれはひとつのvassal。低スペックなのでTCPではなく、UNIXドメインソケットを使ってみることにした。こっちのほうがTCP系の処理が入らないので速いとの噂(自分で比較はしていないが・・・)。

uwsgi:
  #socket: 127.0.0.1:3031
  socket: /var/tmp/therm_uwsgi.sock
  frontend_root: /srv/http/therm/frontend
  master: true
  no-orphans: true
  threads: 1
  workers: 1
  cheaper: 1
  idle: 120
  uid: http
  gid: http
  harakiri: 1800
  harakiri-verbose: true
  max-requests: 5000
  auto-procname: true
  procname-prefix: therm_
  touch-reload: %(frontend_root)/reload
  touch-logreopen: /var/log/uwsgi/reload
  chdir: %(frontend_root)
  logto: /var/log/uwsgi/web.therm.log
  module: main:app
  plugins: python
  cache: 1024

UNIXドメインソケットを使う場合のnginxのupstreamの設定はこんな感じになる。

upstream uwsgi_app {
    server unix:///var/tmp/therm_uwsgi.sock max_fails=3 fail_timeout=8s;
    keepalive 64;
}

main.pyはこんな感じでこの辺も雛形。

# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; coding: utf-8; -*-

import bottle

try:
    import uwsgi
    from uwsgidecorators import postfork
except ImportError:
    uwsgi = None
else:
    @postfork
    def setup():
        pass

bottle.debug(True)
app = bottle.Bottle()

@app.get('/')
def app_root():
    return '<html><body><h1>hello</h1></body></html>'

setup関数に関しては今回たぶん使わない。uwsgiはpythonのプロセスを複数フォークすることができるので、フォーク後に新しいプロセスからDBへの接続など行う場合はsetup関数で処理する必要がある。

他のPCからsiegeで5並列でベンチとってみるとこんな感じ。

Transactions:                    844 hits
Availability:                 100.00 %
Elapsed time:                   8.17 secs
Data transferred:               0.03 MB
Response time:                  0.05 secs
Transaction rate:             103.30 trans/sec
Throughput:                     0.00 MB/sec
Concurrency:                    4.97
Successful transactions:         844
Failed transactions:               0
Longest transaction:            1.08
Shortest transaction:           0.01

たった40バイトのレスポンスで100 trans/secはさすが低スペック。実際は静的なコンテンツが大部分を占めるので、nginxのレイヤーで処理されるものばかりになるし、なにより自分しか使わないので、大丈夫だ、問題ない。

ここまできたら残りはほとんどフロントエンドの仕事になる。バックエンドでやることはpickleを読み込んで返すことと、もしかしたらテンプレートレンダリングとか、そのくらい。

ちなみに、pickleのデータはどっか(今はルートでない)のvarに入っていて、こんな感じになっている。

@pi1 $ find var
var
var/db
var/db/996cc068-fc68-3c4e-81e4-e74e0bff61d6
var/db/996cc068-fc68-3c4e-81e4-e74e0bff61d6/2015-06-09.pickle
var/db/996cc068-fc68-3c4e-81e4-e74e0bff61d6/2015-06-10.pickle

996cc068-fc68-3c4e-81e4-e74e0bff61d6はデバイスIDから生成したUUIDになってる。なぜこうしたかというと、デバイスIDがprintableでないから。

@pi1 $ hexdump /sys/bus/w1/devices/w1_bus_master1/28-00000647526d/id
0000000 6d28 4752 0006 3600

別のやりかたもあったと思うけど、とりあえずこでれいいやってことにした。