8月 16

RHEL5中的Cluster组件是基于章文嵩先生创立的LVS(Linux Virtual Server) 制作而成,

关于lvs的工作原理请参照《Linux 服务器集群系统》

Virtual Server via Network Address Translation(VS/NAT)
通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。

Cluster(NAT部分)实验

用到5台机器,做一个nat类型的httpd负载均衡集群.网络拓扑为

             ________
            |        |
            | client |
            |________|
           192.168.1.28          eth0 192.168.1.5
                |                eth1 10.0.0.1
                |                 _____________
     VIP(eth0:1)=192.168.1.50    |             |
     NIP(eth1:1)=10.0.0.254      |    router   |
            _ _ _ _ _            |_____________|
           |          |               |
             director  ---------------+
           |_ _ _ _ _ |               |
                |                eth0 192.168.1.6
                |                eth1 10.0.0.2
                |                 ______________
        -----------------        |              |
       |                 |       | router backup|
       |                 |       |______________|
  eth0 10.0.0.100   eth0 10.0.0.200
  gw   10.0.0.254   gw   10.0.0.254
 ______________    ______________
|              |  |              |
| realserver1  |  | realserver2  |
|______________|  |______________|


[client]
    os
        windwows xp

[router]
    os
        rhel5
    hostname
        vs
    software
        ipvsadm piranha httpd php

[router backup]
    os
        rhel5
    hostname
        vs_bk
    software
        ipvsadm piranha httpd php

[real server 1]
    os
        rhel5
    hostname
        rs1
    software
        httpd
 
[real server B]
    os
        rhel5
    hostname
        rs2
    software
        httpd

[director]
    为router或者router backup中的一台虚拟出来


配置如下
[router]

#打开路由转发功能
/etc/sysctl.conf
>
net.ipv4.ip_forward = 1

#设置piranha密码
piranha-passwd

#开启服务
service piranha-gui start

#访问配置页面
http://192.168.1.5:3636/

#配置以后的文件
[root@vs ~]# cat /etc/sysconfig/ha/lvs.cf
#序号
serial_no = 41


#公网ip地址
primary = 192.168.1.5

#内部ip地址
primary_private = 10.0.0.1

#服务名称
service = lvs

#是否有备份
backup_active = 1

#备份机器的ip地址
backup = 192.168.1.6

#备份机器的内网ip地址
backup_private = 10.0.0.2

#是否开启心跳
heartbeat = 1

#心跳的udp端口
heartbeat_port = 539

#心跳间隔(秒)
keepalive = 6

#如果主 LVS 节点在deadtime(秒)后没有答复,那么备份 LVS 路由器节点就会发起失效转移。
deadtime = 18

#lvs的类型
network = nat

#浮动ip地址以及对应设备
nat_router = 10.0.0.254 eth1:1

#浮动ip掩码
nat_nmask = 255.255.255.0

#debug信息级别
debug_level = NONE

#是否开启realserver的监视功能,和后面的scheduler(调度算法)以及load_monitor相关
monitor_links = 0

#虚拟服务的名称
virtual HTTP {
     #是否激活
     active = 1

     #虚拟服务所绑定的ip(vip)以及设备名
     address = 192.168.1.50 eth0:1

     #vip相对应的掩码
     vip_nmask = 255.255.255.0

     #虚拟服务的端口
     port = 80

     #给realserver发送的验证字符串
     send = "GET / HTTP/1.0\r\n\r\n"

     #服务器正常运行时应该返回的文本答复,用来判断realserver是否工作正常
     expect = "HTTP"

     #expect中是否使用正则表达式
     use_regex = 0

     #LVS 路由器能够使用 rup 或 ruptime 来监视各个真正服务器的载量。如果你从拉下菜单中选择了 rup,每个真正服务器就必须运行 rstatd 服务。如果选择了 ruptime,每个真正服务器就必须运行 rwhod 服务。
     load_monitor = none


     #调度算式,有循环调度/循环调度/最少连接/加权最少连接法(默认)/基于地区的最少连接调度/带有复制调度的基于地区的最少连接调度/目标散列调度/源散列调度
     scheduler = wlc

     #虚拟服务使用的协议类型
     protocol = tcp

     #realserver失效后从lvs路由条目中移除realserver所必须经过的时间(秒)
     timeout = 6

     #移除以后的realserver重新加入lvs路由条目所必须经过的时间(秒)
     reentry = 15

     #当选择了 Quiesce server 单选按钮时,无论何时某个新的真正服务器节点联机,最少连接表都会被重设为零,因此活跃 LVS 路由器就会选路发送所有请求,如同所有真正服务器都被重新加入群集一样。这个选项防止了新服务器在进入群集时对大量连接应接不暇。
     quiesce_server = 0

     #realserver服务器名称空间配置
     server rs1.yubo.org {
         #realserver的ip地址
         address = 10.0.0.100

         #是否激活
         active = 1

         #一个表明和集合内其它主机相比而言的主机能力的整数值。这个值可以是任意的,但是请把它当作和群集中其它真正服务器的比例对待
         weight = 1
     }
     server rs2.yubo.org {
         address = 10.0.0.200
         active = 1
         weight = 1
     }
}

