atwood-pan

 

Nginx学习

一、概述

1.nginx是什么?

是一个高性能的反向代理服务器、还是一个负载均衡服务器

特点:在高并发和处理静态资源上相对于tomcat有更多优势.

  • 什么是反向代理

    • 正向代理:客户端发送请求到代理服务器,代理服务器将请求转发至原始服务器。代理服务器所代理的对象是很多个客户端。

    • 反向代理:对于客户而言反向代理就像原始服务器,客户不需要作任何设置,客户端发送请求,直接发送到代理服务器,代理服务器判断向何处转发请求,并将获得的内容返回给客户端。反向代理是对多个服务器进行代理

  • 什么是负载均衡

    可以按照调度规则实现动态、静态页面分离,可以按照轮询、ip哈希、权重等多种方式实现将请求平均分配到后端服务器上

2.搭建服务器

  • 网址:nginx.cn

    四个软件下载方法:

    1. wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.38.tar.gz
    2. wget http://zlib.net/zlib-1.2.11.tar.gz
    3. wget http://www.openssl.org/source/openssl-1.0.1j.tar.gz
    4. wget http://nginx.org/download/nginx-1.11.1.tar.gz
    5. yum -y install gcc-c++
    
  • 安装pcre

    • 安装c++编译器:yum -y install gcc-c++

    • 创建目录:mkdir /opt/module/nginx

    • 解压:tar -zxvf /opt/software/nginx/pcre-8.38.tar.gz -C /opt/module/nginx/

    • 进入pcre目录,

      ./configure ,默认安装在/usr/lcal目录

    • make&&make install—安装到指定位置

  • openssl安装

    • tar -zxvf /opt/software/nginx/openssl-1.0.1j.tar.gz -C /opt/module/nginx/

    • 进入openssl目录,

      ./config

    • make&&make install

  • zlib安装

    • tar -zxvf /opt/software/nginx/zlib-1.2.11.tar.gz -C /opt/module/nginx/
    • 进入zlib目录,./configure
    • make&&make install
  • nginx安装
    • tar -zxvf /opt/software/nginx/nginx-1.11.1.tar.gz -C /opt/module/nginx/
    • 进入nginx目录,./configure
    • make&&make install,默认安装在/usr/local目录中
  • 创建下面两个软链接
    • ln -s /usr/local/lib/libpcre.so.1 /lib
    • ln -s /usr/local/lib/libpcre.so.1 /lib64
  • 启动服务:/usr/local/nginx/sbin目录中执行./nginx
  • 测试:在浏览器输入虚拟机ip应该能看到欢迎界面
  • 停止服务:./nginx -s stop
  • 重启服务:./nginx -s reload
  • 向服务器中传文件:alt+p–>进入sftp,cd到要传入的路径,如cd /opt/module/apache-tomcat-8.5.51/webapps/–>把文件直接拖入

二、配置文件

进入/usr/local/nginx/conf下,打开nginx.conf

##1.负载均衡

include       mime.types;---包含文件,该文件中列出了nginx所支持的媒体类型
default_type  application/octet-stream;---会让浏览器认为响应是普通文件流,并提示用户下载
keepalive_timeout  65;---处理完一次响应后,连接被保持的时间

