ichuan.net

自信打不死的心态活到老

计划.IN 开源

如同之前承诺的那样,现在将这个项目开源了,欢迎 fork:

https://github.com/ichuan/jihua

jihua.in 这个网站会一直运行,我本身就一直在用。

有个 mm 图在 doc/design.mm,是那晚简单做的一个设计。其他介绍就不写了,都在 github 那里。

计划.IN 上线

最近一周都没写博客,因为我在做一个网站。现在基本成型了,于是放出来,欢迎使用。

计划.IN —— 简单有效的工作计划表

从上周五买域名开始,到刚才把网站部署上去,总共花去了我 10 天的“空闲”时间。平时要上班,哪有那么多空闲时间啊。嗯,我基本都是在熬夜写代码的。10 天里熬夜了几天都记不清了,每次都是最早凌晨 5 点睡,那时睡的话要设 4 个间隔 10 分钟的闹钟,以防上班迟到。期间有天要出差,早上 7 点 50 的火车,那天就没睡,在火车上补的觉。

这么疯狂的原因一个是这是我喜欢的事,自然有无穷的动力去做;另一个也是做这个网站的初衷:我想确信自己还没老去,能力还没消失,我还不是个废人。

这期间又开始喝咖啡了。有些熬夜的晚上,抬起头会有奇异的感觉。后来也看到某百度员工猝死云云,甚惊恐,怕自己哪个晚上也会不小心驾鹤西去,一命呜呼。自毕业后我已有好久没通宵过了,之前玩游戏时偶尔通宵一次也会累个半死,第二天下午睡醒后有世界末日般的感觉。这次还好。

说正题。计划.IN(我这么叫它)其实就是个 todo list + 备忘录工具,具体的介绍可以看帮助页面,刚写的,还热乎着。开发过程可以简单概括为:买域名;用 freemind 列需求和设计;用 mockups 画原型图;实现 ui;实现后台逻辑。

前端 ui 实现占用了我 80% 的开发时间。因为我对细节有洁癖,而且自认有些审美能力,所以一直在细调。logo 是照着 twitter 的用 ps 画的;首页的预览图也是截图后用 ps 旋转得到的。js 代码局部重构了好几次,因为我要的既能运作又看起来漂亮的代码。为了想实现一种动画效果,把 css3 的 transform 尝试了遍,最后以失败告终。前端用的 twitter 的 bootstrap css 框架和核武器 backbone.js MVC 框架,后者的源码也几乎被我看完了。

后台逻辑实现比较简单,主要是一个 RESTful 接口。这个项目里我写的 python 代码远没有写的 js 代码多。现在发现 django 太庞大了,这次又学到很多以前没用过的功能。

因为比较关心数据安全性,于是申请了 StartSSL 的免费 SSL 证书,折腾一会给装上了。

促成我开始做这个站的最初原因是徐东同学说他有 todo list 的需求,然后我想起了我荒废很久的 MyPDC2.0 计划,其中就包含一个类似 计划.IN 的记事功能。于是先把这个实现了,要等想法都成熟才开始干是不明智的。

还有些没实现的功能,但我等不下去了,先让功能可用的它上线吧,我得休息下了。

djblog开源

刚把 djblog——也就是我这个blog用的程序——放到 github 上去了:https://github.com/ichuan/djblog

写这个程序没花多少时间,主要是方便自己用,功能也很少,但够用。

下面贴的是 README

介绍

一个基于 django 开发的 blog 程序,特性包括:

  1. HTML5
  2. 手持设备访问优化
  3. Disqus 评论系统集成
  4. Markdown 语法写作
  5. 标签
  6. 单页面
  7. 友情链接
  8. Google Analytics 集成
  9. 主题
  10. Google 自定义搜索

依赖

  1. markdown: https://github.com/waylan/Python-Markdown/
  2. django >= 1.3

安装步骤

  1. 创建数据库,例如 mysql 数据库:$ mysql -u root -proot -e 'create database blog'
  2. 拷贝 local_settings.default.pylocal_settings.py,修改里面的数据库配置。还有其他配置可以改
  3. 执行 python manage.py syncdb 同步数据库
  4. 执行 python manage.py runserver 0.0.0.0:8000 启动临时服务器
  5. 浏览器访问 http://localhost:8000,后台地址是 http://localhost:8000/admin/,口令在第 3 步时创建

自定义主题

主题放在 templates/ 目录下,一个目录是一个主题,classic 为默认主题,可参考这个制作新主题。

用uWSGI替代fastcgi部署django应用

今日有同事推荐我用 uWSGI 来部署 django 应用,因为它比 fastcgi 方式快很多。刚才实验完毕,现在这个blog和 911.im 已经使用上 uWSGI 了。

对比测试

我用的 webbench 来测试 fastcgi 和 uwsgi 两种方式的效率,下面是换 uwsgi 之前的数据:

$ webbench -c 500 -t 30 http://ichuan.net/archives/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://ichuan.net/archives/
500 clients, running 30 sec.

Speed=12220 pages/min, 1245829 bytes/sec.
Requests: 6110 susceed, 0 failed.

换 uwsgi 后:

