Couchbase Server 2.0 ドキュメント翻訳に参加しました

Couchbaseへの理解と英語強化の為に、Couchbase Server 2.0のドキュメント翻訳に参加しました。
途中仕事が忙しくなったこともあり、当初自分が予定していたほど翻訳活動に参加できませんでしたが、他メンバの方々のおかげで無事公開されました。

Couchbase Server 2.0 ドキュメント

翻訳チームに参加したのは初めてでしたが、自社ソフトウェアのプルーフリード作業にも活かしていきたいと思います。

CouchConf に行ってきました

CouchConf Tokyoに行ってきました。
仕事の都合で午前の部のみとなりましたが、Couchbaseが良く出来ていることを実感したカンファレンスでした。
自分の会社製品とよく似たコンセプトである為、今後の製品としての伸びや自分のスキルの振り方判断になればと思い、少し触っていました。Couchbaseユーザグループでver2.0のマニュアル翻訳に参加したので、これからもっと機能を確認していこうと思います。
それにしても、コンソールの機能・デザインが秀逸です。馬鹿高い自社製品も見習って欲しいところです。
couchbase_top

CouchDB on AWS 最速インストール

CouchDBをインストールをする際に何度かハマってしまったので、AWS上で動かすまでの最速インストール手順を残します。
以下の手順を実行する前に、EC2インスタンスをLaunchしておきます。なお、今回はAmazon Imageを対象としています。

ssh -i [your pem-file] ec2-user@[your ec2-instance]
sudo yum -y update
sudo yum -y install git expect
mkdir git
git clone https://gist.github.com/1171217.git
cd git

vi couchdb-ec2-install.sh
##  you need to change 2 lines for version of couchdb and erlang.
##  For checking CouchDB ver: https://github.com/apache/couchdb/tags
##  For checking Erlang ver: http://www.erlang.org/doc/apps/erts/notes.html

sudo sh couchdb-ec2-install.sh
sudo couchdb start -b
Apache CouchDB 1.2.1 (LogLevel=error) is starting.
Apache CouchDB has started. Time to relax.

Gitからcloneしたら、インストール用のshellスクリプト内のCouchDB, Erlangのバージョンだけ最新に変更して実行します。
(この実行は少し時間がかかる)
あとFutonにアクセスする時に使うAdminパスワードはスクリプト実行結果に出力されますが、
変更する場合は /usr/local/etc/couchdb/local.ini を変更します。事前にshellを変更しておいても良いです。
最後にFutonにアクセスして起動を確認して完了です。

編集後のcouchdb-ec2-install.sh はこのような感じです。(今回はCouchDB:1.2.1, Erlang: 5.9.3.1とした)

#!/bin/bash

#
# This script installs and configures couchdb on a fresh Amazon Linux AMI instance.
#
# Must be run with root privileges
# Tested with Amazon Linux AMI release 2011.02.1.1 (ami-8c1fece5)
#

export BUILD_DIR="$PWD"

# install gem dependencies
yum install gcc gcc-c++ libtool curl-devel ruby-rdoc zlib-devel openssl-devel make automake rubygems perl git-core
gem install rake --no-ri --no-rdoc

if [ ! -e "/usr/local/bin/couchdb" ]
then

  if [ ! -d "$BUILD_DIR/build-couchdb" ]
  then
    # get build-couch code
    git clone git://github.com/iriscouch/build-couchdb
    cd $BUILD_DIR/build-couchdb/
    git submodule init
    git submodule update
  fi

  # run build-couch
  cd $BUILD_DIR/build-couchdb/
  rake git="git://git.apache.org/couchdb.git tags/1.2.1" install=/usr/local
fi

# install our .ini
cat << 'EOF' > /usr/local/etc/couchdb/local.ini
[couchdb]
delayed_commits = false

[httpd]
port = 80
bind_address = 0.0.0.0
socket_options = [{recbuf, 262144}, {sndbuf, 262144}, {nodelay, true}]
WWW-Authenticate = Basic realm="administrator"
;WWW-Authenticate = bummer

[couch_httpd_auth]
require_valid_user = true

[log]
level = error

[admins]
EOF

# generate & set the initial password
export ADMIN_PASSWORD=`mkpasswd`
echo "admin = ${ADMIN_PASSWORD}" >> /usr/local/etc/couchdb/local.ini

# allow beam to bind to port 80 (not necessary if you make httpd.port >=1024)
setcap 'cap_net_bind_service=+ep' /usr/local/lib/erlang/erts-5.9.3.1/bin/beam

if [ ! -e "/etc/logrotate.d/couchdb" ]
then
  # add couch.log to logrotate
  ln -s /usr/local/etc/logrotate.d/couchdb /etc/logrotate.d/
  # change to daily rotation
  sed -e s/weekly/daily/g -i /usr/local/etc/logrotate.d/couchdb
  #logrotate -v -f /etc/logrotate.d/couchdb 
fi

# add couchdb user
adduser --system --home /usr/local/var/lib/couchdb -M --shell /bin/bash --comment "CouchDB" couchdb

# change file ownership
chown -R couchdb:couchdb /usr/local/etc/couchdb /usr/local/var/lib/couchdb /usr/local/var/log/couchdb /usr/local/var/run/couchdb

# run couchdb on startup
ln -s /usr/local/etc/rc.d/couchdb /etc/init.d/couchdb
chkconfig --add couchdb
chkconfig --level 345 couchdb on

# done!
echo
echo
echo "Installation complete!"
echo "Couchdb admin password was set to: ${ADMIN_PASSWORD}"
echo
echo "Couchdb is ready to start. Run:"
echo "    sudo service couchdb start"

MapReduce Views in CouchDB

前回に続いて、MapReduceによるView作成、View実行を確認してみました。
Javascript以外の言語でMapReduceを行う場合は、couchDBのiniファイルに以下のようなイメージで追記します。
正常反映されれば、FutonのView Codeセグメントでlanguageとして使用可能となります。

[query_servers]
python = /usr/bin/couchpy

下記はサンプルとして、tweetのユーザ情報でlocation = ‘Tokyo’であるtweetを出力しています。
また、本サンプルではReduce処理を使用していません。
https://github.com/shmachid/twitter_mining/blob/master/define_view_in_couch.py