#重启服务
service pulse restart




[router backup]

#打开路由转发功能
/etc/sysctl.conf
>
net.ipv4.ip_forward = 1

#设置piranha密码
piranha-passwd

#开启服务
service piranha-gui start

#访问配置页面
http://192.168.1.6:3636/

#配置以后的文件
[root@vs_bk ~]# cat /etc/sysconfig/ha/lvs.cf
serial_no = 39
primary = 192.168.1.6
primary_private = 10.0.0.2
service = lvs
backup_active = 1
backup = 192.168.1.5
backup_private = 10.0.0.1
heartbeat = 1
heartbeat_port = 539
keepalive = 6
deadtime = 18
network = nat
nat_router = 10.0.0.254 eth1:1
nat_nmask = 255.255.0.0
debug_level = NONE
monitor_links = 0
virtual HTTP {
     active = 1
     address = 192.168.1.50 eth0:1
     vip_nmask = 255.255.255.0
     port = 80
     send = "GET / HTTP/1.0\r\n\r\n"
     expect = "HTTP"
     use_regex = 0
     load_monitor = none
     scheduler = wlc
     protocol = tcp
     timeout = 6
     reentry = 15
     quiesce_server = 0
     server rs1.yubo.org {
         address = 10.0.0.100
         active = 1
         weight = 1
     }
     server rs2.yubo.org {
         address = 10.0.0.200
         active = 1
         weight = 1
     }
}


#重启服务
service pulse restart



之后开启rs1,rs2的httpd服务,为了使得便于观察
[root@rs1 ~]# echo "rs1.yubo.org" > /var/www/html/index.html
[root@rs2 ~]# echo "rs2.yubo.org" > /var/www/html/index.html


client频繁访问http://192.168.1.50时,会发现显示内容在"rs2.yubo.org"和"rs1.yubo.org"之间切换


[注意]
route 和 route backup 互为备份,没有主次之分(注意每个配置文件的backup和backup_private)
route backup 是route的备份
route 是route backup的备份

192.168.1.50和10.0.0.254这2个虚拟ip地址同一时刻只出现在1个router上,当前router当机以后,这2个ip地址会被另一台备份机器接管
7月 20

古老的筛法可快速求出100000000以内的所有素数。
筛法,是求不超过自然数N(N>1)的所有质数的一种方法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛子。
具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛”,简称“筛法”。(另一种解释是当时的数写在纸草上,每要划去一个数,就把这个数挖去,寻求质数的工作完毕后,这许多小洞就像一个筛子。)

下载: a.c
#include<stdio.h>
#include<time.h>
#define MAX 100000010
int n,p[MAX],tot=0;
double s,t;
FILE *fp;
void prime()
{
    
int i,j,t=sqrt(n)+1;
    
for(i=2;i<t;i++)
        
if(p[i])
        
{
            
fprintf(fp,"%d\n",i);
            
tot++;
            
j=i+i;
            
while(j<n)
            
{
                
p[j]=0;
                
j+=i;
            
}
        
}
    
for(i=t+1;i<n;i++)
        
if(p[i])
        
{
            
tot++;
            
fprintf(fp,"%d\n",i);
        
}
}
main()
{
    
int i;
    
fp=fopen("prime.txt","w");
    
scanf("%d",&n);
    
s=clock();
    
for(i=0;i<n;i++)
    
p[i]=1;
    
prime();
    
t=clock();
    
fprintf(fp,"Num = %d\nTime = %.0lf ms\n",tot,t-s);
    
fclose(fp);
}
7月 17

