龍昌博客

从Pythoner转向Rubist

Vagrant使用笔记

| Comments

Vgrant是一个基于 Ruby 使用 Virtualbox 进行创建和部署虚拟化环境的工具。 类似的工具之前有使用过 Docker。就我个人而言这两款工具之间,Docker是轻量级的VM, 因此性能应该会比较好,但是只能在64位的系统下使用。 而 Vgrant 是使用 Virtualbox 进行虚拟化,因此性能上不及 Docker, 不过它可以在32/64位的 Linux、Windows 等系统上运行。

我觉得 Vgrant 比较适合用于在开发环境中使用,而 Docker 比较适合用于生产环境。

安装

首先安装 virtualbox,然后再安装 Vgrant。

1.通过源代码安装

1
2
3
4
git clone https://github.com/mitchellh/vagrant
cd vagrant
bundle install
rake install

2.通过安装包安装
根据情况选择下载对应的安装包: http://www.vagrantup.com/downloads.html

注意:如果是 Windows 系统,可能还需要将 Vgrant 的路径添加到环境变量中,以便使用 vgrant 命令。

使用

Vagrant 的使用方法也很简单,基本如下:

1
2
3
4
5
6
7
8
# 这里我先添加一个 ArchLinux 的镜像
vagrant box add archlinux http://vagrant.srijn.net/archlinux-x64-2014-01-07.box
# 进行初始化
vagrant init archlinux
# 运行虚拟机
vagrant up
# 如果需要进行ssh连接到虚拟机中进行一些操作,可以执行该命令
vagrant ssh

其他的一些命令:

1
2
3
4
# 关闭虚拟机
vagrant halt
# 删除创建的虚拟机
vagrant destroy

vagrant的一些镜像: http://www.vagrantbox.es/

Redis集群配置实例

| Comments

通过配置 redis 的主从集群可将请求的负荷分散到多台服务器上。

redis 的集群配置比较简单,以下是一个例子。 假设有如下三台主机:

  • 172.17.0.11 (主)
  • 172.17.0.12 (从)
  • 172.17.0.13 (从)

在从服务器上添加如下配置:

1
slaveof 172.17.0.11 6379

如果主服务器设置了认证密码,那么还需要再添加一条配置:

1
masterauth <password>

然后分别启动三台服务器的 redis 服务即可。

接下来连接主服务器添加一些数据测试一下。

1
2
3
$ redis-cli -h 172.17.0.11
172.17.0.11:6379> set foo1 bar1
OK

然后再连接到从服务器查询结果。

1
2
3
$ redis-cli -h 172.17.0.12
172.17.0.12:6379> get foo1
"bar1"

这时发现数据已经同步过来了。

注意:从服务器默认是只读的。如果需要设置为可写,可将 slave-read-only 设置项的值设为 no 即可。

Mongodb分片配置实例

| Comments

数据分片即是从一个集合中选择一个片键(shard key)作为数据拆分的依据,原理与索引类似,然后将集合的数据拆分并保存到不同的服务器上。 以下通过一个例子来介绍一下Mongodb的分片配置。

有四台主机:

  • 172.17.0.6 (配置服务器)
  • 172.17.0.7 (mongos)
  • 172.17.0.8 (片服务器)
  • 172.17.0.9 (片服务器)

1.在 172.17.0.6 上启动 mongod 服务作为配置服务器;
修改配置,使其作为一个配置服务器,默认监听 27019 端口。

1
configsvr = true

启动服务 $ service mongodb start

2.在 172.17.0.7 上启动 mongos 服务作为路由服务;
建立mongos进程。(可以有多台配置服务器),用法如下:

1
$ mongos --configdb <config server hostnames>[,<config server hostnames>]

例如: $ mongos --configdb 172.17.0.6:27019

注意:在同一个分片集群中的每个 mongos 必须使用相同的 configDB 配置。

