HaProxy学习笔记

5年前

简介


HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代 理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。


安装


安装介质


从HaProxy官方网站下载最稳定的发布版本(1.4.25)源码包;使用源码包的好处是可以在不同的Linux环境上进行编译安装。

haproxy-1.4.25.tar.gz

 

环境准备


HaProxy支持大多数的Linux OS, 我选择开源的操作系统Ubuntu Server 14.04(64Bites),当然选择SUSE或RadHat也没有问题。如果没有Linux环境,可以安装虚拟软件(如VMWare)创建虚拟机并安装操作系统,由于Ubuntu比较小巧,占用资源较少,比较适合在本机虚拟化环境中运行。当然,现在的PC配置较高一般的Linux OS可以安装几台都不成问题。


查看源码包下面的README文件,可以知道HAProxy所支持的OS:

  - linux22     for Linux 2.2

  - linux24     for Linux 2.4 and above (default)

  - linux24e    for Linux 2.4 with support for a working epoll (> 0.21)

  - linux26     for Linux 2.6 and above

  - linux2628   for Linux 2.6.28 and above (enables splice and tproxy)

  - solaris     for Solaris 8 or 10 (others untested)

  - freebsd     for FreeBSD 5 to 8.0 (others untested)

  - osx         for Mac OS/X

  - openbsd     for OpenBSD 3.1 to 5.2 (others untested)

  - aix52       for AIX 5.2

  - cygwin      for Cygwin

  - generic     for any other OS.

  - custom      to manually adjust every setting

 

安装过程


(1)    解压安装包

如果你的本地环境是Linux,那就直接解压安装包;或者使用的是虚拟机,则把安装包上传至虚拟机(可以使用Xftp软件或Linux scp命令);如果虚拟机可以连接Internet,也可以在虚拟机里直接下载HaProxy源码安装包;把准备好的源码安装包解压缩;

 


(2)    源码包目录结构

            

CHANGELOG : 版本变更信息,记录新增更能、BUG修改等信息

doc : 文档

example : 配置示例

tests : 测试用例(配置文件)

include : 依赖类库

ebtree : 类库

src : 源代码(c)

 

(3)    编译源码

与一般编译安装源码程序不同,HaProxy安装不需要执行configure操作,在其安装包根目录下可以发现不存在configure脚本;执行make命令编译源码;

make TARGET=linux26 PREFIX=/opt/programs/haproxy-1.4.25

PREFIX指定安装程序的根目录,如果不指定则安装到系统默认目录下,编译结束根目录下多了一个可执行的文件:haproxy,就是核心程序,执行该命令可以启动HaProxy进程(当然要先准备好配置文件)。

 


(4)    安装

执行make install安装编译产物。

查看安装结果:

配置


HAProxy源码安装包中带有配置示例和技术文档,可以参考学习。以下举例配置最常用的两种代理HTTP和TCP。

 

HTTP


环境准备

Apache-tomcat

192.168.226.128:8080

Apache-tomcat

192.168.226.129:8080

 

配置文件

global

   daemon

   maxconn 256

 

defaults

   mode http

   timeout connect 5000ms

   timeout client 50000ms

   timeout server 50000ms

 

listen http-in

   bind *:80

   server server1 192.168.226.128:8080 maxconn 32

   server server2 192.168.226.129:8080 maxconn 32

 

 

测试


先做一个简单的配置并测试。新建haproxy配置文件${haproxy.home}/conf/haproxy.cfg,输入上述配置内容后保存(配置文件可以任意命名,只要启动时指定配置文件路径即可 [-f ${cfgFilePath}])。执行${haproxy.home}/sbin/haproxy –f ${haproxy.home}/conf/haproxy.cfg启动haproxy进程。如果不知道命令参数,可以输入-h查看帮助信息。

 

执行${haproxy.home}/sbin/haproxy -f ${haproxy.home}/conf/haproxy.cfg启动haproxy进程;

 

编写一个JSP文件放入tomcat自带的example应用中(每个server里都放置一份),查看每次访问的server信息(可以在每个tomcat启动参数中加入不同的值-D${key}=${value},方便测试),JSP文件内容如下:

<%@pageimport="java.util.Properties"%>

