专注业务连续性支持与数据保护
2009-08-17生活琐记

《MySQL性能调优与架构设计》示例库结构脚本已关闭评论

《MySQL性能调优与架构设计》示例库结构脚本

示例库结构脚本的所有创建语句:

 

–创建数据库
Create DATABASE example;

–创建表
–索引是根据应用中使用的 Query 的情况而决定,所有表开始都仅仅只有主键,没有其他的索引
–各表没有特定存储引擎和字符集,各位读者朋友可根据自己的环境决定

Create TABLE event (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
user_id int(11) NOT NULL,
event_type varchar(8) NOT NULL,
event_msg varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
);

–组内讨论信息summary

Create TABLE group_message (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
group_id int(11) NOT NULL,
user_id int(11) NOT NULL,
author varchar(32) NOT NULL,
subject varchar(128) NOT NULL,
PRIMARY KEY (id)
);

–组内讨论信息内容

Create TABLE group_message_content (
group_msg_id int(11) NOT NULL,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
content text NOT NULL,
PRIMARY KEY (group_msg_id)
);

–组信息

Create TABLE groups (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
name varchar(32) NOT NULL,
status varchar(16) NOT NULL,
description varchar(1024) DEFAULT NULL,
PRIMARY KEY (id)
);

–特殊消息

Create TABLE message (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
subject varchar(64) NOT NULL,
status varchar(16) NOT NULL,
PRIMARY KEY (id)
);

–消息

Create TABLE message_content (
msg_id int(11) NOT NULL,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
content varchar(512) DEFAULT NULL,
PRIMARY KEY (msg_id)
);

–照片表

Create TABLE photo (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
user_id int(11) NOT NULL,
status varchar(16) NOT NULL,
subject varchar(64) NOT NULL,
url varchar(64) NOT NULL,
PRIMARY KEY (id)
);

–相册表

Create TABLE photo_album (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
album_name varchar(64) NOT NULL,
user_id int(11) NOT NULL,
PRIMARY KEY (id)
);

–照片相册关系表

Create TABLE photo_album_relation (
id int(11) NOT NULL auto_increment,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
album_id int(11) NOT NULL,
photo_id int(11) NOT NULL,
PRIMARY KEY (id)
);

–照片回复信息表

Create TABLE photo_comment (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
photo_id int(11) NOT NULL,
comments varchar(512) NOT NULL,
PRIMARY KEY (id)
);

–系统各组广播消息表

Create TABLE top_message (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
user_id int(11) NOT NULL,
author varchar(32) NOT NULL,
subject varchar(128) NOT NULL,
PRIMARY KEY (id)
);

–用户基本信息表

Create TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
nick_name varchar(32) NOT NULL,
password char(64) DEFAULT NULL,
email_b varchar(32) DEFAULT NULL,
status varchar(16) DEFAULT NULL,
PRIMARY KEY (id)
);

–用户个人详细信息表

Create TABLE user_profile (
user_id int(11) NOT NULL,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
sexuality char(1) NOT NULL,
msn varchar(32) DEFAULT NULL,
sign varchar(64) DEFAULT NULL,
birthday date DEFAULT NULL,
hobby varchar(64) DEFAULT NULL,
location varchar(64) DEFAULT NULL,
description varchar(1024) DEFAULT NULL,
PRIMARY KEY (user_id)
);

–用户分组表

Create TABLE user_group (
user_id int(11) NOT NULL,
gmt_create datetime NOT NULL,
gmt_modified datetime NOT NULL,
group_id int(11) NOT NULL,
user_type int(11) NOT NULL,
status varchar(16) NOT NULL,
PRIMARY KEY (user_id,group_id)
);

2009-08-17生活琐记

Linux跨网络运行X Window程序已关闭评论

Linux跨网络运行X Window程序

X Window在设计上就是跨网络的,X Client是需要图形显示的应用程序, X Server则负责具体显示和传递用户交互行为。二者之间通信的协议称为 X Protocol,X协议。

基于主机验证的X Window配置

(1) 在X Server端,加入允许发送X Request的机器地址。

$ xhost +192.168.0.1

关于xhost的用法示例:

$ xhost -192.168.0.1 #取消192.168.0.1发送X Request到本机
$ xhost + #允许所有主机发送X Request到本机
$ xhost + #再次执行该命令取消允许所有主机的授权

此外,可在/etc/X*.hosts中永久加入某些授权主机,其中*是本机显示编号,比如X0.hosts。细节可看man xhost的说明。

192.168.0.1
192.168.0.2

(2) 现在,就可以ssh(可能需要配置ssh转发X11数据,我没尝试过)或者telnet到X Client机器,并运行X Window应用程序,而显示和操作在X Server端。

