How to Setup Sync Gateway on Ubuntu/DigitalOcean

I recently set up Couchbase Sync Gateway on DigitalOcean. This is a note about setting Couchbase Sync Gateway with Couchbase Server on Ubuntu/DigitalOcean.

Step 1: Create Virtual Server on DigitalOcean

Before Step 1, please sign up DigitalOcean. DigitalOcean is super user friendly hosting. To create the virtual server, simply follow the tutorial How To Create Your First DigitalOcean Droplet Virtual Server.

Points:

  • Size: $5/mo is good enough for development/experiment
  • Droplet Region: Select closest region from my actual location. Response times from New York and San Francisco are different.
  • Droplet Image: Select Ubuntu 14.04 x64. Couchbase Server 3.0.x does not support 32bit.

Step 2: Setting up Ubuntu 14.04

For setting up Ubuntu such as create new user or configure firewall, I just followed the Tutorial Series New Ubuntu 14.04 Server Checklist.

Points:

  • Basic Firewall: Couchbase server admin UI uses port 8091 as default, and Couchbase Sync Gateway uses 4984 for replication and 4985 for admin UI. I recommend to open these three ports (4984, 4985 and 8091) in addition to SSH port 22.

My sample configuration for opening ports

$ sudo ufw show added
Added user rules (see 'ufw status' for running firewall):
ufw allow 22
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8091/tcp
ufw allow 4984/tcp
ufw allow 4985/tcp
$

Step 3: Install Couchbase Server 3.0.2

1. Download Couchbase Server
Couchbase Server is downloadable from Couchbase Download. Currently (03/21/2015) Couchbase Server 3.0.2 is only for Enterprise Edition only. Go to Version 3.0.1. Select 64-bit and Community Edition, then grab download URL from Download button for Ubuntu 12.04. By using wget command, download installation package to Ubuntu server. See following command.

$ wget http://packages.couchbase.com/releases/3.0.1/couchbase-server-community_3.0.1-ubuntu12.04_amd64.deb

2. Install Couchbase Server
Install the package using the dpkg command as a privileged user under sudo.

$ sudo dpkg -i couchbase-server-community_3.0.1-ubuntu12.04_amd64.deb

3. Confirm installation
Open the URL, http://<IP address of Ubuntu server>:8091/, from your favorite browser. You can see welcome page of Couchbase Server

4. Setup Couchbase Server
As a development server, I just use all default settings. For “Per Server RAM Quota:”, I set half of hosting server’s memory. For my case, it is 256MB. Although it is lower than recommended size, I think it is good enough for development.

5. Create Data Bucket for Sync Gateway
Select “Data Buckets” Menu on the top bar. Before creating new bucket for Sync Gateway, I deleted “default” bucket because no plan to use it. After that,  click “Create New Data Bucket” button. For Bucket Name, I chose “sync_gateway”. And set 256MB for “Per Node RAM Quota”.

Step 4: Install Couchbase Sync Gateway

1. Download Couchbase Sync Gateway
Couchbase Sync Gateway is also downloadable from Couchbase Download Link. You can find download link for Sync Gateway at middle of page. Current latest version of Sync Gateway is 1.0.3 (1.0.4 should be officially released soon). Select 64bit and Community Edition. For my case, if I download Sync Gateway installation package using wget and tried to install package, it fails. So I downloaded Sync Gateway installation package locally through my browser, then scp it from local computer to Ubuntu server.

2. Install Couchbase Sync Gateway
Install the package using the dpkg command as a privileged user under sudo.

$ sudo dpkg -i couchbase-sync-gateway-community_1.0.3_x86_64.deb

3. Sync Gateway configuration

The link is a default sync gateway configuration. The default setting does not allow GUEST user to access.  So I created following configuration file. The difference is Authorizing Users setting.

