2010-10-21

[读书笔记] LVM (更新)

原始版本: http://hi.baidu.com/lidaobing/blog/item/9509a344ed416a87b3b7dc2a.html


updated: ext2resize 不再可用,换到 resize2fs


它是什么?


LVM(逻辑卷管理)能将多个储存设备(包括分区,RAID设备等)合并成为一个新的储存设备。在这设备上可以建立多个分区。他支持动态调整分区大小,动态添加或删除底层设备。


安装



sudo apt-get install lvm2
sudo apt-get install e2fsprogs



创建


LVM 可以在磁盘的分区或者RAID上的分区(如/dev/md0)上创建



# pvcreate /dev/sdb /dev/sdc # 格式化分区为LVM格式
# vgcreate vg0 /dev/sdb /dev/sdc # 创建volume group
# vgdisplay vg0 # 显示volume group 信息
# apt-get install dmraid # 安装raid device map
# lvcreate -L 500G -n vol1 vg0 # 创建逻辑卷
# mke2fs -j /dev/vg0/vol1 # 在逻辑卷上创建 ext3 分区
# mount /dev/vg0/vol1 /mount/path


扩容 (无须停机)



# pvcreate /dev/sdd
# vgextend vg0 /dev/sdd
# lvextend -l +100%FREE /dev/vg0/vol1
# resize2fs -p /dev/vg0/vol1


磁盘损坏


还有额外的地方可以连接新的硬盘 (无须停机)


比如 /dev/sdb 损坏,接入的新硬盘叫 /dev/sde



# pvcreate /dev/sde # 格式化新硬盘
# vgextend vg0 /dev/sde # 添加新硬盘到卷组
# pvmove /dev/sda /dev/sde # 移动数据
# vgreduce vg0 /dev/sda # 卸载硬盘


没有额外的地方可以连接新硬盘


需要先缩小分区至可容纳在剩余的硬盘上



# pvmove /dev/sda # 移动数据至同组的其他硬盘
# vgreduce vg0 /dev/sda # 卸载硬盘
# 更换硬盘
# pvcreate /dev/sda
# vgextend vg0 /dev/sda
# 接上面的扩容步骤



参考文献


2010-10-19

[读书笔记] Rails 中的 Rack 中间件

0. 背景知识


0.1 Rack 协议


Rack 起源于 Python 的 WSGI 协议, 是一个语言相关的 HTTP 服务端接口 (CGI, FCGI, SCGI 是语言无关的接口, WSGI, Rack, Servlet 则属于语言相关的接口), 该协议下一个简单的应用形式如下


# config.ru
class Helloworld
def call(env)
[200, {'Content-Type' => 'text/plain'}, ['hello world!']]
end
end
run Helloworld.new

将该文件存为 config.ru, 然后在该目录下运行 rackup 即可启动该应用, 详细规范可以参考 http://rack.rubyforge.org/doc/files/SPEC.html

Rails 3.0, Sinatra 都使用了 Rack 作为自己的底层, 也就是说这两个 web 框架可以共用 Rack 中间件

0.2 Rack 中间件(middleware)接口



Rack 的协议本身很简单, 需要通过中间件来支持常见的 HTTP 功能,比如 cookie, session, flash, log, cache, ...

中间件本身也是一个 Rack 应用程序, 与简单 app 略有不同的是中间件通常以下一个 app 作为初始化参数

如下的代码就是 Rack::Runtime 中间件,用于记录应用程序的执行时间:

module Rack
class Runtime
def initialize(app)
@app = app
@header_name = "X-Runtime"
end

def call(env)
start_time = Time.now
status, headers, body = @app.call(env)
request_time = Time.now - start_time
if !headers.has_key?(@header_name)
headers[@header_name] = "%0.6f" % request_time
end
[status, headers, body]
end
end
end

中间件的使用也很方便, 只需加一句 "use Rack::Runtime" 即可, 如下所示

# config.ru
class Helloworld
def call(env)
[200, {'Content-Type' => 'text/plain'}, ['hello world!']]
end
end
use Rack::Runtime
run Helloworld.new


1. 如何在 Rails 程序中查看使用了哪些中间件




$ rake middleware
(in /path/to/project)
use ActionDispatch::Static
use Rack::Lock
use Rack::Runtime
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::RemoteIp
use Rack::Sendfile
use ActionDispatch::Callbacks
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::MethodOverride
use ActionDispatch::Head
use ActionDispatch::BestStandardsSupport
use OpenIdAuthentication
run ProjectName::Application.routes

