您的位置:

zuul与nginx的区别

一、概述

zuul和nginx都是一种代理服务器,它们主要的目的都是将客户端请求转发到后端的服务器上。但是,它们之间还是有一些区别的。

二、负载均衡

nginx早期就引入了负载均衡的概念,它可以通过一些算法将请求分发到多台服务器上,从而降低单机的压力,提高反应速度。而zuul的负载均衡是在Netflix的Eureka上实现的,基于Ribbon和RestTemplate实现,在请求到达zuul后,zuul会向Eureka注册中心查询可用的服务,并选出一台最优的服务器,将请求转发到这台服务器上。

此外,在使用zuul实现负载均衡时,我们还需要在服务提供者中配置对应的注解。

    
        @RestController
        @RequestMapping("/api")
        public class ApiController {
            
            @Autowired
            private RestTemplate restTemplate;
            
            @ApiOperation("测试zuul的负载均衡")
            @GetMapping("/test")
            public String test() {
                return "This is from provider " + restTemplate.getForEntity("http://provider/test", String.class).getBody();
            }
        }
    

在上述代码中,我们可以看到,@Autowired注解引入了RestTemplate,这是实现负载均衡的核心组件,而restTemplate.getForEntity()方法中的URL参数中只写了服务的名称,比如"provider",而没有写具体的IP地址和端口号,这是因为要使用zuul的负载均衡功能。

三、动态路由

zuul相对于nginx的另一个优势在于它支持动态路由。在微服务中,如果有新的服务需要加入,或者某个服务需要下线,这个时候我们就需要修改nginx的配置文件并重启nginx,而这个过程可能比较繁琐。但是,在zuul中,我们只需要在Eureka上注册或者下线服务,zuul可以动态地检测这个变化,并相应地调整路由规则,从而实现自动化的服务发现和动态路由。

以下是一个实现了动态路由功能的zuul网关。

    
        @SpringBootApplication
        @EnableZuulProxy
        public class GatewayApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(GatewayApplication.class, args);
            }
        
            @Value("${spring.cloud.config.uri}")
            private String url;
        
            @Autowired
            private DiscoveryClient discoveryClient;
        
            @EventListener
            public void onApplicationEvent(ApplicationReadyEvent event) {
                refreshRoute();
            }
        
            @Scheduled(fixedRate = 60000)
            public void refreshRoute() {
                List
    instances = discoveryClient.getInstances("zuul");
                if (!instances.isEmpty()) {
                    ServiceInstance serviceInstance = instances.get(0);
                    String path = "/actuator/bus-refresh";
                    String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + path;
                    RestTemplate restTemplate = new RestTemplate();
                    restTemplate.postForEntity(url, null, null);
                }
            }
        }
    
   

上述代码实现了通过定时器定时向Eureka Server查询可用服务并更新路由规则。我们可以注意到,使用@EnableZuulProxy注解开启了zuul的代理功能,@Autowired引入了DiscoveryClient,它能查询Eureka上注册的服务。在事件监听方法onApplicationEvent()中,我们在应用启动时即刻启动一次路由刷新,以防重启zuul前Eureka上已有服务改变。在定时任务方法refreshRoute()中,我们通过RestTemplate发送POST请求以触发路由刷新。

四、动态访问日志

nginx在访问日志这个方面表现异常优秀,可以实时记录请求日志,并支持不同格式的日志输出。但是,在zuul这个框架中,要实现动态日志需要借助第三方工具。最常见的做法是结合Logstash和Elasticsearch,这样我们就可以把所有的请求日志都存储到Elasticsearch上,并通过Kibana进行可视化展示和分析。

以下是一个实现动态日志功能的zuul网关。

    
        #zuul配置文件
        zuul:
          routes:
            user:
              path: /user/**
              url: http://localhost:8080
            product:
              path: /product/**
              url: http://localhost:8081
          request:
            occlude-headers:
        
        #Logback日志配置文件
        
        
   
            
    
                
                
     
                    
      %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      
                
     
            
    
            
    
                
                
     ./logs/api-apm.log
     
                
     true
     
                
     
                    
      %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      
                    
      UTF-8
      
                
     
                
     
                    
      ./logs/%d{yyyy-MM-dd}/api-apm-%d{yyyy-MM-dd_HH}.log
      
                    
      7
      
                
     
            
    
            
    
                
     
                
     
            
    
        
   
        
        #Spring Boot启动类
        @SpringBootApplication(scanBasePackages = "com.example")
        @EnableZuulProxy
        public class GatewayApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(GatewayApplication.class, args);
            }
        
            @Bean
            public ConfigurableServletWebServerFactory configurableServletWebServerFactory() {
                TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
                factory.addConnectorCustomizers((connector -> {
                    AbstractHttp11Protocol protocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                    protocol.setCompression("on");
                    protocol.setCompressionMinSize(1024);
                    String[] mimeTypes = protocol.getCompressableMimeTypes();
                    List
    mimeList = new ArrayList<>(Arrays.asList(mimeTypes));
                    mimeList.add("application/json");
                    protocol.setCompressableMimeTypes(mimeList.toArray(new String[0]));
                }));
                return factory;
            }
        
            @Bean
            public PatternLayoutEncoder encoder() {
                PatternLayoutEncoder encoder = new PatternLayoutEncoder();
                encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
                encoder.setCharset(Charset.forName("UTF-8"));
                return encoder;
            }
        
            @Bean
            public LoggerFilter loggerFilter() {
                LoggerFilter loggerFilter = new LoggerFilter();
                loggerFilter.setAppenders("api-apm");
                loggerFilter.setAdditive(false);
                return loggerFilter;
            }
        
            @Bean
            public Logger logger() {
                Logger logger = (Logger) LoggerFactory.getLogger("com.netflix.zuul.monitoring.MonitoringHelper");
                logger.setLevel(Level.ERROR);
                return logger;
            }
        }
    
   

在上述代码中,我们使用Logback配置了日志相关信息,通过@EnableZuulProxy注解启用了zuul的服务代理功能。在@Bean注解的方法中,我们还配置了Tomcat的压缩策略和编码信息,以及zuul的日志过滤器和日志级别。

总之,zuul和nginx二者的优劣势都很明显,它们的选择要根据实际使用场景来判断。在微服务架构中,通常会使用zuul作为服务网关,以实现动态路由、负载均衡等功能。但是,在静态网页服务器、WEB路由、反向代理等方面,nginx的性能和稳定性都是值得称赞的。