3.添加分片
一个片服务既可以是单个 mongod 实例,也可以是一个副本集。
1).先分别在 172.17.0.8 和 172.17.0.9 上启动片服务器,即就是一个普通的 mongod 服务。

1
$ service mongodb start

2).使用 mongo 客户端连接到 mongos 服务

1
$ mongo --host <hostname of machine running mongos> --port <port mongos listens on>

如: $ mongo --host 172.17.0.7 --port 27017

3).在 mongo 客户端上执行命令添加分片:

1
2
3
4
> use admin
> db.auth(<user>, <pswd>)
> sh.addShard("172.17.0.8:27017")
> sh.addShard("172.17.0.9:27017")

4.切片数据
1).首先对数据库进行切片
使用 mongo 客户端连接到 mongos ,执行命令打开数据库的分片功能,用法如下:

1
> sh.enableSharding("<database>")

例如要打开 mydb 数据库的分片功能: > sh.enableSharding("mydb")

2).然后对数据集合进行切片
命令用法如下:

1
> sh.shardCollection("<database>.<collection>", shard-key-pattern)

shard-key-pattern 与索引的用法一样,例如,要对 mydb 数据库的 test 集合按照 _id 字段进行分片: > sh.shardCollection("mydb.test", {"_id": "hashed"})

接下来通过一个程序来测试一下,向数据库中添加10000条数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env ruby
#-*- coding:utf-8 -*-

require "mongo"

begin
  conn = Mongo::Connection.new '172.17.0.7'
  db = conn['mydb']
rescue Exception=>e
  p e
  exit 1
end

i = 0
while i < 10000
  d = {'no' => i}
  d = db['test'].insert(d)
  i += 1
  puts d
end

然后分别查看 172.17.0.8 和 172.17.0.9 的状态:

1
2
3
4
5
6
7
172.17.0.8:
> db.test.count()
4952

172.17.0.9:
> db.test.count()
5048

数据基本上是平均的分布在两台服务器上。

参考: http://docs.mongodb.org/manual/tutorial/deploy-shard-cluster/

使用gunicorn部署Django

| Comments

Gunicorn 是 Python的 一个 WSGI HTTP服务器,根据它的介绍说是它来自于 Ruby 的 Unicorn。可以方便的部署 Python 的 Web 程序,而且本身支持多种 Python 的框架,如 Django、Paster等。

通过介绍来看貌似很不错的样子,只可惜我现在不玩 Python 了,于是就简单体验一下。

简单应用

首先是安装,这个可以直接使用 pip 来完成:

1
$ pip install gunicorn

然后再根据官方文档的介绍部署一个简单的例子试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cd examples
$ cat test.py
# -*- coding: utf-8 -
#
# This file is part of gunicorn released under the MIT license.
# See the NOTICE for more information.

def app(environ, start_response):
    """Simplest possible application object"""
    data = 'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type','text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])

$ gunicorn -b 0.0.0.0:8000 --workers=2 test:app

好的,现在程序运行起来了,可以访问 http://localhost:8000 看下效果。

gunicorn 也可以通过配置文件来设置一些内容, 一个配置文件是一个 python 脚本,格式类似 .ini 。通过 -c 参数指定要使用的配置文件。如:

1
2
3
# config.ini
bind = ["0.0.0.0:8000", "unix:///tmp/gunicorn.sock"]
workers = 3 

gunicorn 还能与 Django 和 Paster 应用集成:

1
2
$ gunicorn --env DJANGO_SETTINGS_MODULE=myproject.settings myproject.wsgi:application
$ gunicorn --paste development.ini -b :8080 --chdir /path/to/project

与 Nginx 部署