这些中间件大部分在 $GEM_PATH/railities-3.0.0/lib/rails/application.rb 的 default_middleware_stack 函数中定义。

2. 这些中间件有什么用



  • ActionDispatch::Static, 静态文件(即 public/ 下的文件)支持, 一般在生产环境下会禁用此功能
    Rack::Lock, 线程锁, 保证 rails 代码单线程运行, 同时设置 env['rack.multithread'] = false, 你可以通过设置 config.allow_concurrency = true 来去掉该中间件

  • Rack::Runtime, 统计运行时间, 放在 response 的 "X-Runtime" header 中

  • Rails::Rack::Logger, 比如 log/development.log 中的这一行 "Started GET "/" for 127.0.0.1 at Wed Sep 15 21:46:51 +0800 2010"

  • ActionDispatch::ShowExceptions, 截获异常,把异常转换为 HTTP 错误号 (一般转为 500, 但一些特殊异常转到相应的错误号,比如 "ActionController::MethodNotAllowed" 会被转为 405, 同时显示对应的错误页面,对应开发环境,会显示异常的 backtrace, 对于生产环境,则会显示 public/500.html, 对于测试环境,该中间件会被禁用,直接把异常抛出

  • ActionDispatch::RemoteIp, 解决服务器转发, 代理导致客户端真实 IP 丢失的问题,用户的真实IP放在 env["action_dispatch.remote_ip"]

  • Rack::Sendfile, 如果返回数据已经放在一个文件里边了(比如生成的 PDF), 则可以让 nginx 服务器直接从该文件读取,降低系统消耗

  • ActionDispatch::Callbacks, 测试环境下用于检测源文件是否改变, 产品环境下作用不明 (TODO)
  • ActionDispatch::Cookies, cookie 支持
  • ActionDispatch::Session::CookieStore, session 支持,此处使用 cookie store
  • ActionDispatch::Flash, flash 支持, 参见 http://guides.rubyonrails.org/action_controller_overview.html#the-flash
  • ActionDispatch::ParamsParser, 分析XML, JSON参数,放到 env["action_dispatch.request.request_parameters"]
  • Rack::MethodOverride, 支持用 POST 来模拟 PUT, DELETE, ..., 可以在 POST 使用 _method 参数,也可以使用 HTTP 头 "HTTP_X_HTTP_METHOD_OVERRIDE"
  • ActionDispatch::Head, 把 HEAD 请求转为 GET 请求, 同时设置 env["rack.methodoverride.original_method"] = "HEAD"
  • ActionDispatch::BestStandardsSupport, 设置 HTTP 头: X-UA-Compatible
  • ProjectName::Application.routes, 终于进入你的 rails 程序了, 开始路由, 同时开始使用 rails 的协议栈

3. 如何配置中间件


3.1 通过 config 来配置


可以参考 $GEM_PATH/railities-3.0.0/lib/rails/application.rb 的 default_middleware_stack 函数, 源码显示了如何使用 config 来控制中间件

3.2 直接修改中间件


你可通过 config.middleware (如果在配置外则需使用 Rails::Application.middleware) 来访问 middleware, 这是一个 ActionDispatch::MiddlewareStack 对象, 你可以通过他的方法来操纵 middleware, 比如你要删除 Rack::Runtime, 就可以新添 config/initializers/stack.rb 文件,内容如下
Rails::Application.middleware.delete Rack::Runtime

3.3 覆盖 default_middleware_stack 函数


修改 config/application.rb, 把 Application 类改为如下所示

module MyApp
class Application < Rails::Application
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |x|
x.use Rack::Runtime
end
end
end
end

再运行 rake middleware, 可以看到大部分 middleware 都不见了

3.4 通过 rails 的插件体系


比如 vendor/plugins/open_id_authentication/init.rb 中间就有一句:
config.middleware.use OpenIdAuthentication

这句话就把 OpenIdAuthentication 这个中间件放到了 MiddlewareStack 的栈顶

2010-10-08

approx

打包时经常需要反复下载一些包, 如果你的网速不够快,建议安装 approx 透明代理, 可以缓存大部分包。

1. 如何安装 approx
安装方法: "sudo apt-get install approx", 然后修改配置文件 /etc/approx/approx.conf 为
ubuntu http://cn.archive.ubuntu.com/ubuntu
debian http://mirrors.163.com/debian
修改 /etc/apt/sources.list, 修改为如下的内容
deb http://127.0.0.1:9999/ubuntu lucid main restricted universe multiverse
deb http://127.0.0.1:9999/ubuntu lucid-security main restricted universe multiverse
deb http://127.0.0.1:9999/ubuntu lucid-updates main restricted universe multiverse

2. approx 的优点
2.1 可以在局域网内共享, approx 缺省绑定在 0.0.0.0, 所以一个局域网内用户可以共享这个源,互相加速, 如果使用安装法部署大量机器时也非常快速
2.2 i386 和 amd64 系统可以互相加速(因为可以互相共享架构无关的包),karmic 和 lucid 也可以互相共享包 (某些包在这两个版本是一致的), 但 debian 和 ubuntu 之间不能共享包
2.3 即使单人使用, approx 也很有帮助,比如可以快速重建 linux chroot, pbuilder, 或者在虚拟机内重装一份debian/ubunu
2.4 可以模拟多线程下载,比如你要同时安装 vim 和 emacs, 可以先运行 "sudo apt-get install vim", 然后在下载时按 Ctrl+C 终端,然后运行 "sudo apt-get install emacs23", 这时候 approx 会在后台帮你下载 vim 所需的包 (一般会帮你下载前面5个)
2.5 智能cache, debian/ubuntu 仓库有逐级签名, approx 能快速判定一个文件,是不是完整的,是不是最新的, 也可以定时清理掉不再被使用的文件。

2010-10-02

在 Ubuntu 构建 Debian 打包环境

0. 原因
尽管你是在 Ubuntu 下工作,但由于种种原因[1],你还是需要给 Debian 做打包工作,如果你不想你做的包因为一些简单的错误被退回,比如无法在 Debian 下编译,没有处理好 lintian 警告,那么最好在 Ubuntu 下给 Debian 打包的环境,步骤如下所示:

1. 安装 approx
打包时经常需要反复下载一些包, 如果你的网速不够快,建议安装 approx 透明代理, 可以缓存大部分包。安装方法: "sudo apt-get install approx", 然后修改配置文件 /etc/approx/approx.conf 为
ubuntu http://cn.archive.ubuntu.com/ubuntu
debian http://mirrors.163.com/debian

2. 修改 /etc/apt/sources.list, 修改为如下的内容
deb http://127.0.0.1:9999/ubuntu lucid main restricted universe multiverse
deb http://127.0.0.1:9999/ubuntu lucid-security main restricted universe multiverse
deb http://127.0.0.1:9999/ubuntu lucid-updates main restricted universe multiverse

3. 安装工具包, 运行 "sudo apt-get install ubuntu-dev-tools cowbuilder"

4. 准备 cowbuilder-sid
$ sudo cp /usr/bin/pbuilder-dist /usr/bin/cowbuilder-sid
$ sudo sed -ie 's,ftp://ftp.debian.org/debian,http://127.0.0.1:9999/debian,' /usr/bin/cowbuilder-sid

5. 准备开发环境
$ sudo mkdir /var/cache/pbuilder-dist/sid_result
$ cowbuilder-sid create

6. 开始开发
$ dget http://ftp.debian.org/debian/pool/main/h/hello/hello_2.6-1.dsc
$ dpkg-source -x hello_2.6-1.dsc
$ cd hello-2.6
$ # 修改 debian 包,版本改为 2.6-2
$ debuild -S -sa
$ cd ..
$ cowbuilder-sid hello_2.6-2.dsc # 使用 sid 环境进行编译

7. 检查
7.1 安装最新版的 lintian
Ubuntu 自带的 lintian 版本不够新,需要从 Debian 安装最新版本
$ # 到 http://ftp.us.debian.org/debian/pool/main/l/lintian/ 下载最新版本的 lintian
$ wget http://ftp.us.debian.org/debian/pool/main/l/lintian/lintian_2.4.3_all.deb
$ sudo dpkg -i lintian_2.4.3_all.deb
$ sudo apt-get -f install

7.2 对包做最后的检查
$ cd /var/cache/pbuilder-dist/sid_result
$ lintian -i hello_2.6-2_amd64.changes
$ #如果上一步出现错误,则继续修正
$ debsign hello_2.6-2_amd64.changes #签名

8. 上传
根据 http://mentors.debian.net/cgi-bin/maintainer-intro 的介绍准备好 mentors.debian.net 的上传的环境, 然后用如下的命令上传
$ dput mentors hello_2.6-2_amd64.changes

9. 召唤 Debian Developer (DD)
到 mentors.debian.net, 登录后可以找到一份模板邮件, 把模板邮件中的内容填好,然后发到 debian-mentors@lists.debian.org
如果你有相熟的 DD, 也可以直接发信给他让他帮忙检查。