<%@pageimport="java.net.InetAddress"%>

<%@pagelanguage="java"contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<%

InetAddress address = InetAddress.getLocalHost();

String hostAddress = address.getHostAddress();

String hostName = address.getHostName();

 

Properties props = System.getProperties();

 

%>

<!DOCTYPEhtmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<metahttp-equiv="Content-Type"content="text/html; charset=UTF-8">

<title>Test HAProxy HTTP mode</title>

</head>

<body>

   <spanstyle="colorblue;">ZhongWen.Li (lizw@primeton.com)</span>

   <tablewidth="100%"border="0.1">

      <thead>

        <tr>

           <thcolspan="2"align="center">Server information</th>

        </tr>

      </thead>

      <tbody>

        <tr>

           <td>SERVER ADDRESS</td>

           <td><%=hostAddress %></td>

        </tr>

        <tr>

           <td>SERVER NAME</td>

           <tdstyle="colorred;"><%=hostName %></td>

        </tr>

        <tr>

           <td>Session ID</td>

           <td><%=session.getId() %></td>

        </tr>

        <tr>

           <tdcolspan="2"align="center">System information</td>

        </tr>

        <%for (Object key : props.keySet()) { %>

        <tr>

           <td><%=key %></td>

           <td><%=props.get(key) %></td>

        </tr>

        <% } %>

      </tbody>

   </table>

</body>

</html>

 

 

直接访问应用容器1

 

直接访问应用容器2

 

通过HaProxy访问,不断刷新页面,由于请求比较少,配置的第一台server响应的几率比较高(HaProxy把大部分请求分发到第一台Server上);如果每个Server的处理能力不一样(例如硬件环境不同)可以配置每个Server的最大请求数,优先级(权重)等并结合分发策略来合理利用每个Server的处理能力。更多高级配置可以参考官方文档(安装包根目录下doc/configuration.txt以及示例配置examples)

 

 

关闭其中一台Server,并通过HAProxy地址不断请求,你会发现有时请求正常响应,有时会出现503 Service Unavailable错误。这是因为使用上述的配置,HaProxy不知道后面的Server状态,只是安装现有的请求分发策略去处理请求,如果发到正常运行的Server上则响应正常,否则出现503错误。解决这个问题很简单,只要给这些Server配置一个健康检查页面即可和健康检查时间间隔,建议配置一个小的静态页面(如果健康检查太频繁、响应页面太大会消耗网络流量);这样HaProxy发现后端Server服务不可用时,则不会把请求转发给他。(通常可以使用HaProxy+ Keepalived来做应用的高可用方案)

 

应用集群会遇到一个问题:如何保持各个Server的回话(session)一致。这一点,HaProxy无能为力,只能通过其他手段来实现。可以通过扩展应用容器的session实现,集中存储session信息(例如存储在Memcached上),Jetty、Tomcat有很多开源的共享session实现。

 

TCP

环境准备


VMWare RabbitMQ

192.168.226.128:5672

VMWare RabbitMQ

192.168.226.129:5672

 

配置文件


global

   daemon

   maxconn 256

 

defaults

   mode tcp

   timeout connect 5000ms

   timeout client 50000ms

   timeout server 50000ms

 

listen rabbitmq

   bind *:8001

   server server1 192.168.226.128:5672 maxconn 32

   server server2 192.168.226.129:5672 maxconn 32    

 

 

测试


使用rabbitmq-java客户端API编写测试代码。

 

package org.amqp.dev.test;

 

import com.rabbitmq.client.Channel;

import com.rabbitmq.client.Connection;

import com.rabbitmq.client.ConnectionFactory;

import com.rabbitmq.client.QueueingConsumer;

 

public class MessageConsumer {

   

    private final static String QUEUE_NAME = "hello_world";

   

    private static String SERVER_HOST_1 = "192.168.226.128";

    private static String SERVER_HOST_2 = "192.168.226.129";

   

    private static int SERVER_1_PORT = 5672;

    private static int SERVER_2_PORT = 5672;

   

    private static String HAPROXY_HOST = "192.168.226.128";

    private static int HAPROXY_PORT = 8001;

   

   