gunicorn 本身也是一个 WSGI 应用,可以与 Nginx 一同使用。 以下是 Nginx + Gunicorn 部署 Django 的事例, Nginx 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# nginx.conf
http {
    include mime.types;
    default_type application/octet-stream;
    access_log /tmp/nginx.access.log combined;
    sendfile on;

    upstream app_server {
        server unix:/tmp/gunicorn.sock fail_timeout=0;
        # For a TCP configuration:
        # server 192.168.0.7:8000 fail_timeout=0;
    }

    server {
        listen 80 default;
        client_max_body_size 4G;
        server_name _;

        keepalive_timeout 5;

        # path for static files
        root /path/to/app/current/public;

        location / {
            # checks for static file, if not found proxy to app
            try_files $uri @proxy_to_app;
        }

        location @proxy_to_app {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;

            proxy_pass   http://app_server;
        }

        error_page 500 502 503 504 /500.html;
        location = /500.html {
            root /path/to/app/current/public;
        }
    }
}

Gunicorn 的配置文件:

1
2
3
4
5
6
7
8
9
10
11
# gunicorn.ini
import os

bind = ["0.0.0.0:8000", "unix:///tmp/gunicorn.sock"]
workers = 3
chdir = os.path.dirname(os.path.realpath(__file__))
raw_env = ["DJANGO_SETTINGS_MODULE=app.settings"]
accesslog = "/tmp/gunicorn-access.log"
errorlog = "/tmp/gunicorn.log"
daemon = True
pidfile = "/tmp/gunicorn.pid"

运行:

1
2
$ gunicorn -c gunicorn.ini webui.wsgi:application
$ service nginx start

其他内容

与 WSGI 应用一样,如果之后配置有改动可以向 gunicorn 服务进程发送 HUP 信号让其重新加载配置:

1
$ kill -s HUP <pid>

Mongodb集群配置实例

| Comments

Mongodb的集群有两种,一个是主从复制,另一种是副本集。

主从复制

根据 Mongodb 的官方文档说明,在生产环境中建议使用副本集代替主从复制。 http://docs.mongodb.org/manual/core/master-slave/

不过对于主从复制还是可以了解一下。假设有如下三台主机:

  • 172.17.0.4 (主)
  • 172.17.0.5 (从)
  • 172.17.0.6 (从)

要进行主从复制的配置,首先修改主服务器的配置信息:

1
2
master = true         # 以主服务器模式启动
bind_ip = 0.0.0.0

然后修改另两台从服务器配置信息:

1
2
3
slave = true
source = 172.17.0.4
bind_ip = 0.0.0.0

最后启动三台主机上的 Mongodb 服务,再通过一个简单的程序来测试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env ruby
#-*- coding:utf-8 -*-

require "mongo"

begin
  conn = Mongo::Connection.new '172.17.0.4'
  db = conn['test']
rescue Exception=>e
  p e
  exit 1
end

i = 0
while i < 100
  d = {'no' => i}
  d = db['data'].insert(d)
  i += 1
  puts d
end

执行该脚本,向 172.17.0.4 主机的 Mongodb 中插入一些数据。然后发现数据被同步到了另外两台主机上。

主从之间安全认证:
如果启动了 auth 项,那么主从之间的认证需要使用 keyFile 选项。

执行如下命令生成 key 文件,并设置为只有 mongodb 的进程用户可读写:

1
2
3
$ openssl rand -base64 741 > /path/mongodb_keyFile
$ chmow 600 /path/mongodb_keyFile
$ chown mongodb:mongodb /path/mongodb_keyFile

将该文件复制到这三台主机中,然后分别修改主从的配置信息:

1
keyFile = /path/mongodb_keyFile

副本集

同样的对于这三台主机,我们重新修改配置设置为副本集的形式。

  • 172.17.0.4
  • 172.17.0.5
  • 172.17.0.6

首先修改配置文件,设置副本集的名字。
注意:副本集中所有主机设置的名字需要一样。这里我们设为 myrepl0
注意:设置副本集之前各个 mongodb 的数据目录必须都为空。

1
replSet = myrepl0

接着启动所有 mongodb 服务,然后对副本集进行初始化。
连接任意一台 mongodb 服务,执行如下操作:

