zoukankan      html  css  js  c++  java
  • netflix zuul 1.x与zuul2.x之比较

    1.zuul 1.x的架构如下所示:

    线程模型:

    其web应用的web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
      
        <listener>
            <listener-class>com.netflix.zuul.StartServer</listener-class>
        </listener>
    
        <servlet>
            <servlet-name>ZuulServlet</servlet-name>
            <servlet-class>com.netflix.zuul.http.ZuulServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>ZuulServlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
        <filter>
            <filter-name>ContextLifecycleFilter</filter-name>
            <filter-class>com.netflix.zuul.context.ContextLifecycleFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>ContextLifecycleFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
      
    </web-app>

    从上面可以看出,启动时有三个主类:

    1.1. StartServer

        @Override
        public void contextInitialized(ServletContextEvent sce) {
            logger.info("starting server");
    
            // mocks monitoring infrastructure as we don't need it for this simple app
            MonitoringHelper.initMocks();
    
            // initializes groovy filesystem poller
            initGroovyFilterManager();
    
            // initializes a few java filter examples
            initJavaFilters();
        }

    1.2. ZuulServlet

    @Override
        public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
            try {
                init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
    
                // Marks this request as having passed through the "Zuul engine", as opposed to servlets
                // explicitly bound in web.xml, for which requests will not have the same data attached
                RequestContext context = RequestContext.getCurrentContext();
                context.setZuulEngineRan();
    
                try {
                    preRoute();
                } catch (ZuulException e) {
                    error(e);
                    postRoute();
                    return;
                }
                try {
                    route();
                } catch (ZuulException e) {
                    error(e);
                    postRoute();
                    return;
                }
                try {
                    postRoute();
                } catch (ZuulException e) {
                    error(e);
                    return;
                }
    
            } catch (Throwable e) {
                error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
            } finally {
                RequestContext.getCurrentContext().unset();
            }
        }

    1.3. ContextLifecycleFilter

    public class ContextLifecycleFilter implements Filter {
    
        public void destroy() {}
    
        public void init(FilterConfig filterConfig) throws ServletException {}
    
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
            try {
                chain.doFilter(req, res);
            } finally {
                RequestContext.getCurrentContext().unset();
            }
        }
    
    }

    2. zuul2的线程模型

    其应用的web.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
    
        <filter>
            <filter-name>guiceFilter</filter-name>
            <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>guiceFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <listener>
            <listener-class>com.netflix.zuul.StartServer</listener-class>
        </listener>
    
    </web-app>

    2.1. StartServer

     /**
         * Overridden solely so we can tell how much time is being spent in overall initialization. Without
         * overriding we can't tell how much time was spent in BaseServer doing its own initialization.
         *
         * @param sce
         */
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            try {
                server.start();
            } catch (Exception e) {
                LOG.error("Error while starting karyon.", e);
                throw Throwables.propagate(e);
            }
            try {
                initialize();
            } catch (Exception e) {
                e.printStackTrace();
            }
            super.contextInitialized(sce);
        }

    2.2. ZuulServlet

       @Override
        public void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException
        {
            try {
                zuulProcessor
                        .process(servletRequest, servletResponse)
                        .doOnNext(msg -> {
                            // Store this response as an attribute for any later ServletFilters that may want access to info in it.
                            servletRequest.setAttribute("_zuul_response", msg);
                        })
                        .subscribe();
            }
            catch (Throwable e) {
                LOG.error("Unexpected error running ZuulHttpProcessor for this request.", e);
                throw new ServletException("Unexpected error running ZuulHttpProcessor for this request.");
            }
        }

    2.3 ZuulHttpProcessor

    /**
     * The main processing class for Zuul.
     *
     * 1. Translates the inbound native request (ie. HttpServletRequest, or rxnetty HttpServerRequest) into a zuul HttpRequestMessage.
     * 2. Builds the filter chain and passes the request through it.
     * 3. Writes out the HttpResponseMessage to the native response object.
     */

    处理过程:

      public Observable<ZuulMessage> process(final I nativeRequest, final O nativeResponse)
        {
            // Setup the context for this request.
            final SessionContext context;
    
            // Optionally decorate the context.
            if (decorator == null) {
                context = new SessionContext();
            } else {
                context = decorator.decorate(new SessionContext());
            }
    
            return Observable.defer((Func0<Observable<ZuulMessage>>) () -> {
    
                // Build a ZuulMessage from the netty request.
                final ZuulMessage request = contextFactory.create(context, nativeRequest, nativeResponse);
    
                // Start timing the request.
                request.getContext().getTimings().getRequest().start();
    
                /*
                 * Delegate all of the filter application logic to {@link FilterProcessor}.
                 * This work is some combination of synchronous and asynchronous.
                 */
                Observable<ZuulMessage> chain = filterProcessor.applyFilterChain(request);
    
                return chain
                        .flatMap(msg -> {
                            // Wrap this in a try/catch because we need to ensure no exception stops the observable, as
                            // we need the following doOnNext to always run - as it records metrics.
                            try {
                                // Write out the response.
                                return contextFactory.write(msg, nativeResponse);
                            }
                            catch (Exception e) {
                                LOG.error("Error in writing response! request=" + request.getInfoForLogging(), e);
    
                                // Generate a default error response to be sent to client.
                                return Observable.just(new HttpResponseMessageImpl(context, ((HttpResponseMessage) msg).getOutboundRequest(), 500));
                            }
                            finally {
                                // End the timing.
                                msg.getContext().getTimings().getRequest().end();
                            }
                        })
                        .doOnError(e -> {
                            LOG.error("Unexpected error in filter chain! request=" + request.getInfoForLogging(), e);
                        })
                        .doOnNext(msg -> {
                            // Notify requestComplete listener if configured.
                            try {
                                if (requestCompleteHandler != null)
                                    requestCompleteHandler.handle(((HttpRequestMessage) request).getInboundRequest(), (HttpResponseMessage) msg);
                            }
                            catch (Exception e) {
                                LOG.error("Error in RequestCompleteHandler.", e);
                            }
                        })
                        ;
            }).finallyDo(() -> {
                // Cleanup any resources related to this request/response.
                sessionCleaner.cleanup(context);
            });
        }
    }

    参考文献:

    【1】http://techblog.netflix.com/2013/06/announcing-zuul-edge-service-in-cloud.html

    【2】http://techblog.netflix.com/2016/09/zuul-2-netflix-journey-to-asynchronous.html?utm_source=tuicool&utm_medium=referral

  • 相关阅读:
    Django框架13 /缓存、信号、django的读写分离
    linux09 /消息队列、saltstack工具
    会话管理之AbpSession
    ABP之事件总线(5)
    依赖注入容器之Castle Windsor
    ABP之事件总线(4)
    ABP之事件总线(3)
    ABP之事件总线(2)
    ABP之事件总线(1)
    ABP之展现层(Datatables分页)
  • 原文地址:https://www.cnblogs.com/davidwang456/p/6421025.html
Copyright © 2011-2022 走看看