    public static void main(String[] args) throws Exception {

       // 新建连接工厂

       ConnectionFactory factory = new ConnectionFactory();

       factory.setHost(SERVER_HOST_1);

//     factory.setHost(SERVER_HOST_2);

//     factory.setHost(HAPROXY_HOST);

       

       factory.setVirtualHost("/");

       factory.setPort(SERVER_1_PORT);

//     factory.setPort(SERVER_2_PORT);

//     factory.setPort(HAPROXY_PORT);

      

       factory.setUsername("guest");

       factory.setPassword("guest");

      

       // 新建连接

       Connection connection = factory.newConnection();

      

       // 建立通道

       Channel channel = connection.createChannel();

      

       // 重复声明队列,如果存在该队列且声明的参数与现在队列的参数一致则不会出错否则异常

       channel.queueDeclare(QUEUE_NAME, false, false, false, null);

      

       System.out.println("Waiting for messages.");

      

       // 新建消息接收器

       QueueingConsumer consumer = new QueueingConsumer(channel);

        channel.basicConsume(QUEUE_NAME, true, consumer);

   

        boolean flag = true;

        while (flag) {

          QueueingConsumer.Delivery delivery = consumer.nextDelivery(/*可以传入一个超时时间,否则死等*/);

          String message = new String(delivery.getBody());

          System.out.println("Received '" + message + "'");

          // TODO biz

        }

   

        channel.close();

        connection.close();

    }

 

}

 

在Eclipse中使用Debug方式运行MessageConsumer:


从Debug视图中可以看到长连接的线程


从rabbitmq_management可以看到客户端连接;192.168.226.1:56423是rabbitmq java客户端在我的本地开启的一个端口;下面我们在更改连接方式,通过HaProxy连接rabbitmq。

编写HaProxy配置文件${haproxy.home}/conf/rabbitmq.cfg,输入上述配置后保存;执行${haproxy.home}/sbin/haproxy –f ${haproxy.home}/conf/rabbitmq.cfg 启动HaProxy进程;修改MessageConsumer代码,使用HaProxy的主机和端口:

 

在Eclipse中使用Debug方式运行MessageConsumer:


从Debug视图看到的连接线程显示的是HaProxy服务端口;


从rabbitmq_management可以看到客户端连接;但显示的客户端地址不是我本地的,而是HaProxy的地址。

可以编写测试类创建很多Connection,会发现和之前测试HTTP模式一样,他会连接到不同的Server上;这样我们就可以使用HaProxy来做负载。(rabbitmq可以搭建集群环境)

 

监控


可以通过配置listen监控HaProxy后端服务状态:

listen admin

   bind 0.0.0.0:11111

   mode http

   stats refresh 5s#刷新时间间隔

   stats uri /admin访问地址

   stats auth admin:admin登陆账户密码


 

需要为Server配置健康检查才能显示状态。

 

关于配置


上述示例使用的是listen模块配置,也可以使用frontend(端口,引用的backend等)+ backend(后端服务)模块配置;

    global

        daemon

        maxconn 256

 

    defaults

        mode http

        timeout connect 5000ms

        timeout client 50000ms

        timeout server 50000ms

 

    frontend http-in

        bind *:80

        default_backend servers

 

    backend servers

        server server1 127.0.0.1:8001 maxconn 32

server server1 127.0.0.1:8002 maxconn 32

 

 

每个配置文件可以配置多个listen,但不能配置一样的端口;虽然可以配置多组,但不建议这么做,可以编写多个配置文件,分别为这些配置文件启动HaProxy进程完成,各个HaProxy独立运行,需要更新集群URL列表时(应用伸缩,应用迁移等)可以停止而不会影响其他应用。在使用HaProxy+keepalived做高可用方案时,可以主备先后停机更新配置做到服务不中断。

 

结论


本文讲述了HaProxy的入门,利用简单的配置测试HaProxy的负载功能,更多高级的配置需要结合应用场景来配置测试。可以通过学习HaProxy的文档和示例掌握更多的配置技巧。

 

 

COMMENTS

1 个回应

Normal

zipu888 2014年07月12日 12:57

ding

回复


需要 后方可回复
如果没有账号可以 一个帐号。