1
2
3
4
5
> rs.initiate({'_id': 'myrepl0', 'members': [
    {'_id': 1, 'host': '172.17.0.4:27017'},
    {'_id': 2, 'host': '172.17.0.7:27017'},
    {'_id': 3, 'host': '172.17.0.8:27017'}
]})

现在副本集的初始化已完成,可以通过如下命令查看状态:

1
> rs.status()

在运行过程中可以随时添加或移除一个节点,如:

1
2
rs.add("172.17.0.8:27017")
rs.remove("172.17.0.8:27017")

可以再通过上面的程序添加一些数据。然后再连接到任意一台主机进行查询,看看数据是否已同步。

详细内容可参考文档: http://docs.mongodb.org/manual/core/replication/

安全认证:

1.禁用 auth 选项和 replSet 选项再运行 mongodb

2.连接到该 mongodb 服务并创建用户

1
2
3
4
5
6
7
8
9
10
> use admin
switched to db admin
> db.addUser('root','root')
{
        "user" : "root",
        "readOnly" : false,
        "pwd" : "2a8025f0885adad5a8ce0044070032b3",
        "_id" : ObjectId("54745351f79804bd44b596fb")
}
>

3.重新以 auth、keyFile 和 replSet 模式启动 mongodb

4.连接到刚刚创建用户的 mongodb 服务

5.跟之前的步骤一样,配置副本集

1
2
3
4
5
> rs.initiate({'_id': 'myrepl0', 'members': [
    {'_id': 1, 'host': '172.17.0.4:27017'},
    {'_id': 2, 'host': '172.17.0.7:27017'},
    {'_id': 3, 'host': '172.17.0.8:27017'}
]})

参考: http://docs.mongodb.org/manual/tutorial/deploy-replica-set-with-auth/

使用VIM进行PHP远程调试

| Comments

最近在写 PHP 时感觉它的调试不是很方便,基本都是用的 var_dump 将信息输出到页面上进行调试。最终实现是受不了这种方式,就找了一下看看有没有什么简便的方法。 于是就找到了 vdebug 这个 vim 插件,使用它可以方便的进行远程调试。

根据 vdebug 的介绍,说是它可以用来调试基于 DBGP 协议的程序,比如: PHP、Python、Ruby等。 可能只是 DBGP 协议在 PHP 中用得比较多吧,因此看到的大部分介绍都是说的 PHP 调试。 关于 DBGP 协议的详细介绍可参考: http://xdebug.org/docs-dbgp.php

使用方法:

首先是在 vim 中安装这个插件,下载地址: https://github.com/joonty/vdebug

由于它的配置信息都写死在代码中的,因此我就 fork 了一份进行自定义的修改,如快捷键设置、远程主机名和端口号。

然后是安装 PHP 的 Xdebug 扩展,并配置一些参数信息。在 php.ini 配置文件中添加如下内容:

1
2
3
4
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9010

注意:这里的主机名和端口号要与 vdebug 中的一致。

接着使用 vim 打开一个 php 文件,按 <F5> 键启动该插件进行调试。然后在浏览器中访问该 php 程序, 并加上 XDEBUG_SESSION_START=1 参数,如: http://127.0.0.1/test.php?XDEBUG_SESSION_START=1

现在就可以在 vim 中对 php 程序进行单步调试了。

Nginx + Uwsgi + Django环境配置

| Comments

有段时间没折腾 Django 了,又有点生疏了。最近又部署了一下 Django 的环境,顺便作个笔记以便之后查阅。

首先安装 nginx、uwsgi 以及 uwsgi 的 python 插件。

然后新建一个 uwsgi 的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
[uwsgi]
uid = www-data
chdir = /repo/django-blog
virtualenv = /repo/django-blog/pyenv2.7/    # python虚拟环境,没有可以不设置
env = DJANGO_SETTINGS_MODULE=blog.settings
module = blog.wsgi:application
master = true
plugin = python
pidfile = /tmp/blog-master.pid
socket = /tmp/blog.sock
enable-threads = true
post-buffering=1024000
post-buffering-busize=655360