server {       
		listen      8089;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
			proxy_pass http://tc;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
    
    upstream tc{
		#ip_hash;
		server 192.168.1.180:80 weight=1 backup;
		server 192.168.1.180:8080 weight=3;
	}	
	轮询:这是默认的策略,就是一个一个的按顺序提供服务.
	weight:权重,对于静态资源,如html,jpg,在访问过后,nginx会缓存这些数据,再次访问时,会直接从nginx获取,不再访问服务器
	backup:表示该服务器平时不用,其它服务器挂掉才启用,跟ip_hash会冲突
	ip_hash:会根据用户的ip来决定由哪台服务器执行请求
	
	启动linux的tomcat:./catalina.sh run

2.动静分离

2.1 什么是动静分离

让静态资源(image,html,js,css)跟动态资源分布在不同的服务器上,这种技术叫动静分离

2.2 实现步骤

  • 在配置文件中添加

    ./指的是当前目录

    location ~.*\.(html|js|png|css|jpg|gif) {
     root ./;
    }  
    
  • 在/usr/local/nginx目录中分别创建img目录,1.html文件放入html目录中,ng.gif图片放入img目录

  • 创建两个springboot项目

    • 导入依赖

      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      
      <dependency>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      
    • 添加控制器类

      @Controller
      public class NC {
      	@RequestMapping("/test")
      	@ResponseBody
          public String t1(){
              return "负载均衡-----this is boot1";
          }
          @RequestMapping("/showHtml")
          public String t2(){
              return "show";
          }
      }
      
    • 两个端口号一个是80,一个是8080

    • 在templates目录中添加show.html

      <h1>动静分离</h1>
      <img src="img/ng.gif"><br>
      <a href="html/1.html">this is session1 html</a>
      
  • 测试http://192.168.188.100/test

2.3可能遇到的问题

无法访问到资源:这边要使用重定向,而不能使用默认的或者转发跳转
/**
     * 获取用户名与密码,用户登录
     * @return 登录成功页面
     */

    @RequestMapping(value = {"/userLogin"})
    public String userLogin(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            HttpServletRequest request){

        if(StringUtils.isEmpty(username)){
            return "用户名不能为空";
        }

        if(StringUtils.isEmpty(password)){
            return "密码不能为空";
        }

        User user = userLoginService.userLogin(username,password);

        if(user != null){                                                  //登录成功
            request.getSession().setAttribute("session_user",user);     //将用户信息放入session  用于后续的拦截器
            return "redirect:product";

        }
        return "登录失败,用户名或密码错误";
    }
    @RequestMapping("/product")
    public String toProduct(){
        return "product";
    }

三、session共享

什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录

1.ip_hash

缺点:

  • 分配不均匀。
  • 如果后端还作了其他负载均衡,就不能共享session

2.tomcat会话复制

会话数据会存储在每个服务器上的堆内存中

2.1 实现步骤

  • 在每一个tomcat中添加集群缓存配置

    在tomcat的conf中找到server.xml,在这一行下面添加下面内容:

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8">
      <Manager className="org.apache.catalina.ha.session.DeltaManager"
                 expireSessionsOnShutdown="false"
                 notifyListenersOnReplication="true"/>
      <Channel className="org.apache.catalina.tribes.group.GroupChannel">
          <Membership className="org.apache.catalina.tribes.membership.McastService"
                address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/>
          <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
      address="auto" port="4000" autoBind="100" selectorTimeout="5000" maxThreads="6"/>
        <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">       <Transport       className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
        </Sender>
         <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
         <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
        </Channel>
        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>
        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
        <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
            tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/"
            watchDir="/tmp/war-listen/" watchEnabled="false"/>
        
        <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
    </Cluster>
    
  • 在每个项目的web.xml中添加下面标签

    <distributable/>
    

2.2 缺点

  • 因为每个服务器都存储一份session,所以数据冗余
  • 如果某个服务器内存很小,可能无法存储。

3.会话共享

推荐使用Spring Session方案,主流, 会话存储在远程的redis缓存中.

3.1 实现原理

  • 客户端第一次发请求时,没有携带sessionID,nginx将请求分发给服务器1 ,然后服务器1 产生原始session,spring 对原始sesion封装成RedisSession,并对原始session的id进行base64编码产生一新id,新id作为key,RedisSession作为value, 放入redis中,然后原始session的ID回写到浏览器,这样服务器1 和redis中都会有一个相同的RedisSession

  • 当客户端发送第二次请求的时候,nginx将请求分发给服务器2 (无session),因为请求中携带了一个sessionID,那么服务器2 就根据sessionID重新编码得出RedisSession的id,用这个id去redis中获取RedisSession[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kQcPz7cG-1634974473270)(picture\redis_session共享.png)]

  • 面试题,封装的session对象所属的类叫什么?

    参考DefaultCookieSerializer-->readCookieValues方法
    封装的Session类型为HttpSessionAdapter,伪代码表示关系如下:
    HttpSessionAdapter
    	//有属性如下
    	RedisSession session;
    	
    	
    

3.2 实现步骤

建两个springboot项目,内容如下,除了端口号不同

  • 两个项目的pom依赖

    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
      <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
        <version>2.0.4.RELEASE</version>
      </dependency>
    </dependencies>
    
  • templates目录添加login.html

    <form action="/login" method="post">
        <input name="username"><br>
        <input type="submit">
    </form>
    
  • templates目录添加success.html

        <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
        <h1>this is session1</h1>
        <span th:text="${session.username}"></span>
    
  • yml内容如下,注意:另一项目端口为8080

    server:
      port: 80
    spring:
      redis:
        host: 192.168.188.100
        port: 6379
        jedis:
          pool:
            max-idle: 8
    
  • config包下添加类

    @Configuration
    public class MyConfig implements WebMvcConfigurer {
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/showSuc").setViewName("success");
            registry.addViewController("/showLogin").setViewName("login");
        }
    }
    
  • controller包中添加类

    @Controller
    public class UserCtl {
    @RequestMapping("/login")
    public String hello(HttpSession session, String username){
        session.setAttribute("username",username);
        //注意:这里的session已不是传统session,被重构成新的session,存储在redis中
        System.out.println("name:"+username+",sessionID:"+session.getId());
        return "success";
    }
    }
    
  • 主类添加注解

    //使用该注解,会重构session,参数为session存活时间,默认1800秒,注意:如果在30秒如果有访问,则过期时间会自动设置成30秒
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)
    @SpringBootApplication
    public class SessionApp {
    public static void main(String[] args) {
        SpringApplication.run(SessionApp.class,args);
    }
    }
    
  • nginx中

    • 修改配置

        upstream tc{
          server 192.168.1.144:80;
          server 192.168.1.144:8080;
        }
      
    • 重启nginx

    /usr/local/nginx/sbin/nginx -s reload

  • 启动redis: redis-server redis.conf

  • 启动80和8080两个端口的项目

  • 测试

    • 浏览器输入192.168.188.100/showLogin,输入用户名

    • 192.168.188.100/showSuc,反复刷新观看

posted on 2021-10-23 15:37  JavaCoderPan  阅读(5)  评论(0编辑  收藏  举报  来源

导航