$ webbench -c 500 -t 30 http://ichuan.net/archives/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://ichuan.net/archives/
500 clients, running 30 sec.

Speed=42470 pages/min, 2778475 bytes/sec.
Requests: 21235 susceed, 0 failed.

可以看到换 uwsgi 后能处理的页面数是换之前的 3.5 倍左右。这个数据在我本地虚拟机上是 30 倍。

部署过程

首先下载编译 uwsgi:http://projects.unbit.it/downloads/uwsgi-0.9.9.1.tar.gz,我是 ubuntu 系统,需要额外装个 libxml2-dev 库:sudo apt-get install libxml2-dev

编译完后将得到的 uwsgi 复制到系统目录:sudo cp uwsgi /usr/sbin/

启动 uwsgi:

uwsgi -s /tmp/uwsgi.sock -C -M -p 4 -t 30 --limit-as 128 -R 10000 --vhost -d /tmp/uwsgi.log --pidfile /tmp/uwsgi.pid --pythonpath /var/www

表示用 unix socket 方式执行 uwsgi,-C 表示将 /tmp/uwsgi.sock 文件权限改成 666 以便 nginx 可以读取,-M 表示启动管理进程,-p 4 表示预生成 4 个 worker 子进程,-t 30 是 cgi 程序超时,--limit-as 128 表示限制内存最大 128M,-R 10000 表示每个 worker 处理的最大请求数,--vhost 表示启用虚拟服务器,-d /tmp/uwsgi.log 表示以守护进程方式启动,指定日志文件。

这个命令可以放入 /etc/rc.local 作为开机自启动。

这样启动的 uwsgi 可以被多网站共用,nginx 的 server 块配置如下:

location / {
    uwsgi_pass  unix:///tmp/uwsgi.sock;
    uwsgi_param UWSGI_CHDIR  /var/www/djblog;
    uwsgi_param UWSGI_SCRIPT wsgi_app;
    include     uwsgi_params;
}

上面的配置的前提是,你的 django 工程在 /var/www/djblog,并且在该目录下有个 wsgi_app.py 文件。文件内容如下:

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'djblog.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

如此配置好后,重启 nginx 就可以了。

如果要多加一个网站,只需在 nginx 配置中新加个 server 块,改变下 UWSGI_CHDIR 配置即可。

如果要让 uwsgi 重新载入,可以执行:

kill -SIGHUP `cat /tmp/uwsgi.pid`

如果要让停止 uwsgi,可以给它的 master 进程发送 SIGINT 信号:

kill -SIGINT `cat /tmp/uwsgi.pid`

uwsgi 的更多配置在此

911.im 短网址服务

虽然现在短网址服务已经泛滥了,但看到别人都有自己私人搭建的短网址服务,很是羡慕,于是准备自己搞个。

前段日子我爬了下3位数字字母的.im后缀域名,结果大吃一惊,有大量.im域名嗷嗷待注。我从结果里选了十来个,拿去问阿东,说我想做一个短网址网站,哪个域名好点?我向来是相信阿东的眼光的,这次他帮我选了 911.im 这个域名,说是 911 人尽皆知。

前两天我刚把人生中第一张visa信用卡申请到了,用它买了vps和域名。发现用信用卡在境外网站买东西真是方便,不用登录网银,只需输个密码就完成交易了。

昨晚上开始想一个短域名服务的架构。刚开始想用 redis 做存储,因为它速度快,而且天生就是为短网址这种类型网站用的。后来因为 redis 的数据持久化不太理想,应该只适合做缓存层,我怕丢数据,就放弃了 redis,选择了熟悉的 mysql。关于语言选型,最初想到这个网站功能会很简单,甚至不需要会话这一层,可以用 web.py 来做。考虑到最终部署,我 vps 上已经装了 flup,于是查了半天 nginx+flup+web.py 的配置,无果。后来想想,就这一个小网站,没必要这么认真,就选用熟悉的 django 开发了。

最后一个问题是短网址生成算法。这个我之前没看过其他短网址程序,不清楚他们是怎么做的。最初我想每个 url 取个 md5,md5 再映射到一个小点的字串。用 md5 主要是考虑索引。后来想想,可以这么做:按最简单的,每个 url 插数据库后有个唯一数字 id,这个 id 是 10 进制的,我只要将这个 id 映射到 另外一个进制(比如[0-9a-zA-Z]的62进制)就可以了。后来我先实现了一个 62 进制和 10 进制间相互转换的算法,再做其他的就很简单了。在这里分享下我的 62 进制算法:

chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

def decto62(dec):
    '''十进制转62进制,输入数字,返回字串'''
    ret = []
    while True:
        dec, a = divmod(dec, 62)
        ret.append(chars[a])
        if dec == 0:
            break
    ret.reverse()
    return ''.join(ret)

def decfrom62(num):
    '''62进制转十进制'''
    assert re.match(r'^[0-9a-zA-Z]+$', num)
    num = list(num)
    num.reverse()
    return reduce(lambda x,y:x+chars.find(num[y])*(62**y), range(len(num)), 0)

最后还需要个 favicon 吧。我简单用 mspaint 画了个 png 图,再转 ico 格式后就可以了。

这个短网址服务 911.im 已经上线,欢迎使用。