{
   "interface":":4984",
   "adminInterface":":4985",
   "log":["REST"],
   "databases":{
      "sync_gateway":{
         "users": {"GUEST": {"disabled": false, "all_channels": ["*"], "admin_channels": ["*"]}},
         "server":"http://localhost:8091",
         "bucket":"sync_gateway",
         "sync":`function(doc) {channel(doc.channels);}`
      }
   }
}

4. Start Sync Gateway

Following is how to start sync gateway

/opt/couchbase-sync-gateway/bin/sync_gateway ./config.json

Output just after started sync gateway

$ /opt/couchbase-sync-gateway/bin/sync_gateway ./config.json 
20:03:14.925870 Enabling logging: [REST]
20:03:14.926411 ==== Couchbase Sync Gateway/1.0.3(81;fa9a6e7) ====
20:03:14.926520 Opening db /sync_gateway as bucket "sync_gateway", pool "default", server <http://localhost:8091>
20:03:14.926674 Opening Couchbase database sync_gateway on <http://localhost:8091>
20:03:15.182813     Reset guest user to config
20:03:15.182843 Starting admin server on :4985
20:03:15.192678 Starting server on :4984 ...

5. Confirm Sync Gateway Running

To confirm replication port, open the URL, http://<IP address of Ubuntu server>:4984/, from your favorite browser. You can see welcome page of Couchbase Sync Gateway. See following.

{
   "couchdb":"Welcome",
   "vendor":{"name":"Couchbase Sync Gateway","version":1},
   "version":"Couchbase Sync Gateway/1.0.3(81;fa9a6e7)"
}

To confirm admin port, pen the URL, http://<IP address of Ubuntu server>:4985/_admin/, from your favorite browser. You can see admin UI of Sync Gateway.

Next Step:

I will write about How to sync with Couchbase Lite.

Flask Rest API with MongoDB

I found the great article, How to Build an API with Python and Flask. This post describes how to build REST API using Flask and MySQL. As I’d like to use MongoDB as a database. I’d like to explain how to create REST API using Flask and MongoDB in this post based on How to Build an API with Python and Flask.

1. Set up MongoDB
Please refer http://docs.mongodb.org/manual/installation/.

2. Import data into MongoDB
2.a. Download dataset from Download the raw text file of UFO sightings. This is TSV formated data.
2.b. This TSV file does not have header. So I manually added heder. See below.

$ head sightings.tsv
index	sighted_at	reported_at	location	shape	duration	description	latitude	longitude
0	19951009	19951009	Iowa City, IA			Man repts. witnessing "flash, followed by a classic UFO, w/ a tailfin at back." Red color on top half of tailfin. Became triangular.	41.6611277	-91.5301683

2.c. Also, as mongoimport command does not work well with double-quoted (“) string, I striped double-quotes from file with following command.

cat sightings.tsv | sed 's/"//g' > data.tsv

2.d. Following is command to import TSV formated data into MongoDB.

mongoimport --db ufo --collection ufo --type tsv --file data.tsv

2.e Make sure if data is loaded correctly.

$ mongo ufo
MongoDB shell version: 2.4.3
connecting to: ufo
> db.ufo.count()
60504
>

3. Install PyMongo, which is Python based driver to access MongoDB

$ pip install pymongo

