【问题标题】:Logging response time of Zulu Proxy Request记录 Zulu 代理请求的响应时间
【发布时间】:2025-12-22 20:05:11
【问题描述】:

我们希望捕获由 Zuul 代理服务器处理的每个请求的响应时间,以用于性能监控。 Zuul 过滤器似乎是这样做的合乎逻辑的方式,但考虑到 Zuul 过滤器的结构,似乎不是一种简单的方法来捕获经过的时间。 谁能阐明我们如何实现这一目标?

【问题讨论】:

    标签: java proxy netflix-zuul


    【解决方案1】:

    我还努力使用 Zuul 过滤器来获取基本指标。

    Spring Actuator trace 提供了很多开箱即用的信息。只需使用“/trace”查看:

    • 时间戳
    • 耗时
    • HTTP 状态代码

    它非常适合 Zuul

    [
        {
            "timestamp": 1499429507097,
            "info": {
                "method": "GET",
                "path": "/index.html",
                "headers": {
                    "request": {
                        "host": "localhost:8765",
                        "connection": "keep-alive",
                        "upgrade-insecure-requests": "1",
                        "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/58.0.3029.110 Chrome/58.0.3029.110 Safari/537.36",
                        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
                        "accept-encoding": "gzip, deflate, sdch, br",
                        "accept-language": "en-US,en;q=0.8",
                        "cookie": "zbx_sessionid=02ac46186474dbd668d7abe0f78705c9"
                    },
                    "response": {
                        "X-Application-Context": "application:8765",
                        "Last-Modified": "Fri, 07 Jul 2017 10:52:42 GMT",
                        "Cache-Control": "no-store",
                        "Accept-Ranges": "bytes",
                        "Content-Type": "text/html",
                        "Content-Length": "446",
                        "Date": "Fri, 07 Jul 2017 12:11:47 GMT",
                        "status": "200"
                    }
                },
                "timeTaken": "3"
            }
        },
    

    然而,标准的InMemoryTraceRepository 给了我关于“/health”甚至“/trace”的统计信息,但我只对POSTS感兴趣/strong> 去 Zuul。所以我只是扩展了InMemoryTraceRepository 并将其作为@Bean 提供。

    import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
    import org.springframework.boot.actuate.trace.Trace;
    
    public class ZuulInMemoryTraceRepository extends InMemoryTraceRepository {
    
      public ZuulInMemoryTraceRepository(int maxSize) {
        setCapacity(maxSize);
      }
    
      public Collection<DateTimeTaken> getStats(){
        return fifo;
      }
    
      public void setReverse(boolean reverse) {
        super.setReverse(reverse);
      }
    
      @Override
      public void setCapacity(int capacity) {
        super.setCapacity(capacity);
      }
    
      @Override
      public List<Trace> findAll() {
        return super.findAll();
      }
    
      @Override
      public void add(Map<String, Object> map) {
    
        Object method = map.get("method");
        if (!"POST".equals(method)) {
          return;
        }
        Object timeTaken = map.get("timeTaken");//timeTaken is a String
        //log timeTaken
        super.add(map);
      }
    }
    

    在我的@Configuration 中我添加了:

    @Bean
    public ZuulInMemoryTraceRepository myZuulInMemoryTraceRepository() {
      return new ZuulInMemoryTraceRepository(10000);
    }
    

    或者,您可以将自定义对象添加到 ZuulInMemoryTraceRepository 中固定大小的 EvictingQueue。最后公开一个安静的 web 服务来公开一个 EvictingQueue,比如我的 getStats()。然后可以使用此 json 绘制漂亮的响应时间图。

    @Override
    public void add(Map<String, Object> map) {
      super.add(map);
      Object method = map.get("method");
      if (!"POST".equals(method)) {
        return;
      }
      Object timeTaken = map.get("timeTaken");//timeTaken is a String
      if (timeTaken != null) {
        synchronized (fifo) {
          //Make your own DateTimeTaken
          fifo.add(new DateTimeTaken(new Date(), timeTaken.toString()));
        }
      }
    }
    

    在我的统计数据中@RestController:

    @Autowired
    ZuulInMemoryTraceRepository zuulInMemoryTraceRepository;
    
    @RequestMapping("/stats")
    public Collection<DateTimeTaken> getAll() {
      return zuulInMemoryTraceRepository.getStats();
    }
    

    【讨论】: