这里的“负载均衡”是指在网站建设中应该考虑的“负载均衡”。假设我们要搭建一个网站:aaa.me,我们使用的web服务器每秒能处理100条请求,而aaa.me这个网站最火的时候也只是每秒99条请求,那么我们使用一个服务器是完全可以的。

但是若该网站平均每秒的请求是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这样的解决方案。

理解web服务器和数据库的负载均衡以及反向代理的更多相关文章

  1. [Web] 如何实现Web服务器和应用服务器的负载均衡?

    本文对Web服务器和应用服务器的负载均衡进行说明. 在负载均衡的思路下,多台服务器为对称方式,每台服务器都具有同等的地位,可以单独对外提供服务而无须其他服务器的辅助.通过负载分担技术,将外部发送来的请 ...

  2. nginx高性能WEB服务器系列之六--nginx负载均衡配置+健康检查

    nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...

  3. Nginx可以说是标配组件,但是主要场景还是负载均衡、反向代理、代理缓存、限流等场景;而把Nginx作为一个Web容器使用的还不是那么广泛。

    Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛. 用Nginx+Lua(OpenResty)开发高性能Web ...

  4. 查找“CDN、负载均衡、反向代理”等大型网络真实IP地址的方法

    首先,CDN.负载均衡.反向代理还分为很多层,有时查出来的是最外层的 CDN 服务器群,真实的机器是不对外开放的,类似这样的: 用户 → CDN 网络 → 一台或多台真实机器 ↗ CDN Server ...

  5. CentOS中实现Nginx负载均衡和反向代理

    一.安装必要软件 负载均衡服务器:IP设置为192.168.1.10 Web服务器1:安装Apache或者Nginx,IP设置为192.168.1.11: Web服务器2:安装Apache或者Ngin ...

  6. nginx负载均衡和反向代理有什么区别

    近在研究nginx的负载均衡和反向代理,先看下这两个简单的配置吧! 负载均衡 worker_processes 1; events { worker_connections 1024; } http{ ...

  7. Nginx(六):Nginx HTTP负载均衡和反向代理的配置与优化

    一.什么是负载均衡和反向代理 随着网站访问量的快速增长,单台服务器已经无法承担大量用户的并发访问,必须釆用多台服务器协同工作,以提高计算机系统的处理能力和计算强度,满足当前业务量的需求.而如何在完成同 ...

  8. 【架构师之路】Nginx负载均衡与反向代理—《亿级流量网站架构核心技术》

    本篇摘自<亿级流量网站架构核心技术>第二章 Nginx负载均衡与反向代理 部分内容. 当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台.几十台.几百台.然而,用 ...

  9. nginx的负载均衡和反向代理

    本文介绍一些负载均衡和反向代理的一些基本概念,然后介绍如何基于nginx实现,包括两种安装nginx的方法:yum安装和源码安装,以及ngix该如何配置等. 什么是负载均衡? 概念 负载均衡是高可用网 ...

随机推荐

  1. 领扣(LeetCode)删除注释 个人题解

    给一个 C++ 程序,删除程序中的注释.这个程序source是一个数组,其中source[i]表示第i行源码. 这表示每行源码由\n分隔. 在 C++ 中有两种注释风格,行内注释和块注释. 字符串// ...

  2. Hook原理--逆向开发

    今天我们将继续讲解逆向开发工程另一个重要内容--Hook原理讲解.Hook,可以中文译为“挂钩”或者“钩子”,逆向开发中改变程序运行的一种技术.按照如下过程进行讲解 Hook概述 Hook技术方式 f ...

  3. 从壹开始 [ Design Pattern ] 之二 ║ 单例模式 与 Singleton

    前言 这一篇来源我的公众号,如果你没看过,正好直接看看,如果看过了也可以再看看,我稍微修改了一些内容,今天讲解的内容如下: 一.什么是单例模式 [单例模式],英文名称:Singleton Patter ...

  4. 论文阅读:Face Recognition: From Traditional to Deep Learning Methods 《人脸识别综述:从传统方法到深度学习》

     论文阅读:Face Recognition: From Traditional to Deep Learning Methods  <人脸识别综述:从传统方法到深度学习>     一.引 ...

  5. java运算符详解

    java运算符: 定义:用来指明对于操作数的运算方式 按照操作数数目分类: 单目运算    数目运算    三目运算 a++              a+b           (a>b) ? ...

  6. [译]Nginx入门引导教程

    本文为[Beginner's Guide]译文,原文地址:http://nginx.org/en/docs/beginners_guide.html Guide 本教程基础的介绍了 nginx,以及能 ...

  7. React源码 React.Children

    children是什么意思呢?就是我们拿到组件内部的props的时候,有props.children这么一个属性,大部分情况下,我们直接把 props.children 渲染到 JSX 里面就可以了. ...

  8. Flask入门学习——自定义一个url转换器

          我们知道,flask的url规则是可以添加变量部分的,这个参数变量是写在尖括号里的,比如:/item/<id>/,如果需要指出参数的类型要符合<converter:vai ...

  9. jvm垃圾回收器与内存分配策略

    一.判断对象存活的算法 1.引用计数算法 (1)概念:给对象中添加一个引用计数器每当有一个地方引用它时,计数器值加1:当引用失效时,计数器就减1:任何时刻计数器为0的对象就是不可能再被使用的. (2) ...

  10. typedef & #defiine & struct

    #define(宏定义)只是简单的字符串代换(原地扩展),它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了. typedef是为了增加可读性而为标识符另起的新名称(仅仅只是个别名), ...