4. Python codes with Flask and PyMongo
4.a Create connection to MongoDB using PyMongo
4.b toJson(data): To generate JSON from MongoDB objects,  use json_util (http://api.mongodb.org/python/1.7/api/pymongo/json_util.html).
4.c sightings(): PyMongo’s find() method returns Cursor (data is not yet loaded). So it is unable to directly serialize to JSON. So, it requires to read data into another object(s)
4.d sighting(sighting_id): To query by _id, use ObjectId. find_one() method returns object (not cursor).

from flask import Flask, request
import json
from bson import json_util
from bson.objectid import ObjectId
from pymongo import Connection

# Flask
app = Flask(__name__)

# MongoDB connection
connection = Connection('localhost', 27017)
db = connection.ufo
def toJson(data):
"""Convert Mongo object(s) to JSON"""
return json.dumps(data, default=json_util.default)

@app.route('/sightings/', methods=['GET'])
def sightings():
  """Return a list of all UFO sightings
  ex) GET /sightings/?limit=10&offset=20
  """
  if request.method == 'GET':
    lim = int(request.args.get('limit', 10))
    off = int(request.args.get('offset', 0))
    results = db['ufo'].find().skip(off).limit(lim)
    json_results = []
    for result in results:
      json_results.append(result)
    return toJson(json_results)

@app.route('/sightings/<sighting_id>', methods=['GET'])
def sighting(sighting_id):
  """Return specific UFO sighting
  ex) GET /sightings/123456
  """
  if request.method == 'GET':
    result = db['ufo'].find_one({'_id': ObjectId(sighting_id)})
    return toJson(result)

if __name__ == '__main__':
  app.run(debug=True)

6. How to test
Start flask dev server

python sightings.py

Test URLs

http://127.0.0.1:5000/sightings/?offset=10&limit=3
http://127.0.0.1:5000/sightings/517d625aee2f8817d3609574

Note: For Geo query with MongoDB, I will post how to do it with MongoDB as soon as I could figure out.

Measure temperature using Raspberry Pi with Temper USB Thermometer

Followings are notes how I set up USB Thermometer with Raspberry Pi

1. Hardware: USB Thermometer
I bought TEMPer USB Thermometer w/ Alerts.

2. temper – A command line sensor logger for Temper1 devices (C language)

Requirements (build-essential libusb-1.0.0 and libusb-dev)
    sudo apt-get install build-essential libusb-1.0.0 libusb-dev
    Note: Should install libusb-dev instead of libusb-x.x.x-dev

Source codes
    git clone https://github.com/bitplane/temper.git

Compile
    cd temper
    make

Usage
    sudo ./termper

Output
    28-Jan-2013 07:09,23.581625

temper-python – libusb/PyUSB-based driver to read TEMPer USB HID devices (USB ID 0c45:7401)

Requirements (libusb-1.0.0 and python-usb)
    sudo apt-get install libusb-1.0.0 python-usb

Source Codes
    git clone https://github.com/padelt/temper-python.git

Usage
    cd temper-python
    sudo python src/temper.py

Output
    Found 1 devices
    Device #0: 23.6°C 74.5°F

To allow non-root users access

sudo cp udev/99-tempsensor.rules /etc/udev/rules.d/
    Note: As default, root user has access to usb.

photo

AppEngineの書き込みオペレーションに付いて(前回からの宿題)

AppEngineのDataStoreでインデックスを無効にした場合、書き込みコストが下がるか調べてみました。

まず、全てのModelの全てのフィールドにてindexを無効にしました。

下記のコード参照
AppEngine DataStore Model which is disabled index

class Post(db.Model):
    id             = db.StringProperty(required=True, indexed=False)
    from_name      = db.StringProperty(required=True, indexed=False)
    from_id        = db.StringProperty(required=True, indexed=False)
    message        = db.TextProperty(required=False, indexed=False)
    type           = db.StringProperty(required=False, indexed=False)
    created_time   = db.StringProperty(required=False, indexed=False)

上記の設定にてAppEngine上のサービスを起動。

結果:

  1. 各フィールド毎のインデックスは作成されなくなった。よって書き込みオペレーションの回数が減り、コスト削減。
  2. しかし、DataStoreのエントリーの数と同数のインデックスが作成されている。よって、書き込みオペレーションの回数は書き込んだ(Put)エントリーの2倍発生。下記のイメージ参照。

考察:

キー(Key)でしかデータを参照(Lookup)しないので、なんとかインデックスを完全に無効にしたい。推測であるが、もしかしたら、このインデックスはキーでの参照用に作成されているのかも?自分のアプリのコストは、書き込みオペレーションからくるので、どうにかしたい。。。。。。

検索エンジン on AppEngine 開発の問題点

最近、Google AppEngine上で動作する、単純なFacebook個人コンテンツ検索エンジンを開発している。現在幾つかの問題点にぶつかっているので、その問題点を列挙しておこうと思います。

1. Facebookコンテンツの取得(クロール)に時間がかかる

Facebookのデータ取得にはFacebookのGraph APIを利用しています。自分のユーザー権限を利用して取得できるアップデート(ポスト)の数は約50,000件になります。1度のAPI呼び出しに25件取得出来るので、データを全て取得する為には、2,000回APIを呼び出す必要があります。さらに1度のAPI呼び出しに約数秒かかり、遅いケースでは5秒以上かかるケースもあります。(Slow facebook API via Python on Google App Engine (GAE))ユーザーがサインナップしてから、検索を始める事が出来るようになるまでに、1時間とか2時間とか待たなければならない事は避けなければなりません。コンテンツにプライオリティを付けて重要なものから取得するなどの工夫が必要です。

2. AppEngineのDB(DataStore)への書き込みが遅い

検索エンジンには、転置インデックスというデータ構造を用いています。転置インデックスはKey-Valueのデータ構造を用い、Keyにはキーワード(単語)、Valueにはキーワードを含むドキュメントのリストが保持されます。キーワードの種類はインデックスするドキュメントにもよりますが、ロングテイルとなります。さらに実装にも依存しますが、同じキーワードに対して何回かの更新がかかります。現在共有出来る数値はありませんが、大量の書き込みがある場合はAppEngineのDataStoreは遅いように感じます。

AppEngineのHigh Replication DataStore (HRD)は、信頼性を上げる為に書き込み速度を犠牲にしています。「What are the speed comparisons of NDB vs DB (on High Replication Datastore)? 」によると、HRDの書き込み速度は45ms、Master-Slaveの書き込みは20msかかるようです。

3. AppEngineのDB(DataStore)への書き込みコストが高い

自分のケースでは、アップデート(ポスト)の件数が、約50,000件、転置インデックスインデックスのデータ数が約25,000件あります。合計約75,000。これだけのデータを書き込む(更新も含む)のに、AppEngineのダッシュボードによると0.77M (77万)回の書き込みオペレーションが発生、1M の書き込みオペレーションのコストは$1なので、実際に77セント課金されています。プラス読み込みoperationにも課金され、読み込みには57セント課金されています。合計$1.24。1人分のインデックス作成(約180人の友人がいるケース)に$1は個人サービスとしては高すぎると感じる。

補足

あまりに書き込みオペレーションの回数がデータ数に対して大きいので、もう少し調べた結果、DataStoreがサポートするインデックの為に作られるデータの書き込みもカウントされているようです。自分のデータでは、74,608のデータに対し、977,995のインデックの為のデータが作成されています。上記のデータと一致しないのは、情報取得時のタイミング?インデックスを自動的に作成されないように、インデックスを無効にすることにより、書き込み速度の向上、および書き込みコストが下がるか調べようと考えています。

プロトタイプ

現在のバージョンは自分のアップデートしか検索できませんが、下記から試す事が出来ます。

https://locateweb.appspot.com

僕の中では、”今”オンライン学習が熱い!(もしかしたら僕の中だけ?)

今(今年)、オンライン学習が熱いと感じています。現在どんなオンライン学習サイトが立ち上がって来ているのか紹介したいと思います。

新しいサイトを紹介する前にまずは、「今までのインターネットを利用したオンライン学習ってどんなだっけ?」と言う所を見てみたいと思います。

1)大学の講義を受講する手段としてビデオ聴講が選択肢として提供されている。大学の講義に参加する代わりに、ビデオを見て学習し、宿題・課題を提出し、テストを受け、クレジット(評価)をもらう。約10年前にHarvard Extensionでコースをとった時には、既にビデオによる聴講手段は提供されていたので、かなり歴史が長いですね。コンピューター関連のクラスの殆どはこの方式をサポート。大学から遠い、仕事が忙しい人に学びの手段を提供していて、多くの学生が恩恵にあずかっている事と思います。昨年、同僚がStanfordのコースを取っていたが、仕事もある為、ビデオ学習していた。大学の講義なので授業料は安くないです。