# -*- coding: utf-8 -*-

import couchdb
from couchdb.design import ViewDefinition


SERVER_URL = 'YOUR COUCHDB URL'    #ex: http://localhost:5984
DB_USER = 'YOUR USER'
DB_PASSWD = 'YOUR PASSWORD'
DB = 'YOUR DB NAME'

server = couchdb.Server(SERVER_URL)
server.resource.credentials = (DB_USER, DB_PASSWD)


try:
    db = server.create(DB)

except couchdb.http.PreconditionFailed, e:
    db = server[DB]

    def mapper(doc):
        if doc['author']['location'] == "Tokyo":
            yield (doc['id'], doc['text'])

    ## if you need to use reduce function, please remove bellow the comment-tag.
    #def reducer(keys, values, rereduce):
    #    return max(values)

    view = ViewDefinition('index', 'map_location', mapper, language='python')
    #view = ViewDefinition('index', 'map_location', mapper, reducer, language='python')
    view.sync(db)


    records = [(row.key, row.value) for row in db.view('index/map_location')]

    for record in records:
        print record[1]

Viewを作成・更新後、初回実行時にViewの更新処理が走る為、View実行完了まで時間が掛かりました。(対象件数は25万件であった)
データ更新が絶えず入っている状況でViewへアクセスがあった場合は、どのよう挙動となるのかが気になります。
ログは以下のように出力されます。何か良い方法あるのかな、探したけど分からなかった。

[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244494 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244520 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244548 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244579 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244606 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244634 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244664 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244693 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244721 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244747 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244773 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244797 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244821 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244848 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244877 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244903 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244934 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244961 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244991 for tweets _design/index

Twitter Streaming API to CouchDB with tweepy and jsonpickle

Twitter Streaming API: filter()からCouchDBへ流しこむサンプルスクリプトを作りました。
返ってきたStatus情報等を全て格納しておりテーブルサイズが大きくなりやすいので、適度にフィルタを掛けると良いです。
連休前と連休中で画像共有サービスの利用頻度が変わるのかを確認する為にFilter条件をtwippleで行なったところ、ゴールデンウィーク中は1日で19万件程度tweetされていました。
連休前として2週間程前に収集した際は10万件程でしたので、行楽中は画像共有サービスの利用が増えるようです。
https://github.com/shmachid/twitter_mining/blob/master/stream2couch.py

# -*- coding: utf-8 -*-

import sys
import time
from datetime import datetime
import tweepy
import json
import jsonpickle
import couchdb


if (len(sys.argv) < 2):
    print "Usage: please check your parameter"
    sys.exit()


QUERY = sys.argv[1:]

SERVER_URL = 'YOUR COUCHDB URL'    #ex: http://localhost:5984
DB_USER = 'YOUR USER'
DB_PASSWD = 'YOUR PASSWORD'
DB = 'YOUR DB NAME'

CONSUMER_KEY = 'YOUR CONSUMERKEY'
CONSUMER_SECRET = 'YOUR CONSUMER_SECRET'
ACCESS_TOKEN = 'YOUR ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'YOUR ACCESS_TOKEN_SECRET'

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)

server = couchdb.Server(SERVER_URL)
server.resource.credentials = (DB_USER, DB_PASSWD)


try:
    db = server.create(DB)

except couchdb.http.PreconditionFailed, e:
    db = server[DB]

class CustomStreamListener(tweepy.StreamListener):

    def on_status(self, status):
        results = {}
        try:
            if status.id_str in db:
                return True

            pickled = jsonpickle.encode(status)
            results = json.loads(pickled)
            del results['_api']

            db[results['id_str']] = results

        except Exception, e:
            print >> sys.stderr, "Encountered Exception:", e
            pass

    def on_error(self, status_code):
        print >> sys.stderr, "Encountered error with status code:", status_code
        return True

    def on_timeout(self):
        print >> sys.stderr, "Timeout..."
        return True 


streaming_api = tweepy.streaming.Stream(auth, CustomStreamListener(), timeout=60)
print >> sys.stderr, 'Filtering parameters: "%s"' % (' '.join(sys.argv[1:]),)

try:  # sample(): streaming_api.sample()
    streaming_api.filter(follow=None, track=QUERY)

except Exception, e:
    print >> sys.stderr, "Error: '%s' '%S'" % (str(datetime.now()), str(e))

finally:
    print >> sys.stderr, "disconnecting..."
    streaming_api.disconnect()

CouchDB, CouchAppをさわってみる

前回のCouchDBインストールに引き続き、CouchDBをさわりました。
また、CouchDBでアプリケーション開発するツールであるCouchAppをインストールし、少しさわってみます。

1. adminユーザ設定
データベース作成の前に、必要に応じてadminユーザ設定を行います。
/etc/couchdb/local.ini内にadminユーザ設定箇所あるので、任意のユーザを設定します。
設定後、管理コンソール「Futon」に行き、ログインして確認します。
場所が分かりづらかったのですが、右下部にログインリンクがあります。
また、コマンドライン経由で何らかのアクションを実行する場合、URLにユーザ名とパスワードを含めます。
例えば、http://[user]:[passwd]@[serverIP]:[port]/[db] のようなイメージとなります。

2. データベース作成
データベース作成は、ブラウザ経由でやっても良いですし、コマンドラインからも行えます。
今回はコマンドラインから行います。
下記では最初にadminユーザの指定をしなかったので、エラーとなっています。
また、”PUT”を指定しているところからも、Restfulインタフェースを通じてCouchDBを操作しているのが
確認出来ます。

[shmachid@hoge couchdb]$ curl -X PUT http://49.212.1.17:xxxx/test
{"error":"unauthorized","reason":"You are not a server admin."}
[shmachid@hoge couchdb]$ curl -X PUT http://[user]:[passwd]@49.212.1.17:xxxx/test
{"ok":true}

