APAHCE2.2实现负载均衡实战

来源:互联网 发布:安全事故数据统计 编辑:程序博客网 时间:2024/06/06 23:50

APAHCE2.2实现负载均衡实战

当今中型以上项目大都使用的WAS(Web Application Server)服务器集群, 以节约硬件资源和高可用性.为合理利用WAS服务器资源,让每个WAS服务器都承受相同的负载必需在前端架设负载均衡服务器, 有钱的公司都使用F5,L7等设备实现负载均衡, 而大多数项目还是选择用软件来实现负载均衡吧, 因为一台F5L7少说也要10W-20WRMB, 我个人不太迷信这硬件的能力, 它所带来性能提升和本文中用APACHE实现的负载均衡也相差无几.接下来我们就来看看怎么用APACHE来实现负载均衡.

环境: Linux操作系统 , apache, websphere应用服务器

 

APACHE相关插件: mod_proxy(代理模块), mod_proxy_http(代理模块的HTTP支持), mod_proxy_ajp(AJP协议支持, TOMCAT集群可以使用,可以减少网络交互量), mod_proxy_balancer(负载均衡支持).

 

相关下载地址:

APACHE2.2.15下载:http://httpd.apache.org/download.cgi

 

第一步, 编译安装APACHE

1.  解压缩 tar -zxvf apache_2.2.15.tar.gz

2.  ./configure --prefix=/usr/local/apache2 --enable-so --enable-ssl=static --with-ssl=/usr/local/ssl --enable-mods-shared="all" --with-mpm=worker --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util/

3.  make

4.  make install

5.  查看APACHE2安装目录的 modules下相关模块文件有没有生成 mod_proxy.so, mod_proxy_http.so, mod_proxy_ajp.so, mod_proxy_balancer.so. 如果没有生成可以使用APACHE自带的编译程序apxs来单独编译某个模块, : /usr/local/apache2/bin/apxs -i -c /tmp/httpd-2.2.15/modules/proxy/mod_proxy_balancer.c

 

第二步, 配置APAHCE

1.  httpd.conf 的修改

添加动态加载代理模块的语句

LoadModule proxy_module modules/mod_proxy.so

LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

LoadModule proxy_http_module modules/mod_proxy_http.so

去掉Include conf/extra/httpd-mpm.confInclude conf/extra/httpd-vhosts.conf前的注解#,让这两个包函文件生效, 我们的配置都分类在这几个配置文件中, 便于管理

2.  conf/extra/httpd-vhost.conf 中配置虚拟主机

 

#静态文件路径配置

DocumentRoot "/www/docs"

 

<Directory "/www/docs">

Options FollowSymLinks

AllowOverride None

Order allow,deny

Allow from all

Deny from env=IS_TRACE

</Directory>

 

DirectoryIndex index.html index.jsp index.htm

 

#设置代理类型为反向代理, 关闭正向代理

ProxyRequests Off

 

<VirtualHost *:80>

ServerAdmin yunfei90@hotmail.com

DocumentRoot /www/docs

DirectoryIndex index.html index.jsp

ServerName 127.0.0.1

#ProxyPass 路径 加个'!'号是让APACHE自已处理这个请求, 不转发到后台的服务器

ProxyPass /loadmanager !

ProxyPass /serverstatus !

#ProxyPassMatch 正则表达式版的 ProxyPass

ProxyPassMatch ^/(images|productImages|scripts|decorators|styles|download|sale/siteconfig)/ !

ProxyPassMatch ^(/.*/.exe|/.*/.ini)$ !

 

#这个是把以/开头的请求转发到集群ID balancer://ewallcluster/ 的集群中, balancer://是一个自定义协议

#stickysession 用于会话粘滞时使用的CookieID, 可以类似JSessionId.

ProxyPass / balancer://ewallcluster/ stickysession=BALANCEID nofailover=off

#ProxyPreserveHost 启用和禁用向后台集群转发主机头

ProxyPreserveHost On

#集群成员配置

<proxy balancer://ewallcluster/>

#route 用于和stickeysession配置实现会话粘滞. loadfactor是权重

BalancerMember http://192.168.100.41:9080 route=was1 loadfactor=1

BalancerMember http://192.168.100.43:9080 route=was2 loadfactor=1

BalancerMember http://192.168.100.45:9080 route=was3 loadfactor=1

BalancerMember http://192.168.100.47:9080 route=was4 loadfactor=1

