??xml version="1.0" encoding="utf-8" standalone="yes"?> JAVA的NIO引入了异步I/OQ而Node.js宣称的就是异步编E,I/O自然是异步的。其实操作系l在很早引入了异步I/O的概念,如下图(摘自Unix|络~程中的囄Q: 我对上图的理解有几点Q?/p> 因ؓ内核中的异步I/O有缺P现实中的异步I/O通常qh的U程池模拟完成,如下图: Node.js中原本用了libeio异步I/O库,在v0.9.3后改己实现的U程池来完成异步I/O。所以在Node.js中,除了用户的Javascript代码是单U程外,所有I/O都是多线Eƈ行执行的?/p> Node.js通过事g循环的模式运行,在每一个@环的q程中,通过询问一个或多个观察者来判断是否有事件要处理Q而观察者可以有文gI/O观察者、网lI/O观察者等?/p> Node.js中异步I/O调用的大致流E如下:Node.js中的异步I/O
Node.js中的异步I/O调用
微信订阅P
源文地址Q?a title="作者博客:http://blog.gopersist.com">
]]>
服务?/strong> 操作pȝ IP 虚拟IP Server 1 Centos 192.168.18.20 192.168.18.22 Server 2 Centos 192.168.18.21 192.168.18.22 1. 安装Keepalived
2台Server都用下面的命o安装KeepalivedQ?br />2. Server1 Keepalived 配置
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100 # 优先U?br /> advert_int 1 # 心蟩间隔(U?
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.18.22 # 虚拟IP
}
}3. Server2 Keepalived 配置
vrrp_instance VI_1 {
state BACKUP # 备䆾?br /> interface eth0
virtual_router_id 51
priority 99 # 优先U,比主服务器底
advert_int 1 # 心蟩间隔(U?
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.18.22 # 虚拟IP
}
}4. 启动Keepalived
# Server 1:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:24:8c:8c:67:43 brd ff:ff:ff:ff:ff:ff
inet 192.168.18.20/24 brd 192.168.18.255 scope global eth0
inet 192.168.18.22/32 scope global eth0
inet6 fe80::224:8cff:fe8c:6743/64 scope link
valid_lft forever preferred_lft forever
# Server 2:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:23:54:bf:ab:17 brd ff:ff:ff:ff:ff:ff
inet 192.168.18.21/24 brd 192.168.18.255 scope global eth0
inet 192.168.18.22/32 scope global eth0
inet6 fe80::223:54ff:febf:ab17/64 scope link
valid_lft forever preferred_lft forever5. 试
览器访问http://192.168.18.22Q出?This is Server 1.
?92.168.18.20关闭Q再讉Khttp://192.168.18.22Q出现This is Server 2.
微信订阅P
源文地址Q?a >http://blog.gopersist.com/2014/09/24/keepalived/
]]>
IP配置信息如下Q?/span>
服务?/span> |
操作pȝ |
IP |
IP别名 |
|关 |
调度服务?/span> |
Centos |
192.168.2.90 |
192.168.2.99 |
192.168.2.1 |
实际服务?/span> |
Centos |
192.168.2.71 |
192.168.2.99 |
192.168.2.1 |
Centos |
192.168.2.72 |
192.168.2.99 |
192.168.2.1 |
直接路由方式工作在数据链路层Q通过修改数据包的MAC地址Q将数据包{发到实际服务器上。实际服务器响应时直接发送给用户端,而不l过调度器?/span>
因ؓ调度服务器ƈ没有修改数据包的IP地址Q所以我们需要ؓ实际服务器设|与调度服务器相同的IP别名Q以使实际服务器接受数据包?/span>
度服务器讄IP别名Q?/span>
ifconfig eth1:0 192.168.2.99
IP别名与原来的IP地址在用上q没有什么不同,q里可以ping?/span>90?/span>99两个IP?/span>
为实际服务器讄IP别名Q?/span>
ifconfig lo:0 192.168.2.99 broadcast 192.168.2.99 netmask 255.255.255.255 up
为实际服务器d路由规则Q它不d扑օ他拥有这?/span>IP的服务器Q?/span>
route add -host 192.168.2.99 dev lo:0
防止实际服务器响应针?/span>IP别名?/span>ARPq播Q?/span>
echo 1>/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2>/proc/sys/net/ipv4/conf/lo/arp_announce
echo 1>/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2>/proc/sys/net/ipv4/conf/all/arp_announce
使用ipvsadm配置调度服务器:
ipvsadm -A -t 192.168.2.99:8888 -s rr
ipvsadm -a -t 192.168.2.99:8888 -r 192.168.2.71:8888 -g
ipvsadm -a -t 192.168.2.99:8888 -r 192.168.2.72:8888 -g
使用下面的命令将q接有效旉改ؓ1U来试Q:
ipvsadm --set 1 120 300
览器访?/span>http://192.168.2.99:8888Q每?/span>1U多点击hQ就会交替出?/span>192.168.2.71?/span>192.168.2.72?/span>
IP配置信息如下Q?/span>
服务?/span> | 操作pȝ | |卡 | IP |
调度服务?/span> | Centos | eth0 | 192.168.18.58 |
eth1 | 192.168.2.90 | ||
实际服务?/span> | Centos | eth0 | 192.168.2.71 |
Centos | eth0 | 192.168.2.72 |
1. 首先配置调度服务器:
a) IPVS模块已经内置?/span>linux2.6.x内核中,可以通过下面的命令查看是否已安装Q?/span>
modprobe -l | grep ipvs
看到cM下面的输出,表示已经安装?/span>
kernel/net/netfilter/ipvs/ip_vs.ko
kernel/net/netfilter/ipvs/ip_vs_rr.ko
kernel/net/netfilter/ipvs/ip_vs_wrr.ko
kernel/net/netfilter/ipvs/ip_vs_lc.ko
kernel/net/netfilter/ipvs/ip_vs_wlc.ko
kernel/net/netfilter/ipvs/ip_vs_lblc.ko
kernel/net/netfilter/ipvs/ip_vs_lblcr.ko
kernel/net/netfilter/ipvs/ip_vs_dh.ko
kernel/net/netfilter/ipvs/ip_vs_sh.ko
kernel/net/netfilter/ipvs/ip_vs_sed.ko
kernel/net/netfilter/ipvs/ip_vs_nq.ko
kernel/net/netfilter/ipvs/ip_vs_ftp.ko
kernel/net/netfilter/ipvs/ip_vs_pe_sip.ko
b) 安装IPVS的管理工?/span>ipvsadmQ?/span>
yum install -y ipvsadm
c) 清除表中所有记录:
ipvsadm -C
使用下面的命令增加虚拟服务器Q采用轮询调度策略:
ipvsadm -A -t 192.168.18.58:8888 -s rr
使用下面的命令添加实际服务器Qƈ采用NAT方式转发数据包:
ipvsadm -a -t 192.168.18.58:8888 -r 192.168.2.71:9999 -m
ipvsadm -a -t 192.168.18.58:8888 -r 192.168.2.72:9999 -m
d) 打开数据包{发:
echo 1 > /proc/sys/net/ipv4/ip_forward
2. 接下来配|?/span>2台实际服务器Q分别做以下工作Q?/span>
a) ?/span>9999端口上启动一?/span>web服务Q?/span>
配置?/span>web服务后,当访?/span>http://192.168.2.71:9999Ӟ面q回Q?/span>This is 192.168.2.71.Q当讉Khttp://192.168.2.72:9999Ӟ面q回Q?/span>This is 192.168.2.72.
b) 讄默认|关指向调度服务?/span>
route del default
route add default gw 192.168.2.90
3. 试
讉K192.168.18.58:8888Q会昄This is 192.168.2.71?/span>This is 192.168.2.72Q多ơ刷新应该要交替出现71?/span>72Q但实际上ƈ没有q样Q浏览器只显CZW一ơ相同的内容Q也是ipvsadm每次都选择了同一台服务器。这是因为当一?/span>TCPq接的初?/span>SYN报文到达ӞIPVS选择了一台服务器Q后l报文会被{发到相同的服务器。这?/span>TCPq接?/span>ipvsadm中默认有效时间ؓ15分钟Q可以通过下面的命令查看:
ipvsadm -L --timeout
Timeout (tcp tcpfin udp): 900 120 300
现在有效时间改?/span>1U来试Q用下面的命oQ?/span>
ipvsadm --set 1 120 300
再到览器中每隔1U多点击hQ就会交替出?/span>71?/span>72Q说明轮询调度正在正常工作?/span>
IP配置信息如下Q?/span>
服务?/span> | 操作pȝ | |卡 | IP |
调度服务?/span> | Centos | eth0 | 192.168.18.58 |
eth1 | 192.168.2.90 | ||
实际服务?/span> | Centos | eth0 | 192.168.2.73 |
1. Z看到调度服务器上的数据{发过E,首先在调度服务器上分?/span>内核的debug日志Q?/span>
l ?/span>/etc/rsyslog.conf最后增加:kern.debug /var/log/iptables.log
l 重启日志服务Q?/span>/etc/init.d/rsyslog restart
2. 启动调度服务器的iptablesq清I?/span>
service iptables start
iptables -F
3. 增加调度服务器的iptables特定日志输出
假设要将对调度服务器8888端口的访问{发给实际服务器的9999端口处理Q在iptables中增加与q?/span>2个端口相关的日志输出Q?/span>
iptables -t mangle -A PREROUTING -p tcp --dport 8888 -j LOG --log-level debug --log-prefix "<<<<< PER IN:"
iptables -t mangle -A PREROUTING -p tcp --sport 9999 -j LOG --log-level debug --log-prefix "<<<<< PER IN:"
iptables -t mangle -A POSTROUTING -p tcp --sport 8888 -j LOG --log-level debug --log-prefix ">>>>> POST OUT:"
iptables -t mangle -A POSTROUTING -p tcp --dport 9999 -j LOG --log-level debug --log-prefix ">>>>> POST OUT:"
iptables -t mangle -A POSTROUTING -p tcp --sport 9999 -j LOG --log-level debug --log-prefix ">>>>> POST OUT:"
q时Q通过览器访?/span>http://192.168.18.58:8888可以看到iptables.log中打印出下面的日志:
Apr 24 16:24:35 route-server1 kernel: <<<<< PER IN:IN=eth0 OUT= MAC=00:1f:c6:cb:eb:e0:00:1f:33:de:29:ad:08:00 SRC=192.168.18.25 DST=192.168.18.58 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=28721 DF PROTO=TCP SPT=50270 DPT=8888 WINDOW=14600 RES=0x00 SYN URGP=0
Apr 24 16:24:35 route-server1 kernel: <<<<< POST OUT:IN= OUT=eth0 SRC=192.168.18.58 DST=192.168.18.25 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=8888 DPT=50270 WINDOW=0 RES=0x00 ACK RST URGP=0
虽然q个端口上即没有应用Q也没有请求{发出去,但日志打印出了内核获取到的对q个端口的请求?/span>
4. 配置iptables对8888的请求{发到192.168.2.73:9999
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8888 -j DNAT --to-destination 192.168.2.73:9999
讉Khttp://192.168.18.58:8888Q日志中打印如下信息Q?/span>
Apr 24 16:39:21 route-server1 kernel: <<<<< PER IN:IN=eth0 OUT= MAC=00:1f:c6:cb:eb:e0:00:1f:33:de:29:ad:08:00 SRC=192.168.18.25 DST=192.168.18.58 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=56888 DF PROTO=TCP SPT=50274 DPT=8888 WINDOW=14600 RES=0x00 SYN URGP=0
日志中只打印了从eth0收到的对8888端口的请求,q是因ؓ当数据要被{发到192.168.2.73:9999Ӟ默认情况下被止了?/span>
5. 打开数据包{发功?/span>
echo 1 > /proc/sys/net/ipv4/ip_forward
讉Khttp://192.168.18.58:8888Q日志中打印如下信息Q?/span>
Apr 24 16:39:21 route-server1 kernel: <<<<< PER IN:IN=eth0 OUT= MAC=00:1f:c6:cb:eb:e0:00:1f:33:de:29:ad:08:00 SRC=192.168.18.25 DST=192.168.18.58 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=56888 DF PROTO=TCP SPT=50274 DPT=8888 WINDOW=14600 RES=0x00 SYN URGP=0
Apr 24 16:39:21 route-server1 kernel: <<<<< POST OUT:IN= OUT=eth1 SRC=192.168.18.25 DST=192.168.2.73 LEN=60 TOS=0x00 PREC=0x00 TTL=62 ID=56888 DF PROTO=TCP SPT=50274 DPT=9999 WINDOW=14600 RES=0x00 SYN URGP=0
W一条日志显CZeth0收到了对8888端口的请求,W二条日志显C?/span>iptables已经更改了数据包的目的地?/span>192.168.2.73:9999Qƈ通过eth1发出厅R?/span>
但这时请求虽然已l被转发到实际处理的服务器,但调度服务器收不到响应,览器仍在不停重试,日志也在不断打印。这是因为实际服务器收到的数据包的来?/span>IP是另一个网D늚Q实际服务器回复Ӟ发现不是本网D늚把数据包发l网养I|关讄的是192.168.2.1Q这时数据就丢了?/span>
6. 实际服务器的默认网兌|ؓ192.168.2.90
在实际服务器上执行以下命令:
route del default
route add default gw 192.168.2.90
再次讉Khttp://192.168.18.58:8888Q日志打印如下信息:
Apr 24 16:47:27 route-server1 kernel: <<<<< PER IN:IN=eth0 OUT= MAC=00:1f:c6:cb:eb:e0:00:1f:33:de:29:ad:08:00 SRC=192.168.18.25 DST=192.168.18.58 LEN=60 TOS=0x00 PREC=0x00 TTL=63 ID=37000 DF PROTO=TCP SPT=50279 DPT=8888 WINDOW=14600 RES=0x00 SYN URGP=0
Apr 24 16:47:27 route-server1 kernel: <<<<< POST OUT:IN= OUT=eth1 SRC=192.168.18.25 DST=192.168.2.73 LEN=60 TOS=0x00 PREC=0x00 TTL=62 ID=37000 DF PROTO=TCP SPT=50279 DPT=9999 WINDOW=14600 RES=0x00 SYN URGP=0
Apr 24 16:47:27 route-server1 kernel: <<<<< PER IN:IN=eth1 OUT= MAC=00:22:b0:de:f7:49:00:24:8c:b4:a1:8c:08:00 SRC=192.168.2.73 DST=192.168.18.25 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=9999 DPT=50279 WINDOW=0 RES=0x00 ACK RST URGP=0
Apr 24 16:47:27 route-server1 kernel: <<<<< POST OUT:IN= OUT=eth0 SRC=192.168.2.73 DST=192.168.18.25 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=TCP SPT=9999 DPT=50279 WINDOW=0 RES=0x00 ACK RST URGP=0
上面W一条第二条日志和之前一Piptables目地址更改后,通过eth1|卡发送出厅R第三条日志通过eth1|卡接收C实际服务器发送过来的数据Qƈ在第四条日志中通过eth0发回h斏V?/span>