上記を実行後、Futon(http://49.212.1.17:xxxx/_utils/index.html)からデータベースを確認してください。

3. データ投入
作成したデータベースにデータ投入を行います。
最初はコマンドラインから直に指定してみます。

[shmachid@hoge couchdb6]$ curl -X POST -d '{"data":"hoge test"}' -H 'Content-Type:appl
ication/json; charset=UTF-8' http://[user]:[passwd]@49.212.1.17:xxxx/test
{"ok":true,"id":"ee326263173915e2e424eb8d62002388","rev":"1-2328b45ab4c4437012c5b7defd9ef59d"}

コマンドライン、ブラウザの双方でデータがJSON形式になっているのが確認出来ます。

次に作成済みのHTMLファイルを投入します。
まず、投入対象のHTMLファイルを作ります。

<html>
  <body>test hogehoge</body>
</html>

下記のようなJSONファイルを作ります。コマンドラインで指定をしていたデータ情報を記述します。

{
  "id" : "test_data",
  "_attachments" : {
      "index.html" : {
         "data" : "PGh0bWw+CiA8Ym9keT50ZXN0IGhvZ2Vob2dlPC9ib2R5Pgo8L2h0bWw+Cg==",
         "content_type" : "text/html"
      }
  }
}

上記JSONファイル中のdataには下記のbase64でエンコードした文字列をセットします。

[shmachid@hoge couchdb_test]$ openssl base64 -in index.html
PGh0bWw+CiA8Ym9keT50ZXN0IGhvZ2Vob2dlPC9ib2R5Pgo8L2h0bWw+Cg==

準備は完了したので、投入してみます。

[shmachid@hoge couchdb_test]$ curl -X POST -H 'Content-Type:application/json; charset=
UTF-8' -d @test_data.json http://[user]:[passwd]@49.212.1.17:xxxx/test
{"ok":true,"id":"ee326263173915e2e424eb8d62002945","rev":"1-d7387e19cfef70dc557a98a8d4d65816"}

再び、Futonからデータベース内を確認すると、データが増えているのが分かります。
index.htmlもJSON形式で格納されており、開く事も出来ます。
今度はFutonからExcelファイルをアップロードしてみます。
New Documentボタンを押下すると、Key値が自動提案されてきます。

4. CouchAppインストール
CouchDBでアプリケーション開発を行うツールであるCouchAppをインストールします。
ここが結構ハマったのですが、CouchAppを使用する場合、Pythonはversion2.6以上である必要があります。
sakuraVPSの場合、デフォルトではversion2.4となる為、最後のインストール部分でSyntax errorとなります。
Python2.6へのアップグレードはこちらを参考にさせてもらいました。
では、CouchAppのセットアップをしていきます。
途中、Python2.6が認識出来ずに2.4が適用されてしまう部分では、明示的に指定しています。

[shmachid@hoge couchdb6]$ curl -O http://python-distribute.org/distribute_setup.py
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 15757  100 15757    0     0  11195      0  0:00:01  0:00:01 --:--:-- 25853
[shmachid@hoge couchdb6]$ sudo /usr/local/python-2.6.2/bin/python distribute_setup.py
[sudo] password for shmachid:
Downloading http://pypi.python.org/packages/source/d/distribute/distribute-0.6.19.tar.gz
Extracting in /tmp/tmpGa3LNw
Now working in /tmp/tmpGa3LNw/distribute-0.6.19
Installing Distribute
Before install bootstrap.
Scanning installed packages
Setuptools installation detected at /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools-0.6c12dev_r88846-py2.6.egg
Egg installation
Patching...
Renaming /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools-0.6c12dev_r88846-py2.6.egg into /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools-0.6c12dev_r88846-py2.6.egg.OLD.1312983070.12
Patched done.
Relaunching...
Before install bootstrap.
Scanning installed packages
Setuptools installation detected at /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools-0.6c12dev_r88846-py2.6.egg
Egg installation
Already patched.
running install
running bdist_egg
running egg_info
writing distribute.egg-info/PKG-INFO
writing top-level names to distribute.egg-info/top_level.txt
writing dependency_links to distribute.egg-info/dependency_links.txt
writing entry points to distribute.egg-info/entry_points.txt
reading manifest file 'distribute.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'distribute.egg-info/SOURCES.txt'
installing library code to build/bdist.linux-x86_64/egg
running install_lib
running build_py
creating build
creating build/lib
copying pkg_resources.py -> build/lib
copying easy_install.py -> build/lib
copying site.py -> build/lib
creating build/lib/setuptools
copying setuptools/extension.py -> build/lib/setuptools
copying setuptools/__init__.py -> build/lib/setuptools
copying setuptools/depends.py -> build/lib/setuptools
copying setuptools/package_index.py -> build/lib/setuptools
copying setuptools/sandbox.py -> build/lib/setuptools
copying setuptools/archive_util.py -> build/lib/setuptools
copying setuptools/dist.py -> build/lib/setuptools
creating build/lib/setuptools/command
copying setuptools/command/bdist_rpm.py -> build/lib/setuptools/command
copying setuptools/command/test.py -> build/lib/setuptools/command
copying setuptools/command/build_py.py -> build/lib/setuptools/command
copying setuptools/command/easy_install.py -> build/lib/setuptools/command
copying setuptools/command/sdist.py -> build/lib/setuptools/command
copying setuptools/command/__init__.py -> build/lib/setuptools/command
copying setuptools/command/upload_docs.py -> build/lib/setuptools/command
copying setuptools/command/rotate.py -> build/lib/setuptools/command
copying setuptools/command/saveopts.py -> build/lib/setuptools/command
copying setuptools/command/install_lib.py -> build/lib/setuptools/command
copying setuptools/command/install_scripts.py -> build/lib/setuptools/command
copying setuptools/command/alias.py -> build/lib/setuptools/command
copying setuptools/command/build_ext.py -> build/lib/setuptools/command
copying setuptools/command/upload.py -> build/lib/setuptools/command
copying setuptools/command/register.py -> build/lib/setuptools/command
copying setuptools/command/egg_info.py -> build/lib/setuptools/command
copying setuptools/command/setopt.py -> build/lib/setuptools/command
copying setuptools/command/bdist_wininst.py -> build/lib/setuptools/command
copying setuptools/command/install.py -> build/lib/setuptools/command
copying setuptools/command/install_egg_info.py -> build/lib/setuptools/command
copying setuptools/command/develop.py -> build/lib/setuptools/command
copying setuptools/command/bdist_egg.py -> build/lib/setuptools/command
creating build/lib/setuptools/tests
copying setuptools/tests/test_build_ext.py -> build/lib/setuptools/tests
copying setuptools/tests/doctest.py -> build/lib/setuptools/tests
copying setuptools/tests/test_develop.py -> build/lib/setuptools/tests
copying setuptools/tests/server.py -> build/lib/setuptools/tests
copying setuptools/tests/test_upload_docs.py -> build/lib/setuptools/tests
copying setuptools/tests/__init__.py -> build/lib/setuptools/tests
copying setuptools/tests/test_resources.py -> build/lib/setuptools/tests
copying setuptools/tests/test_sandbox.py -> build/lib/setuptools/tests
copying setuptools/tests/test_packageindex.py -> build/lib/setuptools/tests
copying setuptools/tests/test_easy_install.py -> build/lib/setuptools/tests
copying setuptools/gui.exe -> build/lib/setuptools
copying setuptools/cli.exe -> build/lib/setuptools
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/egg
copying build/lib/easy_install.py -> build/bdist.linux-x86_64/egg
copying build/lib/pkg_resources.py -> build/bdist.linux-x86_64/egg
copying build/lib/site.py -> build/bdist.linux-x86_64/egg
creating build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/extension.py -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/__init__.py -> build/bdist.linux-x86_64/egg/setuptools
creating build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/bdist_rpm.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/test.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/build_py.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/easy_install.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/sdist.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/__init__.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/upload_docs.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/rotate.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/saveopts.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/install_lib.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/install_scripts.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/alias.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/build_ext.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/upload.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/register.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/egg_info.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/setopt.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/bdist_wininst.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/install.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/install_egg_info.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/develop.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/command/bdist_egg.py -> build/bdist.linux-x86_64/egg/setuptools/command
copying build/lib/setuptools/depends.py -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/gui.exe -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/package_index.py -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/sandbox.py -> build/bdist.linux-x86_64/egg/setuptools
creating build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_build_ext.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/doctest.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_develop.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/server.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_upload_docs.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/__init__.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_resources.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_sandbox.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_packageindex.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/tests/test_easy_install.py -> build/bdist.linux-x86_64/egg/setuptools/tests
copying build/lib/setuptools/cli.exe -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/archive_util.py -> build/bdist.linux-x86_64/egg/setuptools
copying build/lib/setuptools/dist.py -> build/bdist.linux-x86_64/egg/setuptools
byte-compiling build/bdist.linux-x86_64/egg/easy_install.py to easy_install.pyc
byte-compiling build/bdist.linux-x86_64/egg/pkg_resources.py to pkg_resources.pyc
byte-compiling build/bdist.linux-x86_64/egg/site.py to site.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/extension.py to extension.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/bdist_rpm.py to bdist_rpm.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/test.py to test.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/build_py.py to build_py.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/easy_install.py to easy_install.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/sdist.py to sdist.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/upload_docs.py to upload_docs.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/rotate.py to rotate.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/saveopts.py to saveopts.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/install_lib.py to install_lib.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/install_scripts.py to install_scripts.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/alias.py to alias.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/build_ext.py to build_ext.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/upload.py to upload.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/register.py to register.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/egg_info.py to egg_info.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/setopt.py to setopt.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/bdist_wininst.py to bdist_wininst.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/install.py to install.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/install_egg_info.py to install_egg_info.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/develop.py to develop.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/command/bdist_egg.py to bdist_egg.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/depends.py to depends.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/package_index.py to package_index.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/sandbox.py to sandbox.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_build_ext.py to test_build_ext.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/doctest.py to doctest.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_develop.py to test_develop.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/server.py to server.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_upload_docs.py to test_upload_docs.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/__init__.py to __init__.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_resources.py to test_resources.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_sandbox.py to test_sandbox.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_packageindex.py to test_packageindex.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/tests/test_easy_install.py to test_easy_install.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/archive_util.py to archive_util.pyc
byte-compiling build/bdist.linux-x86_64/egg/setuptools/dist.py to dist.pyc
creating build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/entry_points.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/entry_points.txt.orig -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
copying distribute.egg-info/zip-safe -> build/bdist.linux-x86_64/egg/EGG-INFO
creating dist
creating 'dist/distribute-0.6.19-py2.6.egg' and adding 'build/bdist.linux-x86_64/egg' to it
removing 'build/bdist.linux-x86_64/egg' (and everything under it)
Processing distribute-0.6.19-py2.6.egg
creating /usr/local/python-2.6.2/lib/python2.6/site-packages/distribute-0.6.19-py2.6.egg
Extracting distribute-0.6.19-py2.6.egg to /usr/local/python-2.6.2/lib/python2.6/site-packages
Adding distribute 0.6.19 to easy-install.pth file
Installing easy_install script to /usr/local/python-2.6.2/bin
Installing easy_install-2.6 script to /usr/local/python-2.6.2/bin

Installed /usr/local/python-2.6.2/lib/python2.6/site-packages/distribute-0.6.19-py2.6.egg
Processing dependencies for distribute==0.6.19
Finished processing dependencies for distribute==0.6.19
After install bootstrap.
Creating /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg-info
Creating /usr/local/python-2.6.2/lib/python2.6/site-packages/setuptools.pth
[shmachid@hoge couchdb6]$ sudo easy_install pip
Searching for pip
Reading http://pypi.python.org/simple/pip/
Reading http://www.pip-installer.org
Reading http://pip.openplans.org
Best match: pip 1.0.2
Downloading http://pypi.python.org/packages/source/p/pip/pip-1.0.2.tar.gz#md5=47ec6ff3f6d962696fe08d4c8264ad49
Processing pip-1.0.2.tar.gz
Running pip-1.0.2/setup.py -q bdist_egg --dist-dir /tmp/easy_install-g89SGU/pip-1.0.2/egg-dist-tmp-Ci0LUo
warning: no files found matching '*.html' under directory 'docs'
warning: no previously-included files matching '*.txt' found under directory 'docs/_build'
no previously-included directories found matching 'docs/_build/_sources'
Adding pip 1.0.2 to easy-install.pth file
Installing pip script to /usr/local/python-2.6.2/bin
Installing pip-2.6 script to /usr/local/python-2.6.2/bin

Installed /usr/local/python-2.6.2/lib/python2.6/site-packages/pip-1.0.2-py2.6.egg
Processing dependencies for pip
Finished processing dependencies for pip
[shmachid@hoge couchdb6]$ sudo pip install couchapp
Downloading/unpacking couchapp
  Downloading Couchapp-0.8.1.tar.gz (422Kb): 422Kb downloaded
  Running setup.py egg_info for package couchapp
    warning: manifest_maker: MANIFEST.in, line 5: 'recursive-include' expects <dir> <pattern1> <pattern2> ...
Installing collected packages: couchapp
  Running setup.py install for couchapp
    building 'couchapp.autopush._select' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -DHAVE_EPOLL=1 -DHAVE_SYS_EPOLL_H=1 -I/usr/local/python-2.6.2/include/python2.6 -c couchapp/autopush/selectmodule.c -o build/temp.linux-x86_64-2.6/couchapp/autopush/selectmodule.o
    gcc -pthread -shared build/temp.linux-x86_64-2.6/couchapp/autopush/selectmodule.o -o build/lib.linux-x86_64-2.6/couchapp/autopush/_select.so
    Linking /home/shmachid/work/couchdb6/build/couchapp/build/lib.linux-x86_64-2.6/couchapp/autopush/_select.so to /home/shmachid/work/couchdb6/build/couchapp/couchapp/autopush/_select.so
    changing mode of build/scripts-2.6/couchapp from 644 to 755
    warning: manifest_maker: MANIFEST.in, line 5: 'recursive-include' expects <dir> <pattern1> <pattern2> ...
    changing mode of /usr/local/python-2.6.2/bin/couchapp to 755
Successfully installed couchapp
Cleaning up...

5. CouchApp 確認
CouchAppのインストールが完了したので、確認します。
アプリケーションを作ってみます。

[shmachid@hoge couchdb6]$ couchapp generate fuga
2011-08-11 02:02:00 [INFO] /home/shmachid/work/couchdb6/fuga generated.

作成したベーステンプレートをCouchDBへpushします。

[shmachid@hoge couchdb6]$ cd fuga
[shmachid@hoge fuga]$ couchapp push http://[user]:[passwd]@49.212.1.17:xxxx/test
2011-08-11 02:04:28 [INFO] Visit your CouchApp here:
http://49.212.1.17:xxxx/test/_design/fuga/index.html


Futonにて、一緒にpushしたその他のファイルが格納されたことを確認できます。

なお、これらはみてわかるクラウドマガジンvol.3 (日経BPパソコンベストムック)
を参考にさせていただきました。

以上です。


CentOS5.6にCouchDBをインストール

ドキュメント指向型のNoSQLであるCouchDBをインストールしてみました。
OSはCentOS5.6となります。

1. CouchDBインストール
yumからCouchDBをパッケージインストールします。

[shmachid@hoge ~]$ yum list | grep couchdb
couchdb.x86_64                             0.11.2-2.el5                epel
[shmachid@hoge ~]$ su -
[root@hoge ~]# yum install couchdb enablerepo=remi
Loaded plugins: downloadonly, fastestmirror, priorities
Loading mirror speeds from cached hostfile
 * addons: ftp.nara.wide.ad.jp
 * base: ftp.nara.wide.ad.jp
 * epel: ftp.kddilabs.jp
 * extras: ftp.nara.wide.ad.jp
 * updates: ftp.nara.wide.ad.jp
addons                                                              |  951 B     00:00
base                                                                | 2.1 kB     00:00
epel                                                                | 3.7 kB     00:00
extras                                                              | 2.1 kB     00:00
updates                                                             | 1.9 kB     00:00
Excluding Packages in global exclude list
Finished
208 packages excluded due to repository priority protections
Setting up Install Process
No package enablerepo=remi available.
Resolving Dependencies
--> Running transaction check
---> Package couchdb.x86_64 0:0.11.2-2.el5 set to be updated
--> Processing Dependency: erlang-tools for package: couchdb
--> Processing Dependency: erlang-sasl for package: couchdb
--> Processing Dependency: erlang-crypto for package: couchdb
--> Processing Dependency: erlang-mochiweb for package: couchdb
--> Processing Dependency: erlang-stdlib for package: couchdb
--> Processing Dependency: erlang-kernel for package: couchdb
--> Processing Dependency: erlang-erts for package: couchdb
--> Processing Dependency: erlang-inets for package: couchdb
--> Processing Dependency: erlang-ibrowse for package: couchdb
--> Processing Dependency: erlang-oauth for package: couchdb
--> Processing Dependency: libjs.so.1()(64bit) for package: couchdb
--> Running transaction check
---> Package erlang.x86_64 0:R12B-5.10.el5 set to be updated
---> Package erlang-ibrowse.x86_64 0:2.1.0-1.el5 set to be updated
---> Package erlang-mochiweb.x86_64 0:1.4.1-5.el5 set to be updated
---> Package erlang-oauth.x86_64 0:1.0.1-1.el5 set to be updated
---> Package js.x86_64 0:1.70-8.el5 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

===========================================================================================
 Package                   Arch             Version                   Repository      Size
===========================================================================================
Installing:
 couchdb                   x86_64           0.11.2-2.el5              epel           558 k
Installing for dependencies:
 erlang                    x86_64           R12B-5.10.el5             epel            39 M
 erlang-ibrowse            x86_64           2.1.0-1.el5               epel            48 k
 erlang-mochiweb           x86_64           1.4.1-5.el5               epel           368 k
 erlang-oauth              x86_64           1.0.1-1.el5               epel            27 k
 js                        x86_64           1.70-8.el5                epel           392 k

Transaction Summary
===========================================================================================
Install       6 Package(s)
Upgrade       0 Package(s)

Total download size: 41 M
Is this ok [y/N]: y
Downloading Packages:
(1/6): erlang-oauth-1.0.1-1.el5.x86_64.rpm                          |  27 kB     00:00
(2/6): erlang-ibrowse-2.1.0-1.el5.x86_64.rpm                        |  48 kB     00:00
(3/6): erlang-mochiweb-1.4.1-5.el5.x86_64.rpm                       | 368 kB     00:00
(4/6): js-1.70-8.el5.x86_64.rpm                                     | 392 kB     00:00
(5/6): couchdb-0.11.2-2.el5.x86_64.rpm                              | 558 kB     00:00
(6/6): erlang-R12B-5.10.el5.x86_64.rpm                              |  39 MB     00:02
-------------------------------------------------------------------------------------------
Total                                                       12 MB/s |  41 MB     00:03
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing     : erlang                                                              1/6
  Installing     : js                                                                  2/6
  Installing     : erlang-oauth                                                        3/6
  Installing     : erlang-mochiweb                                                     4/6
  Installing     : erlang-ibrowse                                                      5/6
  Installing     : couchdb                                                             6/6

Installed:
  couchdb.x86_64 0:0.11.2-2.el5

Dependency Installed:
  erlang.x86_64 0:R12B-5.10.el5                erlang-ibrowse.x86_64 0:2.1.0-1.el5
  erlang-mochiweb.x86_64 0:1.4.1-5.el5         erlang-oauth.x86_64 0:1.0.1-1.el5
  js.x86_64 0:1.70-8.el5

Complete!

あっさりインストールは完了します。CouchDBのdefault portは5984となります。
また、CouchDBにはWebサーバ機能も付加されている為、bindアドレスを変更します。
/etc/couchdb以下にCouchDBのiniファイルがありますので、必要に応じてbindアドレスとportを変更します。

[root@hoge couchdb]# pwd
/etc/couchdb

2. CouchDB起動
以下を実行し、CouchDBを起動します。option “-b”を付与することで、バックグラウンド実行となります。

[root@hoge ~]# couchdb
Apache CouchDB 0.11.2 (LogLevel=info) is starting.

=INFO REPORT==== 10-Aug-2011::01:20:31 ===
    warning: "TODO: max is currently unsupported"
    max: "2048"
Apache CouchDB has started. Time to relax.
[info] [<0.29.0>] Apache CouchDB has started on http://49.212.1.17:xxxx/

上記の”xxxx”には先ほど変更したportが入ります。
なお、CouchDBを止めたい時は$ couchdb -d で終了させます。
続いて、上記のURLにアクセスします。まず、curlで実行してみます。
JSON形式でレスポンスが返ってきます。また、今回のバージョンは0.11.2とわかります。

[shmachid@hoge ~]$ curl  http://49.212.1.17:xxxx/
{"couchdb":"Welcome","version":"0.11.2"}

ブラウザからアクセスしてみます。

3. 管理コンソール「Futon」
CouchDBには、管理コンソール「Futon」が用意されています。
先ほどのURLに”_utils”を付加し、ブラウザからアクセスします。

これでベースセットアップは完了です。

以上です。

CAP定理, BASEのまとめ

以前からCAP定理やBASEがイマイチ腹落ちしていなかったので、調べました。

1. ACID
まず、RDBMSのトランザクション処理におけるACID特性は以下である。

  1. Atomicity: 原子性
  2. トランザクションが実行されるか、全くされないかのどちらかである。

  3. Consistency: 一貫性
  4. データベースの関係制約を保証する。

  5. Isolation: 独立性
  6. トランザクション中に経過が他トランザクションから参照出来ない。隔離性があるということ。

  7. Durability: 永続性
  8. トランザクション完了後、データは失われない。耐障害性があるということ。

2. CAP定理
続いて、クラウド化(クラウドは分散システムと考える)した際はACID特性が保つのは非常に大変である。(無理ではない)
CAP定理では、C.A.Pの3つの内、同時に満たせるのは2つまでという主張。
Eric Brewer氏のCAP定理

  1. Consistency: 一貫性
  2. データ更新後の次アクセス時には、更新後データが読取可能である事。

  3. Availability: 可用性
  4. ユーザがアクセスした時はサービス利用可能である事。稼働率。

  5. Partition Tolerance: ネットワーク分断耐性
  6. 分散システムを構成する物理/仮想サーバのうち、1つが壊れてもサービスは継続可能である。

3つの内、2つを選択すると以下となる。

  • C + A: 一貫性と可用性を選択すると、分散処理が出来ない。  例: 単一サーバ
  • C + P: 一貫性とネットワーク分断耐性を選択すると、可用性が失われる。  例: 分散データベース
  • A + P: 可用性とネットワーク分断耐性を選択すると、一貫性が失われる。  例: DNS
  • クラウド環境ではデータ量やScalabilityの観点から分散処理が必要となる。
    よって、P: Partition Torerance を選択することとなる。
    では、残り1枠は C(一貫性), P(可用性)のどちらを選択するかであるが、
    Webではユーザがアクセスした時はサービスが利用可能であることが前提である為、
    基本的には可用性を選択する事になる。(個々の要件によって、選択する事)
    その場合、一貫性の取り扱いが問題となる。そこで出てくるのばBASEである。

    3. BASE
    ACID特性が個別のデータベースのトランザクションの特性であるのに対して、
    BASEはデータベース機能を含んだシステム全体の特性である。

    1. Basically Available
    2. 可用性が高く、常に利用可能である。

    3. Soft-State
    4. ステータスは厳密ではない。外部から送られる情報により変化する。

    5. Eventually Consistent
    6. 最終的には一貫性が保たれる。ある時点では更新されていないケースがある。

    4. まとめ
    クラウドではCAP定理のうち、A(可用性)とP(ネットワーク分断耐性)を選択する。
    C(一貫性)については、若干妥協して BASEのEventually Consistent を採用する。
    ある時点では、一貫性がない可能性があるが、最終的には一貫性が保つことが出来る。

    気になった点としては、企業システムにおいてはこの一貫性の妥協がどのように許容されるのかです。
    ここはもう少し調べることとします。

    なお、以下を参考に勉強させていただきました。
    Cloudの技術的特徴
    CAPのCとACIDのC

    postgreSQLアーキテクチャ メモ

    最近、初めてpostgreSQLをさわったので、アーキテクチャなど少し調べました。

    postgreSQLとその他のDBMSとの大きな違いは追記型である点です。
    updateを行う際に、オリジナル行に対して更新をするのではなく、
    新規行をinsertとオリジナル行に無効化フラグを付加します。
    よって、データベース内には複数versionのデータを保持することになります。
    この機能をMVCC(Multi Version Concurrency Control)と呼ばれています。
    更新トランザクションが発生する毎にレコードのversionが増える為、大量トランザクション発生するシステムの場合、
    データ量が膨大になります。
    そこで、vacuum機能で、無効化フラグのついたレコードをお掃除します。

    vacuumには以下の2種類があります。

    1. concurrent vacuum
    2. 無効化フラグが付加されたレコードを再利用可能とする。排他ロックは行われない。

    3. vacuum full
    4. 従来からあるvacuumで排他ロックが発生する。
       → 定期的にサービス停止が必要

    以下はメモです。
    ■ postgreSQL起動
    起動は$pg_ctl start で行います。 (停止、再起動はそれぞれstop, restart)

    [postgres@hoge data]$ pg_ctl -w start
    waiting for postmaster to start....LOG:  database system was shut down at 2011-06-22 13:36:38 JST
    LOG:  checkpoint record is at 0/ACB3E0
    LOG:  redo record is at 0/ACB3E0; undo record is at 0/0; shutdown TRUE
    LOG:  next transaction ID: 576; next OID: 17231
    LOG:  database system is ready
     done
    postmaster started
    

    起動後、プロセスを確認します。

    [postgres@hoge data]$ ps aux | grep postgres
    postgres 26561  0.0  0.0  92552   360 ?        S    12:26   0:00 /usr/local/pgsql/bin/postmaster
    postgres 26563  0.0  0.0  92552   340 ?        S    12:26   0:00 postgres: writer process
    postgres 26564  0.0  0.0  82820   180 ?        S    12:26   0:00 postgres: stats buffer process
    postgres 26565  0.0  0.0  81948   188 ?        S    12:26   0:00 postgres: stats collector process
    

    ■ 設定ファイル
    MySQLで言うmy.confに相当する設定ファイルとして、postgres.confがあります。
    私の場合は /usr/local/data/postgres.conf にあります。(以下、$PGDATA)

    [postgres@hoge data]$ ls -al
    合計 64
    drwx------ 8 postgres postgres  4096  6月 22 12:26 .
    drwxr-xr-x 9 postgres root      4096  6月 21 13:19 ..
    -rw------- 1 postgres postgres     4  6月 21 13:19 PG_VERSION
    drwx------ 5 postgres postgres  4096  6月 21 13:21 base
    drwx------ 2 postgres postgres  4096  6月 22 12:26 global
    drwx------ 2 postgres postgres  4096  6月 21 13:19 pg_clog
    -rw------- 1 postgres postgres  3406  6月 21 13:19 pg_hba.conf
    -rw------- 1 postgres postgres  1460  6月 21 13:19 pg_ident.conf
    drwx------ 2 postgres postgres  4096  6月 21 13:19 pg_subtrans
    drwx------ 2 postgres postgres  4096  6月 21 13:19 pg_tblspc
    drwx------ 3 postgres postgres  4096  6月 21 13:19 pg_xlog
    -rw------- 1 postgres postgres 11030  6月 22 12:23 postgresql.conf
    -rw------- 1 postgres postgres    30  6月 22 12:26 postmaster.opts
    -rw------- 1 postgres postgres    48  6月 22 12:26 postmaster.pid
    

    ■ プロセスファイル
    postgreSQLを起動すると、$PGDATA/postmaster.pidが生成されます。
    pidファイルの中身は以下のようになっています。

    26561
    /usr/local/pgsql/data
      5432001   2326529
    

    1行目:”26561″はプロセスID
    2行目:postgreSQLのDATA格納ディレクトリ
    3行目:port番号 (後ろのほうは分からなかった)

    ■ リスナー
    postgreSQLを起動すると、フロントエンドとバックエンド間の通信を行う為のリスナーが生成されます。
    リスナーは /tmp/.s.PGSQL.5432 になります。

    [postgres@hoge data]$ ls -al /tmp/.s.PGSQL.5432*
    srwxrwxrwx 1 postgres postgres  0  6月 22 13:36 /tmp/.s.PGSQL.5432
    -rw------- 1 postgres postgres 28  6月 22 13:36 /tmp/.s.PGSQL.5432.lock
    

    “5432”はport番号で、postgreSQLのデフォルトportは5432となります。
    変更したい場合はpostgres.confで変更すればOKです。(標準ではコメントアウトされている)

    ■ template database
    コンソールから$psql -l を実行すると、作成されているデータベースが確認出来ます。

    [postgres@hoge data]$ psql -l
            List of databases
        Name    |  Owner   | Encoding
    ------------+----------+----------
     shmachidDB | postgres | UNICODE
     template0  | postgres | UNICODE
     template1  | postgres | UNICODE
    (3 rows)
    

    template0, template1というデータベースは、標準機能として提供しているデータベースで、
    ユーザが新規データベースを作成する際に内部でコピーするテンプレートデータベースとなります。
    データベースの実体は、$PGDATA/base以下にあり、ファイル名は数値となります。

    [postgres@hoge base]$ ls -al
    合計 20
    drwx------ 5 postgres postgres 4096  6月 21 13:21 .
    drwx------ 8 postgres postgres 4096  6月 22 13:36 ..
    drwx------ 2 postgres postgres 4096  6月 21 13:19 1
    drwx------ 2 postgres postgres 4096  6月 21 13:19 17229
    drwx------ 2 postgres postgres 4096  6月 21 13:21 17230
    

    ■ 複数起動
    既にpostgreSQLが起動している状況で、もう1つpostgreSQLを立ち上げてみます。

    [postgres@hoge base]$ pg_ctl start
    pg_ctl: another postmaster may be running; trying to start postmaster anyway
    FATAL:  lock file "/usr/local/pgsql/data/postmaster.pid" already exists
    HINT:  Is another postmaster (PID 26808) running in data directory "/usr/local/pgsql/data"?
    pg_ctl: could not start postmaster
    Examine the log output.
    

    既に$PGDATA/postmaster.pidが存在する為、怒られます。
    そこで、postmaster.pidを別名に変更して、再度起動します。

    [postgres@hoge data]$ pg_ctl start
    postmaster starting
    [postgres@hoge data]$ LOG:  could not bind IPv4 socket: Address already in use
    HINT:  Is another postmaster already running on port 5432? If not, wait a few seconds and retry.
    WARNING:  could not create listen socket for "localhost"
    FATAL:  lock file "/tmp/.s.PGSQL.5432.lock" already exists
    HINT:  Is another postmaster (PID 26808) using socket file "/tmp/.s.PGSQL.5432"?
    

    今度はリスナーがあると怒られます。
    では、次にpostgresql.confでport番号を別指定(今回は11111にします)し、再度起動します。(portは1…65535)

    [postgres@hoge data]$ pg_ctl start
    postmaster starting
    [postgres@hoge data]$ LOG:  database system was interrupted at 2011-06-22 13:36:47 JST
    LOG:  checkpoint record is at 0/ACB3E0
    LOG:  redo record is at 0/ACB3E0; undo record is at 0/0; shutdown TRUE
    LOG:  next transaction ID: 576; next OID: 17231
    LOG:  database system was not properly shut down; automatic recovery in progress
    LOG:  record with zero length at 0/ACB428
    LOG:  redo is not required
    LOG:  database system is ready
    

    立ち上がりましたので、リスナーとプロセスを確認します。

    [postgres@hoge data]$ ls -al /tmp/.s.PGSQL.*
    srwxrwxrwx 1 postgres postgres  0  6月 22 13:51 /tmp/.s.PGSQL.11111
    -rw------- 1 postgres postgres 28  6月 22 13:51 /tmp/.s.PGSQL.11111.lock
    srwxrwxrwx 1 postgres postgres  0  6月 22 13:47 /tmp/.s.PGSQL.5432
    -rw------- 1 postgres postgres 28  6月 22 13:47 /tmp/.s.PGSQL.5432.lock
    [postgres@hoge data]$ ps aux | grep postgres
    postgres 26808  0.0  0.2  92552  1320 pts/0    S    13:36   0:00 /usr/local/pgsql/bin/postmaster
    postgres 26810  0.0  0.1  92552   632 pts/0    S    13:36   0:00 postgres: writer process
    postgres 26811  0.0  0.0  82820   396 pts/0    S    13:36   0:00 postgres: stats buffer process
    postgres 26812  0.0  0.0  81948   452 pts/0    S    13:36   0:00 postgres: stats collector process
    postgres 26863  0.0  0.6  92552  3132 pts/0    S    13:51   0:00 /usr/local/pgsql/bin/postmaster
    postgres 26865  0.0  0.1  92552   992 pts/0    S    13:51   0:00 postgres: writer process
    postgres 26866  0.0  0.1  82820   704 pts/0    S    13:51   0:00 postgres: stats buffer process
    postgres 26867  0.0  0.1  81948   832 pts/0    S    13:51   0:00 postgres: stats collector process
    

    2つのport分(5432, 11111)のリスナーが生成されています。
    プロセスも2つ分起動しています。

    よって、今回は最初に起動していたpostmaster.pidを別名にしていますので、2つ立ち上がった事になりませんが、
    $PGDATAを複数用意して、別portで起動すれば複数起動することが出来ると思われます。

    あと今回はゴミプロセスが残っていますので、killしてください。

    ウェブオペレーション(非リレーショナルデータベース)

    その時の気分で本を変えてしまってますが、ウェブオペレーション ―サイト運用管理の実践テクニック
    15章 非リレーショナルデータベースを読んだメモを残します。
    イマイチNoSQLが自分の中に落ち切っていないので、この章から確認しました。

    SQLデータベースのスケーラビリティ
    SQLデータベースのスケーラビリティは、4つにまとめめられる。

    1. キャッシュの最適化
    2.  読み取り負荷の軽減には非常に役立つ。
       但し、アプリケーションは複雑になり、軽減可能な負荷に限界がある。

    3. クエリの最適化
    4.  クエリの最適化も同様に限界がある

    5. 新しいハードウェアの購入
    6.  非常に効果的。問題は2つ。値段が高い。最も良いハードウェアを購入するとその後の手立てがなくなる。

    7. シャーディング
    8.  最後はシャーディング。シャーディングに適しているのは、ユーザID等から取得先のデータベースを
       振り分けるような場合(西海岸と東海岸とか)。だけど、ちょっと面倒。

    どうすれば簡単にスケール出来るのか? どうすればデータを近くに保存出来るのか? どうすればアプリケーションを再構築しなくて済むか? といった悩みから生まれたのがNoSQLである。

    NoSQLデータベースの概要
    NoSQLは以下の5つに分類出来る

    1. キーバリュー型
    2. キーバリュー型は昔からある。memcachedで再注目された。
      非常にシンプルでキーを渡せばバリューが返る。

    3. データ構造型
    4. キーバリュー型とほとんど同じ。バリューをリスト・セット・ハッシュ等のデータ構造で格納する。
      リストだとpush, popが出来たりとアプリケーションのデータ構造と同様に操作出来る。
      Redis

    5. グラフ型
    6. データ構造型のデータ構造がグラフになっただけ。データはキーバリューではなく、
      ノードとエッジで格納される。

    7. ドキュメント指向型
    8. キーバリュー型に似ているが、バリューがドキュメントとなる。
      ドキュメントはJSONオブジェクトで格納されている。
      このタイプは、データ構造が事前に分からない場合に有用である。
      CouchDB
      MongoDB

    9. 高分散型
    10. 複数の形式があるが、共通しているのは複数ノードへのデプロイに最適化されている事。
      分散システムでキャパシティを増やすには、新しいノードをクラスタに追加すれば良い。
      1つのノードに障害があっても データが失われることなく、
      キャパシティが損なわれるだけである。一貫性を犠牲にして、可用性と分割耐性を保証するものが多い。
      なぜ、高分散型を使用するか?他に選択肢がないから。
      SQLベースのDBでは、大量のデータを扱えないが、高分散型では可能。
      但し、面倒。
      Cassandra
      HBase
      Riak

    例で挙げた各データベースについては、後日調べる事とする。


    MySQL Expert at Yahoo!

    4月にMySQL Conference & Expoが開催されたので、その時のスライドをチェックしてみてると、
    4年前にYahoo! incでパフォーマンスチューニングで相談させてもらったJayさんを発見した。
    Websiteもあった。

    あの相談をさせてもらった頃から、自分自身が少しは成長していると良いのですが。。
    しかし、スライドがkeynoteで見れない・・・。学校の人に変換してもらおう。

    当時、現場で使える MySQL (DB Magazine SELECTION)
    がバイブルでした。