理解web服务器和数据库的负载均衡以及反向代理

来源: 电脑维修教程 阅读:     发表时间:

但是若该网站平均每秒的请求是200多次,那么问题就来了:这已经是最好的web服务器了,我该怎么办?同样的情景也适用于数据库。要解决这种问题,就需

但是若该网站平均每秒的请求是200多次,那么问题就来了:这已经是最好的web服务器了,我该怎么办?同样的情景也适用于数据库。要解决这种问题,就需要了解“负载均衡”的原理了。

web服务器如何做负载均衡

为web服务器做负载均衡适用的的较多的方式是dns重定向和反向代理,其他的方式原理也是很类似。

我们多次ping一下百度,会发现回复的ip会有所不同,例如第一次的结果为:

代码如下:

正在 ping baidu.com [220.181.111.86] 具有 32 字节的数据:

来自 220.181.111.86 的回复: 字节=32 时间=27ms ttl=51

来自 220.181.111.86 的回复: 字节=32 时间=27ms ttl=51

来自 220.181.111.86 的回复: 字节=32 时间=27ms ttl=51

过一会再ping一次,结果可能就变了:

代码如下:

正在 ping baidu.com [220.181.111.85] 具有 32 字节的数据:

来自 220.181.111.85 的回复: 字节=32 时间=27ms ttl=51

来自 220.181.111.85 的回复: 字节=32 时间=27ms ttl=51

来自 220.181.111.85 的回复: 字节=32 时间=29ms ttl=51

使用nslookup命令可以看到多个ip与baidu.com对应。在这里用到的就是dns重定向技术,原理很简单:dns服务器保存某域名对应的多个ip,客户端发出dns请求时dns服务器根据算法将ip发回给客户端;发送回的一般是一个ip地址集合,但是每次的排序不同,第一次的第一个ip为201.11.11.1,第二次的第一个可能是201.11.11.2,客户端使用的是第一个ip——简单地说,就是客户端每次获取的域名的ip可能不同。不同的ip对应不同的web服务器,但是这些web服务器的内容应该是一样的。

我们从下图理解反向代理:

客户端向反向代理发送http请求报文(若该网站有域名,域名的ip是反向代理服务器的外网ip),反向代理将请求报文随机发送给一个web服务器,web服务器将http响应报文发送给反向代理,反向代理再将这报文返回给客户端。既然这样简单,我们就可以着手实现一个简单的反向代理。

在linux mint 15 下安装apache和nginx服务器,在apache的80端口的文档根目录下创建文件index.html,内容如下:

代码如下:

<html>

<head>

<title>index</title>

</head>

<body>

<h1>hello, i am apache</h1>

</body>

</html>

在nginx的8080端口的文档根目录下创建文件index.html,内容如下:

代码如下:

<html>

<head>

<title>index</title>

</head>

<body>

<h1>hello, i am nginx</h1>

</body>

</html>

创建源文件simple_reverse_proxy.py,内容如下:

代码如下:

#!/usr/bin/python

#-*-encoding:utf8-*-

'''

这是一个简单的反向代理服务器

'''

import basehttpserver

import urllib2

host_name = '127.0.0.1'

port_number = 8081 #端口

server_url=('http://127.0.0.1:80','http://127.0.0.1:8080')

server_choice = 0

class myhandler(basehttpserver.basehttprequesthandler):

def do_get(s):

"""response to a get request"""

global server_choice

url = server_url[server_choice]

print url

server_choice = (server_choice + 1) % 2

headers = {'user-agent': 'mozilla/4.0 (compatible; msie 5.5; windows nt)'}

try:

req = urllib2.request(url, none, headers)

response = urllib2.urlopen(req)

html = response.read()

#print html

s.send_response(200);

s.send_header("content-type", "text/html")

s.end_headers()

s.wfile.write(html)

except:

s.send_response(404);

s.send_header("content-type", "text/html")

s.end_headers()

s.wfile.write('<h2>404</h2>')

if __name__ == '__main__':

server_class = basehttpserver.httpserver

httpd = server_class((host_name, port_number), myhandler)

try:

httpd.serve_forever()

except keyboardinterrupt:

pass

httpd.server_close()

启动apache、nginx,并运行simple_reverse_proxy.py。我们在浏览器中打开 http://127.0.0.1:8081 ,我们可以看到:

刷新一下可以看到:

而simple_reverse_proxy.py会有以下信息输出:

代码如下:

bash >> ./simple_reverse_proxy.py

http://127.0.0.1:80

127.0.0.1 - - [05/sep/2013 19:25:02] "get / http/1.1" 200 -

http://127.0.0.1:8080

127.0.0.1 - - [05/sep/2013 19:25:43] "get / http/1.1" 200 -

当然,开源世界里已经有很多优秀的反向代理服务器了,例如nginx。

只要理解了反向代理的原理,更复杂的架构也容易去实现。

数据库的负载均衡

对于大型网站,一个数据库系统肯定会遇到无法负担大量的读请求、写请求的情况。那么我们怎么来通过负载均衡来实现高并发的读写请求呢?

这其中一个很好的方法就是读写分离:将原本针对一个数据库服务器的读写请求分成读请求和写请求,向一个(或者多个)数据库服务器发送写请求,向另外一个(或多个)服务器发送读请求,这可以明显的提高响应时间。不过其中有一个难点,就是必须保持多个数据库服务器中的数据是一致的,不用担心,很多数据库系统已经实现了这个功能。下面是一个架构示例:

上图中其实有一个写写冲突的问题,想象以下场景:

该系统用于存放某网站的用户注册信息,该网站不允许用户名相同,且以用户名为唯一主键,所以在单数据库架构中必须涉及到事务的处理。现在在这个负载均衡的数据库架构中,用户a要注册用户名为xiaoming,这个写请求分配给了db server 1;与此同时用户b同样注册用户名xiaoming,如果写请求分配给了db server1,就不会有问题发生,可是如果分配给db server 2呢?两个db server分别存放了不同用户的用户名相同的用户信息!解决的方法很简单,写请求的分配不能用随机算法,应该使用哈希映射,例如注册的用户名首字母为x时,写请求分配各 db server2,其他写请求一律分配给db server 1。

另外一个问题,这种架构为开发应用提供了很大的灵活性,就是这种架构不适用于某些orm框架,解决方法就是在这个架构上再加上一层——“数据库代理”。例如对于mysql,就有mysql proxy这样的解决方案。

您可能感兴趣的文章:

windows安装nginx部署步骤图解(反向代理与负载均衡)

nginx 作为反向代理实现负载均衡的例子

nginx 安装笔记(含php支持、虚拟主机、反向代理负载均衡)

以上是:解决理解web服务器和数据库的负载均衡以及反向代理问题的详细资料教程