$ xeyes -display 192.168.0.254:0

其中192.168.0.254是(1)中配置的主机,后面的:0表示发送到0号显示屏幕。有些X程序不支持-display参数,此时可考虑导出DISPLAY环境变量。

$ export DISPLAY=192.168.0.254:0

也许你会问,一台机器可以有多个显示屏幕吗?有的,默认启动的屏幕为0,不过你还可以启动多个。对于gdm启动X Window的方式,你可以修改/etc/X11/gdm/gdm.conf:

0=/usr/bin/X11/X -bpp 8 vt7
1=/usr/bin/X11/X -bpp 8 vt9
...

-bpp.参数指定颜色数,此处为8位色深。vt7表示Ctrl+Alt+F7可切换到该屏幕,vt9表示Ctrl+Alt+F9。你可以指定任意数目的显示屏幕。

如果要配置不同屏幕的登录界面,可执行如下操作:

$ cp /etc/X11/gdm/Init/Default /etc/X11/gdm/Init/:0
$ cp /etc/X11/gdm/Init/Default /etc/X11/gdm/Init/:1

然后可修改其中的配置命令。

对于startx启动X Window的方式,可直接在命令行指定,比如 startx — :1。

基于每用户验证的X Window配置

基本步骤是:先在X Server端的用户目录生成用户的cookie,然后把该cookie加入到X Client的用户目录。这样X Client程序运行的时候,会根据当前的DISPLAY搜寻cookie信息,并发送到X Server,从而得到验证。

因此,首先需要在X Server端生成cookie,可用xauth命令。

$ xauth
Using authority file /home/yingyuan/.Xauthority
xauth>list
192.168.0.199/unix:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
xauth>add 192.168.0.199:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
xauth>list
192.168.0.199/unix:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
192.168.0.199:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
xauth>exit

系统原来就有了一个cookie,我们用add命令新加了一个。

那么,如何把cookie传递给X Client呢?实现方法有三种,以下分别介绍。

(1) 直接把~/.Xauthority从X Server复制为X Client下的~/.Xauthority。这是最简单的实现办法。

(2) 用xauth的extract和merge命令。

在X Server端,

$ xauth
...
xauth>extract MyCookie 192.168.0.199:0
xauth>exit

然后我们把MyCookie文件传到X Client,并在X Client运行如下命令,

$ xauth
...
xauth>merge MyCookie
xauth>exit

(3) 记下X Server端的cookie值(用xauth的list可查看),

$ xauth
...
xauth>list
192.168.0.199/unix:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
192.168.0.199:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
xauth>exit

然后在X Client用xauth的add添加到.Xauthority文件。

$ xauth
...
xauth>add 192.168.0.199:0 MIT-MAGIC-COOKIE-1 8432567fa3ae2341
xauth>exit

X Window为我们运行程序提供了很大的灵活性,不是一般的GUI操作系统所能比拟的。Microsoft Windows可以通过运行X OnNet、X-WinPro、Omni-X等程序提供X Server服务,从而可以运行Linux上的X Client程序。

2009-08-17技术合集

通过PXE网络安装OpenBSD 4.2已关闭评论

通过PXE网络安装OpenBSD 4.2

1. 准备PXE服务

我的PXE服务安装在Ubuntu 7.10 Desktop环境,配置过程如下:

1.1 配置tftp

确保安装了xinetd,因为tftp是借助xinetd监听端口的,/etc/xinetd.d/tftp的内容如下:

service tftp
{
        socket_type = dgram
        protocol = udp
        wait = yes
        user = root
        server = /usr/sbin/in.tftpd
        server_args = -s /tftpboot
        disable = no
}

参数 “-s /tftpboot” 指定tftp的根目录为/tftpboot,这个目录的文件结构如下:

yingyuan@yyresearch:~$ ls -Rl /tftpboot/
/tftpboot/:
总用量 5024
-rw-r--r-- 1 root root 5068775 2007-11-27 18:25 bsd.rd
drwxr-xr-x 2 root root    4096 2007-11-28 10:59 etc
-rw-r--r-- 1 root root   52928 2007-11-27 18:25 pxeboot

/tftpboot/etc:
总用量 4
-rw-r--r-- 1 root root 12 2007-11-28 10:59 boot.conf

bsd.rd是OpenBSD的ram disk文件系统,pxeboot是PXE请求时返回的启动加载文件,这两个文件都可以从安装光盘或者从ftp镜像网站提取。boot.conf是由pxeboot读取的启动配置文件,内容只有一行:

boot bsd.rd

启动tftp服务,

yingyuan@yyresearch:~$ sudo /etc/init.d/xinetd restart

1.2 配置DHCP服务

