ユーザに提供するのは、機能やサービスではなく
''価値'''を提供することをということを念頭に
下記を3原則とし「ものづくり」をしているとのことです。
(料理も作ることなので、つくるつながりはよいと思いました。)

1, 無限実行
事前にリリース予定などの告知はしない。見えないものを伝えるのは困難だし誤解を生じやすくユーザを混乱させる。事前告知の効果もはっきりしないので、しないほうがよい

2, 無限語化
HelpやFAQなどは準備しない。ユーザがマニュアルやFAQを必要とするサイトはどこかに問題があるので、それを解決するほうが先。ユーザが2秒で理解できないものは問題がある。

3, サービスに値段をつける
Webサービスは無料で提供しているものが多いが、無料であることがサービス提供側の言い訳になる恐れがあり、クオリティが低下する。サービスに予め値段をつけることで、そういう状況を回避できる。
(http://d.hatena.ne.jp/atyks/20090201/1233421922の下に書いてあります)

おもしろい考え方だと思いました。

下記がコードサンプル、create_indexは忘れずに。

#!/usr/bin/env python

import binascii
import struct
import datetime
import hashlib
rom pymongo import Connection
from time import sleep

reconnect_times = 10
reconnect_counter = 0
dbsetting = {'dbhost':'localhost','dbname':'shorturldb'}

def con(**kwargs):

    global reconnect_counter
    global reconnect_times

    if 'host' not in kwargs:
        kwargs['host'] = dbsetting['dbhost']
    dbname = dbsetting['dbname']

    try:
        _con = Connection(**kwargs)
        return eval('_con.'+dbname)

    except Exception, e:

        sleep(0.1)

        print('Fail to excute %s [%s]' % ( __name__, e))
        if reconnect_counter == reconnect_times:
            reconnect_counter = reconnect_counter + 1
            con(**kwargs)


def save_hash(url, length=5):
    base32 = [
            'a', 'b', 'c', 'd', 'e',
            'f', 'g', 'h', 'i', 'j',
            'k', 'l', 'm', 'n', 'o',
            'p', 'q', 'r', 's', 't',
            'u', 'v', 'w', 'x', 'y','z',
            'A', 'B', 'C', 'D', 'E',
            'F', 'G', 'H', 'I', 'J',
            'K', 'L', 'M', 'N', 'O',
            'P', 'Q', 'R', 'S', 'T',
            'U', 'V', 'W', 'X', 'Y','Z',
            '0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9'
            ]
    hex = hashlib.md5(url).hexdigest()
    hexLen = len(hex)
    subHexLen = hexLen/8
    output = []
    mydb = con()
    for i in range(0, subHexLen):
        subHex = hex[i*8:(i*8)+8]
        num = 0x3FFFFFFF & int('0x'+subHex, 0)
        hash = '';
        for j in range(0,length):
            val = 0x0000003D & num
            hash = hash + base32[val]
            num = num >> length
        r = mydb.shorturl.find_one({'i':{'$in':[hash,url]}})
        if not r:
            insert = {'i':[hash,url],'p':datetime.datetime.utcnow()}
            mydb.shorturl.insert(insert)
            return hash

        elif r and r['i'][1] == url:
            return r['i'][0]
    return None

def get_hash(url):
    mydb = con()
    r = mydb.shorturl.find_one({'i':{'$in':[url]}})
    if r:
        return r['i'][0]
    return None

from pymongo import Connection
from time import sleep

reconnect_times = 10
reconnect_counter = 0

def con(**kwargs):

    global reconnect_counter
    global reconnect_times

    if 'host' not in kwargs:
        kwargs['host'] = settings.application['dbhost']
    dbname = settings.application['dbname']

    try:
        _con = Connection(**kwargs)
        return eval('_con.'+dbname)

    except Exception, e:

        sleep(0.1)

        print('Fail to excute %s [%s]' % ( __name__, e))
        if reconnect_counter == reconnect_times:
            reconnect_counter = reconnect_counter + 1
            con(**kwargs)

==
mongodb 1.5.* は若干バギーで、コネクトエラーがたまにでる。(でるらしいので、pymongoのコネクトラッパーらしきものもあるが)自前で、対応
べーすハンドラーに
class BaseHandler(tornado.web.RequestHandler):
    def get_user_locale(self):
        return tornado.locale.get(*[self.get_cookie('lang', None)])

get_user_locale を上記のように指定すると、
cookie lang に locale の指定があれば、locale テーブルを差し替えられる。

== po file 作成サンプルシェル ==

BASE=.
DOMAINNAME='main'
FILELIST=$BASE/templates
POFILEDIR=$BASE/po
XGETTEXT=`which xgettext`

find $FILELIST -type f > .tmp
touch $POFILEDIR/$DOMAINNAME.pot
$XGETTEXT -j -n -o $POFILEDIR/$DOMAINNAME.pot --keyword=_:1,2 --language=Python -f .tmp
rm .tmp

#for x in "af_ZA" "ar_AR" "bg_BG" "bn_IN" "bs_BA" "ca_ES" "cs_CZ" "cy_GB" "da_DK" "de_DE" "el_GR" "en_GB" "en_US" "es_ES" "es_LA" "et_EE" "eu_ES" "fa_IR" "fi_FI" "fr_CA" "fr_FR" "ga_IE" "gl_ES" "he_IL" "hi_IN" "hr_HR" "hu_HU" "id_ID" "is_IS" "it_IT" "ja_JP" "ko_KR" "lt_LT" "lv_LV" "mk_MK" "ml_IN" "ms_MY" "nb_NO" "nl_NL" "nn_NO" "pa_IN" "pl_PL" "pt_BR" "pt_PT" "ro_RO" "ru_RU" "sk_SK" "sl_SI" "sq_AL" "sr_RS" "sv_SE" "sw_KE" "ta_IN" "te_IN" "th_TH" "tl_PH" "tr_TR" "uk_UA" "vi_VN" "zh_CN" "zh_HK" "zh_TW";
for x in "ja_JP";
do

LOCALE=$x
POPATH=$POFILEDIR/$LOCALE.po

test ! -f $POPATH && touch $POPATH

nkf -wLu $POPATH > $POFILEDIR/$LOCALE.old.po
msgmerge -v $POFILEDIR/$LOCALE.old.po $POFILEDIR/$DOMAINNAME.pot -o $POPATH
done


mongosが安定してきたので一安心。

==
ディレクトリ作る(ec2の場合とりあえず、/mnt以下へ)
==

$ sudo mkdir /mnt/data/shards
$ sudo mkdir /mnt/data/shards/0 /mnt/data/shards/1 /mnt/data/shards/2
$ sudo mkdir /mnt/data/shards/config
$ sudo chown mongodb:mongodb -R /mnt/data/shards

==
mongosの設定
==

$ sudo -u mongodb -H mongo
> use admin
> db.runCommand( {addshard : "localhost:27020", allowLocal : true} );
> db.runCommand( {addshard : "localhost:27021", allowLocal : true} );
> db.runCommand( {addshard : "localhost:27022", allowLocal : true} );

# Listing shards
> db.runCommand( { listshards : 1 } );

#Enabling Sharding on a Database
> db.runCommand( { enablesharding : "dbname" } );

#Sharding a Collection
> db.runCommand( { shardcollection : "dbname.collection_name" , key : { "_id" : 1 } , unique : true } );

==
簡易スタートスクリプト
==

#!/bin/bash

sudo -u mongodb -H mongod \
--configsvr \
--dbpath /mnt/data/shards/config \
--fork \
--port 27019 \
--logpath /var/log/mongodb/mongodb.config.log  &

sleep 2

sudo mongos \
-vvv \
--port 27017 \
--fork \
--configdb localhost:27019 \
--logpath /var/log/mongodb/mongos.log  &

sleep 2

sudo -u mongodb -H mongod \
--shardsvr \
--port 27020 \
--fork \
--dbpath /mnt/data/shards/0 \
--logpath /var/log/mongodb/mongodb.shard.log &

sudo -u mongodb -H mongod \
--shardsvr \
--port 27021 \
--fork \
--dbpath /mnt/data/shards/1 \
--logpath /var/log/mongodb/mongodb.shard.log &

sudo -u mongodb -H mongod \
--shardsvr \
--port 27022 \
--fork \
--dbpath /mnt/data/shards/2 \
--logpath /var/log/mongodb/mongodb.shard.log  &

print '-------------------------------------'
ps -o pid,command ax | grep mongos | grep -v grep |cut -d' ' -f1
print '-------------------------------------'

ps -o pid,command ax | grep mongos | grep -v grep |cut -d' ' -f1 > /tmp/mongo.pid

久々に設定、

$ sudo apt-get install fetchmail

後、

$ vi $HOME/.fetchmailrc

==中身==

poll imap.gmail.com proto imap port 993
    user "アカウント名@gmail.com" password "パスワード"
    keep
    ssl
    mda "/usr/bin/procmail"

========

$ chmod 600 .fetchmailrc

そして、

$ sudo apt-get install procmail

後、

$ vi .procmailrc

==中身==

PATH=$HOME/bin:/usr/bin:/usr/local/bin
MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/inbox/.
LOGFILE=$MAILDIR/procmail.log
LOCKFILE=$HOME/.lockmail

========

$ fetchmail -v

これで定期的にメールを取得して、メールを軸に何らかの処理可能。

unicode should be encoded before parts not body.

<code>

def _signature(self, args):
        parts = ["%s=%s" % (n, args[n].encode("utf-8") if isinstance(args[n], unicode) else args[n]) for n in sorted(args.keys())]
        body = "".join(parts) + self.settings["facebook_secret"]
        return hashlib.md5(body).hexdigest()

</code>
2 servers results

Web Sever: Nginx 0.7* + Tornado 0.2
                   using nginx 5 load balancers
                  worker processes 5
                  worker connections 1024

DB Server: mongodb 1.5.1 shards

====
$ ab -n 10000 -c 25 http://****.***/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking ****.*** (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        TornadoServer/0.1
Server Hostname:        ****.***
Server Port:            80

Document Path:          /
Document Length:        4259 bytes

Concurrency Level:      25
Time taken for tests:   139.086 seconds
Complete requests:      10000
Failed requests:        1469
   (Connect: 0, Receive: 0, Length: 1469, Exceptions: 0)
Write errors:           0
Non-2xx responses:      1469
Total transferred:      38561669 bytes
HTML transferred:       36470146 bytes
Requests per second:    71.90 [#/sec] (mean)
Time per request:       347.716 [ms] (mean)
Time per request:       13.909 [ms] (mean, across all concurrent requests)
Transfer rate:          270.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      106  108  42.5    107    3106
Processing:   108  239 221.4    200    3539
Waiting:      108  239 221.3    200    3539
Total:        214  347 225.2    307    3646

Percentage of the requests served within a certain time (ms)
  50%    307
  66%    356
  75%    392
  80%    419
  90%    482
  95%    530
  98%    602
  99%    664
 100%   3646 (longest request)

==
mongodbが2回ほど、open fileを振り切って、connectionエラー、 ulimitをマックスまであげるが同じ。
なので、monitを使って、can not open fileになったら、サーバーリスタートで対応。
KeyRemap4MacBook インストール
system pref -> For Japanese -> Remap Space Key -> Shift+Space to KANNA/EISUU

command+spaceでの変換になれていないので、だいぶ楽になった。



xcode  と  mac port をインストール

そして

$ sudo port install boost pcre
$
sudo port install spidermonkey
$ sudo port mongo

# ついでにpymongoも
$ sudo easy_install pymongo

参照: mongodb
http://www.mongodb.org/display/DOCS/Building+for+OS+X?showComments=true&showCommentArea=true

tornadoも同じ、(xcodeを入れてコンパイル環境を用意する)

で、
$ sudo easy_install setuptools pycurl==7.16.2.1 simplejson
$ git cloan git://github.com/facebook/tornado.git
$ cd tornado
$ python setup.py build
$ sudo python setup.py install

最近のコメント

アイテム

  • DSC_0016_small.jpg
  • Logitec 無線LANルータ  MicroRouter  54Mbps  11bg LAN-PWGR.jpg
  • stock.jpg
  • 31rmjKykfYL._SL500_AA280_.jpg
  • P6010075.JPG
  • P5290075.JPG
  • P5290074.JPG
  • P5290060.JPG
  • P5290070.JPG
  • P5290069.JPG

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。