BalancerMember http://192.168.100.31:9080 route=was5 loadfactor=1

</proxy>

 

#如果集群成员的端口号不与APACHE的端口号一致,重定向的页面就会失败, 加入下面这条配置就好了.

Header edit Location ^(.*):9080(.*) $1$2

#用于查看负载均衡的状态

<Location /loadmanager>

SetHandler balancer-manager

Order Deny,Allow

Deny from all

Allow from 192.168.100.63

Allow from 192.168.100.67

</Location>

 

<Directory "/www/docs">

Order Deny,Allow

Allow from all

</Directory>

 

</VirtualHost>

 

OK, 配置文件都搞定了, 但是当你访问页面的时候并没有正真的实现了会话粘滞, 在同一个会话中还会从was1跳到WAS2.如果网站是需要登录的那必需保证在一个会话中的所有请求都转发到同一台WAS服务器.我的解决办法是修改源代码.

 

, 修改源代码实现会话粘滞

 1, 修改mod_proxy_balancer.c 模块

删除或注解掉下面这断代码

if ((*route) && ((*route = strchr(*route, '.')) != NULL ))

        (*route)++;

 

修改access_status = rewrite_url(r, *worker, url);

/* Add the session route to request notes if present */下面的语句改成

if (route) {

        apr_table_setn(r->notes, "session-sticky", sticky);

        apr_table_setn(r->notes, "session-route", (*worker)->s->route);

 

        /* Add session info to env. */

        apr_table_setn(r->subprocess_env,

                       "BALANCER_SESSION_STICKY", sticky);

        apr_table_setn(r->subprocess_env,

                       "BALANCER_SESSION_ROUTE", (*worker)->s->route);

    } else {

        apr_table_setn(r->notes, "session-sticky", sticky);

        apr_table_setn(r->notes, "session-route", (*worker)->s->route);

 

        /* Add session info to env. */

        apr_table_setn(r->subprocess_env,

                       "BALANCER_SESSION_STICKY", sticky);

        apr_table_setn(r->subprocess_env,

                       "BALANCER_SESSION_ROUTE", (*worker)->s->route);

    }

 

2.  修改mod_proxy_http.c文件

添加一个函数:

 

static char *get_cookie_param(request_rec *r, const char *name)

{

    const char *cookies;

    const char *start_cookie;

 

    if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {

        for (start_cookie = ap_strstr_c(cookies, name); start_cookie;

             start_cookie = ap_strstr_c(start_cookie + 1, name)) {

            if (start_cookie == cookies ||

                start_cookie[-1] == ';' ||

                start_cookie[-1] == ',' ||

                isspace(start_cookie[-1])) {

 

                start_cookie += strlen(name);

                while(*start_cookie && isspace(*start_cookie))

                    ++start_cookie;

                if (*start_cookie == '=' && start_cookie[1]) {

                    /*

                     * Session cookie was found, get it's value

                     */

                    char *end_cookie, *cookie;

                    ++start_cookie;

                    cookie = apr_pstrdup(r->pool, start_cookie);

                    if ((end_cookie = strchr(cookie, ';')) != NULL)

                        *end_cookie = '/0';

                    if((end_cookie = strchr(cookie, ',')) != NULL)

                        *end_cookie = '/0';

                    return cookie;

                }

            }

        }

    }

    return NULL;

}

 

 

在以下语句

/* Now, add in the just read cookies */

            apr_table_do(addit_dammit, save_table, r->headers_out,

                         "Set-Cookie", NULL);

 

的下面加入如下代码:

 

//INSERT COOKIE

            {

              const char* route;

            const char* sticky;

            const char* balancer_route_change;

                sticky = apr_table_get(r->notes, "session-sticky");

                balancer_route_change = apr_table_get(r->subprocess_env, "BALANCER_ROUTE_CHANGED");

 

                if (balancer_route_change)

                  ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,

                                          "balancer_route_change=%s",

                                          balancer_route_change);

                if (sticky)

                  route = get_cookie_param(r, sticky);

 

                if ((!route) || strlen(route) == 0

                     || (balancer_route_change&&strncasecmp(balancer_route_change, "1", 1)==0) ) {

                  route = apr_table_get(r->notes, "session-route");

                    addit_dammit(save_table, "Set-Cookie", apr_pstrcat(r->pool, sticky , "=", route, "; Path=/", NULL));        

                  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,

                            "COOKIETEST:sticky=%s, route=%s",

                            sticky, route);

              }

               

            }