/etc/dhcp3/dhcpd.conf的配置内容如下,

ddns-update-style none;
option domain-name "example.com";
option domain-name-servers 10.0.0.1;
default-lease-time 600;
max-lease-time 7200;

class "openbsd-pxeboot-class" {
        match pick-first-value (option dhcp-client-identifier, hardware);
        filename "pxeboot";
        next-server 10.0.0.1;
}

subclass "openbsd-pxeboot-class" 1:8:0:27:3B:56:0;

subnet 10.0.0.0 netmask 255.255.255.0 {
        pool {
                allow members of "openbsd-pxeboot-class";
                option routers 10.0.0.1;
                range 10.0.0.200 10.0.0.240;
        }
}

需要安装OpenBSD机器的网卡MAC地址是08:00:27:3B:56:00,协议是以太网(协议号是1),我们把它分到openbsd-pxeboot-class这个类里。

启动dhcp服务,

yingyuan@yyresearch:~$ sudo /etc/init.d/dhcp3-server restart

2. 准备HTTP网络安装文件

我只从OpenBSD的镜像FTP站点拷贝了一些必要的文件,放在Apache的OpenBSD/i386目录下,

yingyuan@yyresearch:~$ ls -l /var/www/OpenBSD/i386
总用量 145976
-rw-r--r-- 1 yingyuan yingyuan 42603450 2007-11-27 17:21 base42.tgz
-rw-r--r-- 1 yingyuan yingyuan  6229740 2007-11-27 17:16 bsd
-rw-r--r-- 1 yingyuan yingyuan  5068775 2007-11-27 17:13 bsd.rd
-rw-r--r-- 1 yingyuan yingyuan  5185536 2007-11-27 17:08 cd42.iso
-rw-r--r-- 1 yingyuan yingyuan 78804092 2007-11-27 17:31 comp42.tgz
-rw-r--r-- 1 yingyuan yingyuan  1240720 2007-11-27 17:34 etc42.tgz
-rw-r--r-- 1 yingyuan yingyuan      266 2007-11-28 12:27 index.txt
-rw-r--r-- 1 yingyuan yingyuan   100845 2007-11-27 17:00 INSTALL.i386
-rw-r--r-- 1 yingyuan yingyuan    22354 2007-11-27 17:02 INSTALL.linux
-rw-r--r-- 1 yingyuan yingyuan  7656850 2007-11-27 17:35 man42.tgz
-rw-r--r-- 1 yingyuan yingyuan     1287 2007-11-27 17:14 MD5
-rw-r--r-- 1 yingyuan yingyuan  2292887 2007-11-27 17:38 misc42.tgz
-rw-r--r-- 1 yingyuan yingyuan    52928 2007-11-27 17:14 pxeboot

启动www服务,

yingyuan@yyresearch:~$ sudo /etc/init.d/apache2 restart

3. 安装OpenBSD 4.2

把机器设置为从网络启动,一按电源按照提示操作就OK了。

分区的时候我选择把整块硬盘分为一个OpenBSD分区,标签分配如下,

标签          容量                                  挂载点
----------------------------
a      512M            /
b      512M            swap
c      整个硬盘
d      1G              /var
e      剩下的空间                    /usr

指定大小的时候以磁盘扇区(512 bytes)为单位,所以需要计算一下。每个标签之间默认间隔一个磁道。

2009-08-16技术合集

Memcache的备忘已关闭评论

Memcache的备忘

  • 用memcache保存session的例子,非常简单
     
    CODE:

    1. <?php
    2. $session_save_path = "tcp://$host:$port?persistent=1&weight=2&timeout=2&retry_interval=10, ,tcp://$host:$port ";
    3. ini_set(‘session.save_handler’, ‘memcache’);
    4. ini_set(‘session.save_path’, $session_save_path);
    5. ?>

     

  • memcache每一个item上限是1M,注意不要超出上限
  • memcache本身并不支持namespace,但是可以通过一些手段模拟出namespace的效果来,见Memcache 中模拟 namespace
  • 刚接触memcache的时候,可能会写出这样的代码来
    CODE:

    1. $zhang = $memcache->get(‘key1’);
    2. $li = $memcache->get(‘key2’);
    3. $wang = $memcache->get(‘key3’);

    这种写法实际运行效果是

    • get(key1) – 客户端发出请求 – 服务器端查询 – 客户端获取
    • get(key2) – 客户端 – 服务器端 – 客户端
    • get(key3) – 客户端 – 服务器端 – 客户端

    如此一来,会有三次客户端和服务器端交互的过程。但是如果用批量查询的方法,就只有一次交互的过程。比如:

     
    CODE:

    1. $all = $memcache->get(array(‘key1’, ‘key2’, ‘key3’));

    这样性能会有一些提升。对于其它程序语言来说,也封装了类似get_multi这样的方法。

  • 从数据库从查询获得一个列表,放到memcache里面保存起来是一个不错的主意,但是不要忘记memcache有1m限制。如果列表太大,可以考虑把数据分割开来,然后用key序列来保存这个列表数据,比如event_0_500来保存前500行,用event_0_1000保存500-1000行,在获取的时候可以用前面说的批量get来一次性得到这个列表。
  • 经常观察memcached的大小和命中率,方便调整缓存策略