2)大学が、講義のビデオを無料公開。大学に属する学生以外が、講義のビデオを見ることが出来る。MITやStanfordのクラスなど。大学側は、教授、学友とのインターラクションに価値を見出している為、講義のビデオを無料公開に踏み切った。ウィキペディアによると2002年に試験プログラムを開始したようですね。この方式も歴史が長いですね。1コースは大体、1回1時間から2時間程のクラスを10回又は20回分です。全てのビデオを集中して見続けるのは大変な為、自分には合わない方式です。

3)群衆の知恵方式。知識を持った人が、その知識をブログ、知識共有サイト、Q&Aサイトなどで共有。知識・解決策を探している人が、検索し知識を得る方式。多分インターネットを利用している人が既に毎日利用している方式ですね。知識共有サイトには、StackOverFlowなどがあります。最近流行りのQ&AサイトにはQuoraなどがあります。群衆の知恵+Google検索により多くの問題を解決出来るので大変素晴らし方式なのですが、体系的な知識をつけるには(100%じゃやないけど)向かない方式だといえます。。

他にも色々あると思いますが、ぱっと思い浮かんだのが上記の3方式です。

今年(2012年)の熱い状況

1)新年早々、スタートアップである、Codecademyがオンライン学習サイトを開始。現在はJavaScriptのクラスを週1回のペースで提供。何が凄いって?新年早々、40万人がサインアップして、JavaScriptの学習を開始。しかし、実際に勉強している人の数はかなり少ないとは思います。立ち上げたばかりのプログラミング学習サイトに40万人集めるのも凄いのですが、40万人もの人がJavaScriptを学ぼうと思った所がもっと凄い!。特徴として、課題などを終わらせる事に、バッジなどがもらえ、ゲーム感覚でプログラミング言語を学べる。現在はJavaScript入門的なコースなのですが、内容もしっかりしていて、学べるサイトだと感じています。