BubbleSort O(n2)

alt=”Your browser understands the <APPLET> tag but isn’t running the applet, for some reason.”Your browser is completely ignoring the <APPLET> tag!

BidirBubbleSort O(n2)

alt=”Your browser understands the <APPLET> tag but isn’t running the applet, for some reason.”Your browser is completely ignoring the <APPLET> tag!
Quick Sort O(nlog2n)

alt=”Your browser understands the <APPLET> tag but isn’t running the applet, for some reason.”Your browser is completely ignoring the <APPLET> tag!



一般来说,排序在普通情况下理想的时间复杂度为O(nlog2n),如果需要从50个无序数字中选出由小到大第30个数字,一般做法是先排序,再找出第30个.
能再快点吗?能在线性时间内完成吗?
下面给出实现办法,前提就是在不排序的情况下选择.

alt=”Your browser understands the <APPLET> tag but isn’t running the applet, for some reason.”Your browser is completely ignoring the <APPLET> tag!




自己改写的,具体算法和上面的类似.QuickSort

alt=”Your browser understands the <APPLET> tag but isn’t running the applet, for some reason.”Your browser is completely ignoring the <APPLET> tag!


The Sources

The applet.(改写过)
The “generic” sorting algorithm.
The Bi-directional Bubble Sort algorithm.
The Bubble Sort algorithm.
The Quick Sort algorithm.
快速选择.
快速排序.

7月 04

昨天应聘的一道题目,将32bit容量的整型转成字符.编译通过,从函数参数方面比较,IntToString明显要好于inttostr,算法都是o(n)级别的

#include <stdio.h></stdio.h>
 
int inttostr(int i, char *s, int *p);
char* IntToString(int value, char* string);
 
main() {
    
char str[10],*s;
    
int p = 0;
    
s = str;
 
    
inttostr(1234,s,&p);
    
// s=IntToString(1234,s);
    
printf("%s\n",s);
}
 
int inttostr(int i, char *s, int *p)
{
    
if ( i/10 )
    
inttostr( i/10 , s, p);
    
s[*p] = i%10 + '0';
    
s[++*p] = '\0';
    
return 1;
}
 
char* IntToString(int value, char* string)
{
    
char* pos = string;
    
int radix = 1;
 
    
if (value == 0)
    
{
        *
string = '0';
        *
(string+1) = '\0';
        
return string;
    
}
 
    
while (radix <= value)
    
{
        
pos++;
        
radix *= 10;
    
}
 
    *
pos = '\0';
 
    
while (pos != string)
    
{
        *--
pos = value % 10 + '0';
        
value = value / 10;
    
}
 
    
return string;
}

运行结果:

[root@rhel5 inttostr]# make
cc -c 1.c
cc -o 1 1.o
[root@rhel5 inttostr]# ./1
1234
6月 21

燕子啊!你飞到了什么地方?

可曾看到我亲爱的家乡?

太阳下马群在泉边饮水,

迷人的金盏花满山开放.

在群峰和海浪拥抱的岸旁,

风中的白杨树沙沙作响,

葡萄结实,麦穗金黄,故乡的田野多么芬芳!
有的人离开家乡到处流浪,

终生向往着童年的村庄.

燕子啊!飞到我家门上去做窝吧!

给我母亲带回游子的梦想。

6月 21

墨西孟德尔颂是德国知名作曲家的祖父。他的外貌极其平凡,除了身材五短之外,还是个古怪可笑的驼子。

      一天,他到汉堡去拜访一个商人,这个商人有个心爱的女儿名叫弗西,墨西无可救药地爱上了她,但弗西却因他的畸形外貌而拒绝了他。

    到了必须离开的时候,墨西鼓起所有的勇气,上楼到弗西的房间,把握最后和她说话的机会,她有着天使般的脸孔,但让他十分沮丧的是,弗西始终拒绝正眼看他。经过多次尝试性的沟通,他害羞地问:“你相信姻缘天注定吗?”

    她眼睛盯着地板答了一句:“相信,”然后反问他:“你相信吗?”他回答:“我听说,每个男孩出生前,上帝便会告诉他,将来要娶的是哪一个女孩。我出生的时候,未来的新娘便已经许配给我了。上帝还告诉我,我的新娘是个驼子。”我当时向上帝恳求:“上帝啊,一个驼背的妇女将是个悲剧,求你把驼背赐给我,再将美貌留给我的新娘。”

      当时,弗西看着墨西的眼睛,并被内心深处的某些记忆所搅乱了。她把手伸向他之后成了他最挚爱的妻子