这里我们的 Django 项目代码位于 /repo/django-blog ,项目的配置文件为: blog/settings.py

virtualenv 项表明我们使用的是 virtualenv 环境,也可以直接系统的 python 环境。不过还是建议使用虚拟环境,以免软件包版本冲突。

post-bufferingpost-buffering-busize 这两项设置了 POST 请求时缓冲区的大小,该值可根据自己的情况进行调整。之前遇到过由于缓冲区不足导致返回的内容不完整。

再安装对应的 python 依赖包,然后运行 uwsgi 服务。

接着修改 nginx 的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
  listen 80;
  server_name localhost;

  client_max_body_size 50m;

  access_log /var/log/nginx/blog-access.log;
  error_log /var/log/nginx/blog-error.log;

  location / {
    uwsgi_pass unix:///tmp/blog.sock;
    include uwsgi_params;
  }

  location /static {
    alias /repo/django-blog/static/;
  }
}

这个内容比较简单, client_max_body_size 项是用于设置 http 请求的 body 最大大小。如果你的程序中有文件上传的,那么就需要根据自身情况来设置允许上传文件的最大值。

最后再启动 nginx 服务。

配置rails的vim环境

| Comments

今天分享一款 vim 的 rails 插件: vim-rails

使用该插件可以方便的在多个文件之间进行跳转。如在控制器的 action 上按 gf 键会自动跳转到对应的视图文件。

也可以使用 :Emodel, :Eview, :Econtroller, 命令在模型、视图以及控制器之间进行跳转。

该插件还提供了对 rails 的一些关键字的高亮。

并且还可以直接在 vim 中使用 :Rails 命令。

同时还有 vim-rakevim-bundler 两个插件提供了 rakebundle 的 vim 命令接口。

如果是用的 vundle 进行插件管理的话,可以直接在 .vimrc 配置中添加如下内容即可:

1
2
3
Bundle 'tpope/vim-rails'
Bundle 'tpope/vim-rake'
Bundle 'tpope/vim-bundler'

然后再在vim执行命令 :BundleInstall 即可。

博客终于迁移完成了!

| Comments

折腾了两天,终于将博客从之前的WordPress迁移到Jekyll上来了。

我的博客是从2009年开始使用WordPress的,至今也有5年多了。最近感觉WordPress提供的文章编辑功能不是很方便,本来是想着改用别的博客系统的。但是一直纠结着始终没换。一是由于懒,感觉能用就行了,不想折腾了。二是由于找不到比较好的系统。

这样就纠结了一年多。最近突然发现了Octopress,感觉很不错。于是果断地选择迁移过来。

环境搭建好了之后,接下来就是数据的迁移了。原打算之前的数据都不要了,准备从头再来的。毕竟之前的文章也写得不咋滴。 也许是自己比较怀旧吧,最终还是写了一个脚本将WordPress的数据输出为Markdown文件。
程序地址: https://github.com/wusuopu/wordpress-to-octopress

数据输出之后发现布局全乱了,又得重新调整一下格式。唉~~~~~,只是麻烦啊!

配置elixir的vim环境

| Comments

elixir是建立在Erlang虚拟机之上的一种函数式编程语言。下面介绍elixir的两个vim插件。

首先是语法高亮支持: https://github.com/elixir-lang/vim-elixir

其次是snippets支持: https://github.com/carlosgaldino/elixir-snippets 这个需要先安装 snipMate 插件。

如果也是用的 vundle 进行插件管理的话,可以直接在 .vimrc 配置中添加如下内容即可:

Bundle 'elixir-lang/vim-elixir'
Bundle 'carlosgaldino/elixir-snippets'

au BufNewFile,BufRead *.exs set ft=elixir

然后再在vim执行命令 :BundleInstall 即可。