2)先週コースの第一週目が始まったのが、Stanfordの有名教授が始めたUdacity。ロボティクスのクラスを担当しているセバスチャンは本当に有名な大学教授らしいです。内容としては、大学と同クオリティーの授業をインターネットで提供。現在は2つのコースを提供しています。一つは、コンピューターサイエンス入門、入門ながら最終的には、検索エンジンを作ってしまおうという超野心的なコース。GoogleのFounderも紹介ビデオに出てきます。もう一つは、自動運転自動車のプログラミングコース(ロボティクス入門)。ロボット・人工知能の基礎が学べてしまいます。コンピューターサイエンス入門にはCS101の番号が付いていて、101の番号が付くものはアメリカでは、入門クラスという意味なのですが、Pythonをアカデミックな観点から勉強でき、かなり為になります。ロボティクスクラスはCS373と番号が付くだけに、コンピューターサイエンスの中ではアドバンス(ハイレベル)なクラスなのですが、ロボット(AI・人工知能)の基礎は統計(特に確率)で、基礎をしっかり学べます。いつかロボット作ってみたいなどの夢を持てるコースです。

3)まだ始まっていないのです(何らかの理由で延期)が、Stanfordも無料オンラインコースをはじめるようです。NLPのクラスに大変興味ありです。コンピュータサイエンス以外のコースもいくつかあります。リンク先の一番したに提供予定のコースリストがあります。コンピューターサイエンス以外のコースもあり。

4)正直リサーチ不足なのですが紹介しておきたいのがKhan Academy。jQueryの作者であるJohn ResigがKhan Academyの為に働き始めたりして自分のレーダーに引っかかり始めました。Khan Academyはコンピューターサイエンス以外のコースも多く提供しています。