5月 30
  1. [root@localhost 2]# ./a
  2. pid: 4144 fork: 0
  3. pid: 4143 fork: 4144
  4. [root@localhost 2]# cat a.c
下载: a.c
  1.  #include <stdlib.h>
  2.  #include <stdio.h>
  3.  
  4.  main() {
  5.     int pid;
  6.  
  7.     switch ( pid = fork() ){
  8.        case -1:
  9.           printf("fork: error");
  10.           break;
  11.  
  12.        case 0:         /* child */
  13.           printf ("pid: %d fork: %d\n", getpid(), pid);
  14.           break;
  15.  
  16.        default:        /* parent */
  17.           printf("pid: %d fork: %d\n", getpid(), pid );
  18.           break;
  19.  
  20.     }
  21.     exit(0);
  22.  }

网上有些文章简单的说成fork调用一次,返回两次.

我的理解是fork调用以后,会创建一个新的子进程,将父进程(4143)的环境(fork调用之前的所有变量)复制(是复制!!!)到子进程(4144)中.这样,运行到fork函数的时候,我们就得到了2个进程(4144和4143)

然后由fork函数返回该进程(也就是父进程4143)创建的子进程pid(4144)

如果没有就返回0(比如4144)

如果异常,返回-1

由于是2个进程,每个进程的fork都会返回1次,总体看上去就像返回了2次一样.根据返回值的不同,可以让2个进程执行不同的代码.

以下是TCPechod.c中fork应用的节选

  1.  switch (fork()) {
  2.     case 0:         /* child */
  3.        (void) close(msock);
  4.        exit(TCPechod(ssock));
  5.     default:        /* parent */
  6.        (void) close(ssock);
  7.        break;
  8.     case -1:
  9.        errexit("fork: %s\n", strerror(errno));
  10.  }
5月 17

以下代码摘自 Internetworking With TCP/IP Vol III (Douglas E.Comer/David L.Stevens) 第7章

int main(int argc, char *argv[])
{
  
char *host = "localhost"; /* host to use if none supplied */
  
char *service = "echo"; /* default service name */
 
  
switch (argc) {
      
case 1:
        
host = "localhost";
        
break;
      
case 3:
        
service = argv[2];
        
/* FALL THROUGH */
      
case 2:
        
host = argv[1];
        
break;
      
default:
        
fprintf(stderr, "usage: TCPecho [host [port]]\n");
        
exit(1);
  
}
  
TCPecho(host, service);
  
exit(0);
}

代码第一眼看上去有点奇怪,switch的顺序1>3>2,而且case3没有break,稍微花点时间可以看出上下文的意思就明白为什么这么做了.仔细想了一下,感觉这样做是否值得呢?

1. 对于人而言,维护这样的代码无疑增加了开销

2. 对于编译器而言,这样写于常规写法比起来,并没有提高任何性能(如循环次数,处理命令的数量等)

3. 对于读者再说,不知道其他人或者作者的习惯如何,至少我是迷糊了一会儿的….(当然,这样写比较巧妙,但这样的技巧似乎没有带来任何收益?)

4月 18

前段时间装了个solaris,这几天在瞎掰,好多命令忘记了,关于软件包管理的命令比较多,我按照linux日常使用习惯,归纳了一下,并附有相应的linux命令,当然,solaris也有自己特有的功能(没有相对应的linux命令),我用中文简单注释了一下 

# pkginfo | more   
// rpm -qa

# pkgrm xxx   
//rpm -e xxx

# pkgadd -d path xxx
# pkgadd -d cvs-bundle.pkg all  //数据流格式pkg
# pkgadd -d http://localhost/pkgs/cvs-bundle.pkg all
//rpm -ivh path/xxx-version-i386.rpm

———————eg.start——————————
# pkgtrans /cdrom/cdrom0/Solaris_10/Product /root/pkg/cvs.pkg SMCcvs
//将光盘中Product 目录下的 SMCcvs  转换成数据流格式文件cvs.pkg

# pkgadd -d /root/pkg/cvs.pkg -s spool all
//将数据流格式文件安装到缓冲中(/var/spool/pkg)
# pkgadd SMCcvs
//从缓冲中安装SMCcvs到系统

