tomcat负载渣渣?ngnix+tomcat+redis实现动静分离,负载均衡,session共享

本文的内容比较复杂,设计的技术点有很多,所以不会详细的一一列出,只以主线流程为主,希望能给大家带来思路

java程序员最熟悉的服务器就属于tomcat服务器了,

众所周知,tomcat就算再优化,单个服务器的负载能力和并发能力都是很弱的,

但是这不代表你运行tomcat服务器的服务器主机的能力就是如此了(也就是说如果你的项目是基于tomcat搭建的,那么可以通过一些手段来提高服务器的访问能力)

因为一个tomcat同时承受的连接数有限,但是此时服务器主机的空闲进程可能还有很多,为了最大化的提高服务器主机利用率

分布式的服务器搭建模式就应运而生了

简单介绍一下分布式的结构,先看图


用最好理解的语言说,就是在一个服务器主机上使用一个负载能力超强的服务器来接受所有的请求,但是他不去处理每一条请求,他的作用是把这些请求分成n个去向,把他们对应的转到另一个服务器来处理具体的请求动作,也就是相当于机场的安检,旅客们就相当于来自各个电脑和手机的请求,他们的目的都是进入候机大厅,然而想要过安检的话如果只有一个安检通道就必须等待一个一个顺序过安检,这样速度很慢,那么就变成n个安检通道一起去做安检,这样同时处理的人数就增加了,安检就相当于负载服务器,他可以把请求分流并指向多个tomcat这样来实现增加服务器的访问量

那么这个架构需要的东西

首先是nginx服务器(用来做负载服务器,也就是安检)

然后是tomcat和项目

有了这两个以后我们分析一下

这个结构就是

比如在80端口启动ngnix

那么我们可以在8080 和 8081分别启动两个tomcat,正常这个就代表了两个项目,

但是ngnix的特点是转发请求后使用的还是nginx的路径

所以如果是多个tomcat我们还可以进一步优化就是把项目的图片,css,js等静态资源都放在nginx上

由于多个tomcat只是用来分压的,那么使用一套静态资源就可以节省很多空间

先看一下nginx的配置

安装步骤掠过

http {
    #扩展名与文件类型映射表
    include       mime.types;
    #默认类型
    default_type application/octet-stream;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #日志
    access_log /usr/local/var/log/nginx/access.log;
    error_log /usr/local/var/log/nginx/error.log;
    #gzip 压缩传输
    gzip on;
    gzip_min_length 1k;  #最小1K
    gzip_buffers 16 64K;
    gzip_http_version 1.1;
    gzip_comp_level 6;
    gzip_types text/plain application/x-javascript text/css application/xml 	application/javascript;
    gzip_vary on;
    #负载均衡组
    upstream web_app {   
 	server 127.0.0.1:9080 weight=1 max_fails=2 fail_timeout=30s;   
 	server 127.0.0.1:9081 weight=1 max_fails=2 fail_timeout=30s;   
    } 
    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
           proxy_next_upstream http_502 http_504 error timeout invalid_header;   
	    proxy_set_header Host  $host:80;   
	    proxy_set_header X-Real-IP $remote_addr;   
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   
 	    proxy_pass http://web_app;   
  
        }
	#静态资源存放目录(项目的静态资源可以全部放在这里)
	location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$   
	{   
   
		root /usr/local/etc/nginx/html;  
		expires      3d;   
	} 
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    server{
        server_name localhost;
        listen 443 ssl;
        root html;
        location / {
            proxy_next_upstream http_502 http_504 error timeout invalid_header;   
	    proxy_set_header Host  $host:80;   
	    proxy_set_header X-Real-IP $remote_addr;   
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   
 	    proxy_pass http://web_app;  
        }
        ssl on;
        ssl_certificate conf/ssl/client.pem;
        ssl_certificate_key conf/ssl/client.key.unsecure;
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}

这里有一步是配置https协议的,在这里就不多说了,有兴趣的可以去搜索一下其他的地方有详细的讲解

接下来就是在对应的端口创建两个tomcat服务器

项目是一个ssm的后台权限系统





这些准备工作的具体细节就不介绍了,以流程为主

这个时候启动nginx和tomcat

可以访问localhost


我们可以尝试一下登录

会发现无法登陆了,

因为,默认项目的拦截系统是以session为主的

由于服务器变成了分布式形式,每个tomcat的session是不互通的,

那么由于我们访问的都是一个nginx感觉不到有区别,其实我们每次访问的时候他会轮流把请求转发到后面的其中一个tomcat上

也就是说可能登录的时候我们访问的是tomcat1

转到登录验证时就访问tomcat2,再转向可能又回到了1,这样的话带来的情况就是session是保存不上的,我们每次访问的时候sessionid都会发生变化

这样登录就无法进行了,

所以这里需要我们进行另一个任务

就是想办法把不同的session同步到一起,这样就能实现跨服务器保持登录状态

这里需要的就是redis和springsession了

首先是依赖包

	<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.1</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
		  <groupId>org.springframework.session</groupId>
		  <artifactId>spring-session-data-redis</artifactId>
		  <version>1.2.1.RELEASE</version>
		</dependency>
		<dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.5.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.3.1.RELEASE</version>
        </dependency>

然后我们需要的就是

安装redis,配置springsession

安装redis这步省略

在applicationContext上配置如下

	<bean id="redisHttpSessionConfiguration"
	      class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
	    <property name="maxInactiveIntervalInSeconds" value="600"/>
	</bean>
	
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
	    <property name="maxTotal" value="100" />
	    <property name="maxIdle" value="10" />
	</bean>
	
	<bean id="jedisConnectionFactory"
	      class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
	    <property name="hostName" value="192.168.50.168"/>
	    <property name="port" value="6379"/>
	    <property name="password" value="" />
	    <property name="timeout" value="3000"/>
	    <property name="usePool" value="true"/>
	    <property name="poolConfig" ref="jedisPoolConfig"/>
	</bean> 


web.xml中配置如下

  <filter>
	  <filter-name>springSessionRepositoryFilter</filter-name>
	  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
	  <filter-name>springSessionRepositoryFilter</filter-name>
	  <url-pattern>/*</url-pattern>
  </filter-mapping>

这两个地方配置好以后spring就可以帮助我们把session持久化到redis中

这样的话不论在拿个服务器上,我们都可以在redis中拿到当前登录的信息

实现了session的共享


这两项配置完毕以后在做登录验证等环节都与正常无异

springSessionRepositoryFilter
这个过滤器会自动拦截我们的请求并且在他的方法中处理session

所以我们可以像单服务器一样去操作session

这样就完成了既解决了负载问题,又可以像单服务器一样进行开发,从而最大化的利用了服务器主机的资源提高了项目的负载能力

具体的代码有时间我会放到git上,

git地址 https://github.com/keaderzyp


猜你喜欢

转载自blog.csdn.net/keader01/article/details/79240073