5)上記4つとは少し違うのですが、tuts+のコースがプラクティカルでオススメ。自分が勉強しているのはjQueryの30日コース、毎日10分から30分程のビデオがアップされ毎日少しづつ学ぶ事ができます。仕事でjQueryを使っているのですが、体系的に学んだ事がなかったので、大変助かっています。一日分が短いため、継続できるのが凄く良い。内容もかなり良い。オススメ。チュートリアルなどWeb関連はかなり充実しています。

他にも色々あるとは思いますが、上記5つが自分のレーダーに入っています。よく見れば皆コンピユーターサイエンス関連ですね。他の分野も、オンライン化されているのでしょうか?

ちなみに自分の中では、オンライン学習ブームで家に帰って来ると上記のサイトにアクセスしてばかりいます。その他にもやらなきゃいけない事が多くあるのに。自分の中のこのブームが習慣になるように心掛けたいと思います。

1 ÷ 998001 = 興味深い結果

知っている方もいるかもしれませんが、ウエブで面白い数学のFactを見つけたので紹介したいと思います。

↓元ネタ
http://www.iheartchaos.com/post/16393143676/fun-with-math-dividing-one-by-998001-yields-a

1を998001で割ると小数点以下が000、001、002、003、004,005、006、007、008、009、010、011、012、013、014、015、016、017、018、019、020、021、022、023、024、025、026、027、028、029、…、999と並ぶのです。

1/998001 = 0.000001002003004005006007008009010011012013014015016017018019020
0210220230240250260270280290300310320330340350360370380390400410420430440450
4604704804905005105205305405505605705805906006106206306406506606706806907007
1072073074075076077078079080081082083084085086087088089090091092093094095096
0970980991001011021031041051061071081091101111121131141151161171181191201211
2212312412512612712812913013113213313413513613713813914014114214314414514614
7148149150151152153154155156157158159160161162163164165166167168169170171172
1731741751761771781791801811821831841851861871881891901911921931941951961971
9819920020120220320420520620720820921021121221321421521621721821922022122222
3224225226227228229230231232233234235236237238239240241242243244245246247248
2492502512522532542552562572582592602612622632642652662672682692702712722732
7427527627727827928028128228328428528628728828929029129229329429529629729829
9300301302303304305306307308309310311312313314315316317318319320321322323324
3253263273283293303313323333343353363373383393403413423433443453463473483493
5035135235335435535635735835936036136236336436536636736836937037137237337437
5376377378379380381382383384385386387388389390391392393394395396397398399400
4014024034044054064074084094104114124134144154164174184194204214224234244254
2642742842943043143243343443543643743843944044144244344444544644744844945045
1452453454455456457458459460461462463464465466467468469470471472473474475476
4774784794804814824834844854864874884894904914924934944954964974984995005015
0250350450550650750850951051151251351451551651751851952052152252352452552652
7528529530531532533534535536537538539540541542543544545546547548549550551552
5535545555565575585595605615625635645655665675685695705715725735745755765775
7857958058158258358458558658758858959059159259359459559659759859960060160260
3604605606607608609610611612613614615616617618619620621622623624625626627628
6296306316326336346356366376386396406416426436446456466476486496506516526536
5465565665765865966066166266366466566666766866967067167267367467567667767867
9680681682683684685686687688689690691692693694695696697698699700701702703704
7057067077087097107117127137147157167177187197207217227237247257267277287297
3073173273373473573673773873974074174274374474574674774874975075175275375475
5756757758759760761762763764765766767768769770771772773774775776777778779780
7817827837847857867877887897907917927937947957967977987998008018028038048058
0680780880981081181281381481581681781881982082182282382482582682782882983083
1832833834835836837838839840841842843844845846847848849850851852853854855856
8578588598608618628638648658668678688698708718728738748758768778788798808818
8288388488588688788888989089189289389489589689789889990090190290390490590690
7908909910911912913914915916917918919920921922923924925926927928929930931932
9339349359369379389399409419429439449459469479489499509519529539549559569579
5895996096196296396496596696796896997097197297397497597697797897998098198298
3984985986987988989990991992993994995996997999 ...