# pkgrm SMCcvs
//从系统中删除SMCcvs

# pkgrm -s spool SMCcvs
//从缓冲中删除

# pkgtrans /root/pkg/cvs.pkg . SMCcvs
//将数据流文件(cvs.pkg)转化为文件系统格式(当前目录下的SMCcvs目录)
———————eg.end——————————

# pkginfo -l SUNWftpr
//rpm -qi vsftpd

# pkgchk  SUNWftpr
//rpm -V vsftpd

# pkgchk  -v SUNWftpr
//rpm -ql vsftpd

# grep /etc/ftpd/ftpusers /var/sadm/install/contents
//rpm -qf /etc/vsftpd/vsftpd.conf

# pkgchk -p /etc/group
# pkgchk -l -p  /etc/group
# pkgchk -l -P  group
//rpm -qf /etc/group | xargs rpm -V | grep /etc/group

4月 16

硬件:TinkPad T61 + vmare6.5

os:
发行版本号
[root@solaris ~]#cat /etc/release
                          Solaris 10 3/05 s10_74L2a X86
           Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
                        Use is subject to license terms.
                            Assembled 22 January 2005

kernel版本号
[root@solaris ~]#uname -a
SunOS solaris 5.10 Generic i86pc i386 i86pc

先看下网卡的设备名(pcn0):
[root@solaris ~]#ifconfig -a
lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
        inet 127.0.0.1 netmask ff000000
pcn0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 2
        inet 192.168.1.100 netmask ffffff00 broadcast 192.168.1.255
        ether 0:c:29:37:c2:a4

设置主机名
/etc/hostname.pcn0
>
solaris

设置主机名的ip(也就是相应网卡的ip地址,还有一个/etc/inet/ipnodes文件作用跟此文件类似,但优先级较hosts文件高,如果发生冲突,应该知道这么办吧)
/etc/hosts
>
127.0.0.1                     localhost
192.168.1.100                 solaris            loghost
192.168.1.1                  router
设置掩码
/etc/netmasks
>
192.168.1.0 255.255.255.0

设置默认路由
/etc/defaultrouter
>
192.168.1.1

重刷网卡配置文件的命令没找到,所以用这个吧
ifconfig pcn0 192.168.1.100 netmask 255.255.255.0
route add default 192.168.1.1

校验下路由和网卡生效没有:
netstat -rn
ifconfig -a
设置dns服务器(我是武汉电信用户.所以….)
/etc/resolv.conf
>
nameserver 202.103.24.68
domain yubo.org
//注意这里的域名是yubo.org哦,后面校验时的www就等于www.yubo.org

设置域名解析优先级
/etc/nsswitch.conf
>
hosts:   files   dns

刷新配置
svcadm refresh network/dns/client

校验
nslookup
> www
Server:         202.103.24.68
Address:        202.103.24.68#53

Non-authoritative answer:
Name:   www.yubo.org
Address: 61.151.239.81
> www.sina.com.cn
Server:         202.103.24.68
Address:        202.103.24.68#53

Non-authoritative answer:
www.sina.com.cn canonical name = jupiter.sina.com.cn.
jupiter.sina.com.cn     canonical name = ara.sina.com.cn.
Name:   ara.sina.com.cn
Address: 58.63.236.36
Name:   ara.sina.com.cn
Address: 58.63.236.37
Name:   ara.sina.com.cn
Address: 58.63.236.38
Name:   ara.sina.com.cn
Address: 58.63.236.39
Name:   ara.sina.com.cn
Address: 58.63.236.40
Name:   ara.sina.com.cn
Address: 58.63.236.41
Name:   ara.sina.com.cn
Address: 58.63.236.42
Name:   ara.sina.com.cn
Address: 58.63.236.43
Name:   ara.sina.com.cn
Address: 58.63.236.44
Name:   ara.sina.com.cn
Address: 58.63.236.45
Name:   ara.sina.com.cn
Address: 58.63.236.46
Name:   ara.sina.com.cn
Address: 58.63.236.47
Name:   ara.sina.com.cn
Address: 58.63.236.48
Name:   ara.sina.com.cn
Address: 58.63.236.33
Name:   ara.sina.com.cn
Address: 58.63.236.34
Name:   ara.sina.com.cn
Address: 58.63.236.35