2009-08-16技术合集

最简便的清空memcache的方法已关闭评论

最简便的清空memcache的方法

This is easy right? Can’t you just restart the memcached server? Well yes, but you may cause errors in applications that are already connected to it. You can follow your memcached restart with an application restart, eg for a Ruby on Rails app:

# /etc/init.d/memcached restart && mongrel_rails cluster::restart

Of course if you have more than one application server you have to restart your app on every single one. This would work on an engineyard slice assuming you have the eycap gem installed:

$ cap production memcached:restart
$ cap production mongrel:restart

Restarting your application is not ideal however, you will lose anything cached in memory, cause delays to users trying to access your site, that sort of thing.

So what can be done? The answer is really simple. Assuming a memcached running on the local machine on the default port:

$ echo “flush_all” | nc localhost 11211

Easy!

2009-08-16技术合集

启用memcached压缩注意事项已关闭评论

启用memcached压缩注意事项

在php开发中,开启memcache的数据压缩存储是一件很简单的事情。在多数情况下,压缩数据不仅不会降低程序的执行效率,反倒会因为网络传输的开销降低,带来速度提升。看看最常用的Memcache::set方法:
bool Memcache::set ( string $key , mixed $var [, int $flag [, int $expire ]] )

在这个方法中,将$flag设置为MEMCACHE_COMPRESSED即可启用memcache压缩存储。

这样做有什么弊端?

如果没有做额外判断,每一次写入memcache都会启用压缩,不管数据的大小。对应的,每次获得数据都需要做一次解压缩的操作,这是典型的一刀切手法。实际上在数据很小的情况下,不需要压缩,在这个基础上压缩省不了多少空间。

更好的压缩策略?

好了,我的想法是在数据超过一定大小(比如2k)的情况下,才开启压缩。这个好办,捋起袖子就干,在调用Memcache::set方法之前,首先判断一下数据的大小,一个strlen就搞定了,再简单不过了。

PHP:

  1. $memcache = new Memcache;
  2. $memcache->connect(‘localhost’, 11211);
  3. $flag = strlen($data)> 2048 ? MEMCACHE_COMPRESSED : 0;
  4. $memcache->set(‘mykey’, $data, $flag);

有人可能会问了,array和object怎么办,这玩意可不能用strlen判断长度。

这还真能难住我一阵子,要知道把array/object写入memcache的时候,php会自动做serialize,再把它当作字符串插入memcache。

PHP:

  1. $flag = strlen(serialize($data))> 2048 ? MEMCACHE_COMPRESSED : 0;

谁会采用这段代码?看起来非常山寨,而且serialize也不快,赔本买卖。

更好的办法!

上面的文字都是废话,直接看这段就好。Memcache::setCompressThreshold方法可以包办之前所有的逻辑。

Memcache::setCompressThreshold – Enable automatic compression of large values

bool Memcache::setCompressThreshold ( int $threshold [, float $min_savings ] )

举个例子,下面这段会自动启用压缩策略,当数据大于2k时,以0.2的压缩比进行zlib。

PHP:

  1. $memcache->setCompressThreshold(2000, 0.2);

根据我的测试结果,setCompressThreshold方法会忽略Memcache::set的flag参数

2009-08-16技术合集

memcache.php stats like apc.php已关闭评论

memcache.php stats like apc.php

For a long time I was looking for a nice web interface like the apc.php (comes with the apc’s source) that displays whole nine yards of stats. The only good tool is memcache-tool from the danga guys. It’s quite complete but I guess I’m too lazy to go on the command line.

Anyways, I decided to rip write my own. Totally based on the original apc.php (I even recycled some functions) and apart from completeness, here is a memcache.php that you can get stats and dump from multiple memcache servers.
Here is a screenshot:


And here is the the source code.

As usual, this piece of software comes with the warnings:
– Don’t expect something complete, might have bugs and security problems etc.
– Do not install on a prod environment unless you’re sure!
– Feel free to add stuff to it, I’ll put it to google code or sf.net soon.
– Feel free to request features. (no I’m not planning a backup tool , there is memcache-tool for that)
– Enjoy!