Spring Cloud技術分析(4)- spring cloud zuul
地址:http://tech.lede.com/
spring cloud zuul是netflix提供的一個元件,功能類似於nginx,用於反向代理,可以提供動態路由、監控、授權、安全、排程等邊緣服務。
1. zuul是什麼
微服務場景下,每一個微服務對外暴露了一組細粒度的服務。客戶端的請求可能會涉及到一串的服務呼叫,如果將這些微服務都暴露給客戶端,那麼會增加客戶端程式碼的複雜度。
參考GOF設計模式中的Facade模式,將細粒度的服務組合起來提供一個粗粒度的服務,所有請求都匯入一個統一的入口,那麼整個服務只需要暴露一個api,對外遮蔽了服務端的實現細節,也減少了客戶端與伺服器的網路呼叫次數。這就是api gateway。
有了api gateway之後,一些與業務關係並不大的通用處理邏輯可以從api gateway中剝離出來,api gateway僅僅負責服務的編排與結果的組裝。
Spring Cloud Netflix的Zuul元件可以做反向代理的功能,通過路由定址將請求轉發到後端的粗粒度服務上,並做一些通用的邏輯處理。
總結Zuul的作用:
- 動態路由
- 監控
- 安全
- 認證鑑權
- 壓力測試
- 金絲雀測試
- 審查
- 服務遷移
- 負載剪裁
- 靜態應答處理
2. 怎麼使用zuul
maven配置
在pom.xml中新增以下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId |
引入eureka的目的是為了後續與eureka做整合,使用serviceId做路由。
java程式設計
在啟動類新增@EnableZuulProxy註解
1 2 3 4 5 6 7 8 9 | public class GatewayServer { public static void main(String[] args) { SpringApplication.run(GatewayServer.class, args); } } |
3. zuul對路由的配置
Zuul對路由跳轉的配置是在application.yml檔案中,定義了兩種對映方式:
- url對映
- serviceId對映
1. url直接對映
- 單例項url直連
1 2 3 4 5 | zuul: routes: wap: path: /wap/** url: http://192.168.1.10:8081 |
- 多例項路由
1 2 3 4 5 6 7 8 9 10 11 | zuul: routes: wap: path: /wap/** serviceId: wap ribbon: eureka: enabled: false wap: ribbon: listOfServers: http://192.168.1.10:8081, http://192.168.1.11:8081 |
- forward跳轉到本地url
1 2 3 4 5 | zuul: routes: wap: path: /wap/** url: forward:/wap |
2. serviceId對映
- 預設serviceId,
serviceId:activity,路由規則:/activity/101 -> /101
1 2 3 | zuul: routes: activity: /activity/** |
- 指定serviceId,
serviceId:micro-activity,路由規則:/activity/101 -> /activity/101
1 2 3 4 5 6 | zuul: routes: activity: path: /activity/** # 指定 serviceId: micro-activity # 指定路由的serviceId stripPrefix: false |
4. Cookie與頭資訊
預設情況下,Zuul在請求路由時,會過濾HTTP請求頭資訊中的一些敏感資訊,預設的敏感頭資訊通過zuul.sensitiveHeaders定義,包括Cookie、Set-Cookie、Authorization。
- 設定全域性引數覆蓋預設值
1 2 | zuul: sensitiveHeaders: # 使用空來覆蓋預設值 |
- 指定路由的引數配置
1 2 3 4 | zuul: routes: [route]: customSensitiveHeaders: true # 對指定路由開啟自定義敏感頭 |
1 2 3 4 | zuul: routes: [route]: sensitiveHeaders: # 對指定路由的敏感頭設定為空 |
5. zuul的關鍵知識點
filter是Zuul的核心,用來實現對外服務的控制。filter的生命週期有4個,分別是”pre”、”route”、”post”、”error”,整個生命週期可以用下圖來表示。
具體的程式碼是在ZuulServletFilter類中,從實現可以看出,error可以在所有階段捕獲異常後執行,但是當post階段處理中出現異常不會再回到post階段,那麼這就需要保證在post階段不要有異常,因為一旦有異常後就不會走post執行SendErrorFilter了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public class ZuulServletFilter implements Filter { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); try { preRouting(); } catch (ZuulException e) { error(e); postRouting(); return; } // Only forward onto to the chain if a zuul response is not being sent if (!RequestContext.getCurrentContext().sendZuulResponse()) { filterChain.doFilter(servletRequest, servletResponse); return; } try { routing(); } catch (ZuulException e) { error(e); postRouting(); return; } try { postRouting(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } } } |
zuul中預設實現的filter
型別 | 順序 | 過濾器 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 標記處理Servlet的型別 |
pre | -2 | Servlet30WrapperFilter | 包裝HttpServletRequest請求 |
pre | -1 | FormBodyWrapperFilter | 包裝請求體 |
route | 1 | DebugFilter | 標記除錯標誌 |
route | 5 | PreDecorationFilter | 處理請求上下文供後續使用 |
route | 10 | RibbonRoutingFilter | serviceId請求轉發 |
route | 100 | SimpleHostRoutingFilter | url請求轉發 |
route | 500 | SendForwardFilter | forward請求轉發 |
post | 0 | SendErrorFilter | 處理有錯誤的請求響應 |
post | 1000 | SendResponseFilter | 處理正常的請求響應 |
禁用指定的filter
可以在application.yml中配置需要禁用的filter,格式:zuul:[filter-name]:[filter-type]:disable:true。
1 2 3 4 | zuul: FormBodyWrapperFilter: pre: disable: true |
自定義filter
使用java實現自定義filter,需要新增繼承於ZuulFilter的類,覆蓋其中的4個方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class CustomerPreFilter extends ZuulFilter { String filterType() { return "pre"; //定義filter的型別,有pre、route、post、error四種 } int filterOrder() { return 10; //定義filter的順序,數字越小表示順序越高,越先執行 } boolean shouldFilter() { return true; //表示是否需要執行該filter,true表示執行,false表示不執行 } Object run() { return null; //filter需要執行的具體操作 } } |
6. zuul對動態語言的支援
zuul支援使用groovy語言來動態修改filter,它是基於jvm的語言,語法簡單並且很多與java類似。
需要先將groovy的jar包引入
1 2 3 4 5 | <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.4.9</version> </dependency> |
然後掃描groovy檔案
1 2 3 | FilterLoader.getInstance().setCompiler(new GroovyCompiler()); FilterFileManager.setFilenameFilter(new GroovyFileFilter()); FilterFileManager.init(internal, path); |
FilterFileManager會對groovy檔案變更載入如記憶體,其實現是開啟了一個後臺執行緒,以指定間隔的時間長度管理檔案,具體的程式碼如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class FilterFileManager { public static void init(int pollingIntervalSeconds, String... directories) throws Exception, IllegalAccessException, InstantiationException { if (INSTANCE == null) INSTANCE = new FilterFileManager(); INSTANCE.aDirectories = directories; INSTANCE.pollingIntervalSeconds = pollingIntervalSeconds; INSTANCE.manageFiles(); INSTANCE.startPoller(); } void startPoller() { poller = new Thread("GroovyFilterFileManagerPoller") { public void run() { while (bRunning) { try { sleep(pollingIntervalSeconds * 1000); manageFiles(); } catch (Exception e) { e.printStackTrace(); } } } }; poller.setDaemon(true); poller.start(); } } |
最終呼叫的是FilterLoader的putFilter方法,是否需要重新載入檔案,判斷依據是看檔案是否已經載入到記憶體中,同時檔案是否被修改過。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class FilterLoader { public boolean putFilter(File file) throws Exception { String sName = file.getAbsolutePath() + file.getName(); if (filterClassLastModified.get(sName) != null && (file.lastModified() != filterClassLastModified.get(sName))) { LOG.debug("reloading filter " + sName); filterRegistry.remove(sName); } ZuulFilter filter = filterRegistry.get(sName); if (filter == null) { Class clazz = COMPILER.compile(file); if (!Modifier.isAbstract(clazz.getModifiers())) { filter = (ZuulFilter) FILTER_FACTORY.newInstance(clazz); List<ZuulFilter> list = hashFiltersByType.get(filter.filterType()); if (list != null) { hashFiltersByType.remove(filter.filterType()); //rebuild this list } filterRegistry.put(file.getAbsolutePath() + file.getName(), filter); filterClassLastModified.put(sName, file.lastModified()); return true; } } return false; } } |
groovy實現的filter,groovy語法格式與java相近:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class PreFilter extends ZuulFilter { String filterType() { return "pre" } int filterOrder() { return 1000 } boolean shouldFilter() { return true } Object run() { return null } } |
7. 全域性異常處理
介紹一下Zuul的全域性異常處理的一種方式:新增一個型別為”error”的filter,將錯誤資訊寫入RequestContext,這樣SendErrorFilter就可以獲取錯誤資訊了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class ErrorFilter extends ZuulFilter { String filterType() { return FilterConstants.ERROR_TYPE } int filterOrder() { return 10 } boolean shouldFilter() { return true } Object run() { RequestContext context = getRequestContext() Throwable throwable = context.getThrowable() LOGGER.error("[ErrorFilter] error message: {}", throwable.getCause().getMessage()) ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR) ctx.set("error.exception", throwable.getCause()) return null } } |
8. 效能優化參考
1. 在application.yml檔案中配置執行緒數、緩衝大小
1 2 3 4 5 6 7 8 9 10 | server: tomcat: max-threads: 128 # 最大worker執行緒 min-spare-threads: 64 # 最小worker執行緒 undertow: io-threads: 8 # IO執行緒數,預設為CPU核心數,最小為2 worker-threads: 40 # 阻塞任務執行緒池,值設定取決於系統的負載,預設為io-threads * 8 buffer-size: 512 # 每塊buffer的空間大小 buffers-per-region: 10 # 每個區分配的buffer數量 direct-buffers: 512 # 是否分配的直接記憶體 |
相關推薦
Spring Cloud技術分析(4)- spring cloud zuul
地址:http://tech.lede.com/ spring cloud zuul是netflix提供的一個元件,功能類似於nginx,用於反向代理,可以提供動態路由、監控、授權、安全、排程等邊緣服務。1. zuul是什麼微服務場景下,每一個微服務對外暴露了一組細粒度
Spring Cloud技術分析(3)- spring cloud sleuth
地址:http://tech.lede.com/1. 目的提供鏈路追蹤。通過sleuth可以很清楚的看出一個請求都經過了哪些服務。可以很方便的理清服務間的呼叫關係。視覺化錯誤。對於程式未捕捉的異常,可以在zipkin介面上看到。分析耗時。通過sleuth可以很方便的看出每個取
Spring Cloud技術分析(1)——服務治理
地址:http://tech.lede.com/ 本文作為系列的第一篇正文,從Spring Cloud中的核心專案Spring Cloud Netflix入手,闡述了Spring Cloud Netflix的優勢,介紹了Spring Cloud Netflix進行服務治
Spring核心技術原理-(3)-Spring歷史版本變遷和如今的生態帝國
前幾篇:
前兩篇從Web開發史的角度介紹了我們在開發的時候遇到的一個個坑,然後一步步衍生出Spring Ioc和Spring AOP的概念雛形。Spring從2004年第一個正式版1.0 Final Released發展至今,儼然已經成為了一個生態帝國
spring cloud系列教程(4)--eureka註冊中心叢集配置,微服務註冊資訊完善
給大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油
1.Eureka是什麼
Eureka是Netflix的一個子模組之一,AP設計原則。Eureka是一個以及Rest的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務註冊與發現對於微服務架構來
Spring原始碼分析(4)---BeanFactoryPostProcessor(看見的不一定是真的)
在第二編對BeanFactory的分析中,我們老能看見BeanFactoyPostProcessor的身影,那麼在這一節中,我們來詳細的討論一下BeanFactoryPostProcessor的程式碼結構,從中學習他的優秀之處;BeanFactoryPostProcessor
Spring的IOC分析(二)源碼
width single def app ali instance exc net classpath 承接上節繼續,分析Ioc的工作原理,在典型的 IOC 場景中,容器創建了所有對象,並設置必要的屬性將它們連接在一起(同時一個叫DI“依賴註入”或DL“依賴查找”的概念
Spring 源碼分析(一)--整體架構和環境搭建
spring 事件傳播 com 之間 環境搭建 core模塊 batis bsp 元數據 本系統分析的spring源碼版本為4.3.8。
(一)整體架構
這些模塊被分為以下幾個部分
(1)Core Container
Core容器(核心容器)包含Core,Bean
Spring 源碼分析(四)--自定義標簽的使用
div protected 不同 space xsd文件 不同的 handle body img 在之前的代碼分析中,Spring標簽的解析分為 默認標簽和自定義標簽兩種,前一篇文章分析了Spring中對默認標簽的解析過程。
本文將分析Spring中自定義標
Spring 源碼分析(六)--bean的加載整體分析
mean ash rep end on() 靈活性 available iat cleanup 通過前面的分析,我們結束了對XML配置文件的解析,接下來將進行bean加載的分析。對於加載bean的功能,在Spring中的調用方式為:
或者 MyTest
Spring 源碼分析(八)--容器的功能擴展
use abs 提取 ext troy sha 根據 idc owb 經過前面幾篇的分析,相信大家對Spring中容器功能有了簡單的了解,在前面的章節中我們一直以BeanFactory接口以及它的默認實現類XmlBeanFactory為例進行分析。但是,Spring
Spring 源碼分析(九)--AOP
see nbsp 完成 owa new util 定義 sep ret 我們知道,使用面向對象編程(OOP)有一些弊端,當需要為多個不具有繼承關系的對象引入同一個公共行為時,例如日誌,安全檢測等,我們只有在每個對象裏引用公共行為,這樣程序中就產生了大量的重復代碼,程
Spring框架學習(4)spring整合hibernate
location host mage too 自動 exception 4.0 數據庫連接 find 內容源自:spring整合hibernate spring整合註解形式的hibernate
這裏和上一部分學習一樣用了模板模式, 將hibernate開發流程封裝在O
Spring源碼分析(五)獲取Document
規則 一個 自定義 trac tst nload indexof get t對象
摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。
這一篇開始進行Document加載了,XmlBeanFactoryR
Spring源碼分析(八)AbstractBeanDefinition屬性
strac code 出現 shm main candidate 靜態變量 col aof
摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。
在上一篇中已經完成了XML文檔到GenericBeanDe
Spring源碼分析(十)註冊解析的BeanDefinition
emp int style ash table 針對 全局變量 我們 名稱
摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。
對配置文件解析完成後,獲取的beanDefiniton已經可以進行使用了,
Spring源碼分析(十三)緩存中獲取單例bean
ould for 目的 存儲 不同 單例 color 正在 span
摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。
介紹過FactoryBean的用法後,我們就可以了解bean加載的過程了。前面已
(4)Spring學習記錄---Spring_bean(屬性配置細節)
這一節主要學了bean的詳細配置
特殊符號的解決方法:
如果字串裡有特殊符號需要用<![CDATA[]]>
引用其他bean
通過引用來使用bean。有時某類bean包含另一類bean。這裡要用到ref引用
Spring入門學習筆記(4)——JDBC的使用
目錄
Spring JDBC框架概覽
JdbcTemplate類
配置資料來源
資料訪問物件(Data Access Object,DAO)
執行SQL命令
Spring JDBC框架概覽
使用傳統的JDBC連線資料庫,需要編寫不必要的程式碼來處理
第三章 spring-bean之FactoryBeanRegistrySupport(4)
前言
從FactoryBeanRegistrySupport類的名字可以看出FactoryBeanRegistrySupport負責FactoryBean的註冊與支援。如果想知道FactoryBean相關的資料,請閱讀spring-bean中關於FactoryBean的解讀。
Spring Cloud技術分析(4)- spring cloud zuul
地址:http://tech.lede.com/ spring cloud zuul是netflix提供的一個元件,功能類似於nginx,用於反向代理,可以提供動態路由、監控、授權、安全、排程等邊緣服務。1. zuul是什麼微服務場景下,每一個微服務對外暴露了一組細粒度
Spring Cloud技術分析(3)- spring cloud sleuth
地址:http://tech.lede.com/1. 目的提供鏈路追蹤。通過sleuth可以很清楚的看出一個請求都經過了哪些服務。可以很方便的理清服務間的呼叫關係。視覺化錯誤。對於程式未捕捉的異常,可以在zipkin介面上看到。分析耗時。通過sleuth可以很方便的看出每個取
Spring Cloud技術分析(1)——服務治理
地址:http://tech.lede.com/ 本文作為系列的第一篇正文,從Spring Cloud中的核心專案Spring Cloud Netflix入手,闡述了Spring Cloud Netflix的優勢,介紹了Spring Cloud Netflix進行服務治
Spring核心技術原理-(3)-Spring歷史版本變遷和如今的生態帝國
前幾篇: 前兩篇從Web開發史的角度介紹了我們在開發的時候遇到的一個個坑,然後一步步衍生出Spring Ioc和Spring AOP的概念雛形。Spring從2004年第一個正式版1.0 Final Released發展至今,儼然已經成為了一個生態帝國
spring cloud系列教程(4)--eureka註冊中心叢集配置,微服務註冊資訊完善
給大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油 1.Eureka是什麼 Eureka是Netflix的一個子模組之一,AP設計原則。Eureka是一個以及Rest的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。服務註冊與發現對於微服務架構來
Spring原始碼分析(4)---BeanFactoryPostProcessor(看見的不一定是真的)
在第二編對BeanFactory的分析中,我們老能看見BeanFactoyPostProcessor的身影,那麼在這一節中,我們來詳細的討論一下BeanFactoryPostProcessor的程式碼結構,從中學習他的優秀之處;BeanFactoryPostProcessor
Spring的IOC分析(二)源碼
width single def app ali instance exc net classpath 承接上節繼續,分析Ioc的工作原理,在典型的 IOC 場景中,容器創建了所有對象,並設置必要的屬性將它們連接在一起(同時一個叫DI“依賴註入”或DL“依賴查找”的概念
Spring 源碼分析(一)--整體架構和環境搭建
spring 事件傳播 com 之間 環境搭建 core模塊 batis bsp 元數據 本系統分析的spring源碼版本為4.3.8。 (一)整體架構 這些模塊被分為以下幾個部分 (1)Core Container Core容器(核心容器)包含Core,Bean
Spring 源碼分析(四)--自定義標簽的使用
div protected 不同 space xsd文件 不同的 handle body img 在之前的代碼分析中,Spring標簽的解析分為 默認標簽和自定義標簽兩種,前一篇文章分析了Spring中對默認標簽的解析過程。 本文將分析Spring中自定義標
Spring 源碼分析(六)--bean的加載整體分析
mean ash rep end on() 靈活性 available iat cleanup 通過前面的分析,我們結束了對XML配置文件的解析,接下來將進行bean加載的分析。對於加載bean的功能,在Spring中的調用方式為: 或者 MyTest
Spring 源碼分析(八)--容器的功能擴展
use abs 提取 ext troy sha 根據 idc owb 經過前面幾篇的分析,相信大家對Spring中容器功能有了簡單的了解,在前面的章節中我們一直以BeanFactory接口以及它的默認實現類XmlBeanFactory為例進行分析。但是,Spring
Spring 源碼分析(九)--AOP
see nbsp 完成 owa new util 定義 sep ret 我們知道,使用面向對象編程(OOP)有一些弊端,當需要為多個不具有繼承關系的對象引入同一個公共行為時,例如日誌,安全檢測等,我們只有在每個對象裏引用公共行為,這樣程序中就產生了大量的重復代碼,程
Spring框架學習(4)spring整合hibernate
location host mage too 自動 exception 4.0 數據庫連接 find 內容源自:spring整合hibernate spring整合註解形式的hibernate 這裏和上一部分學習一樣用了模板模式, 將hibernate開發流程封裝在O
Spring源碼分析(五)獲取Document
規則 一個 自定義 trac tst nload indexof get t對象 摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 這一篇開始進行Document加載了,XmlBeanFactoryR
Spring源碼分析(八)AbstractBeanDefinition屬性
strac code 出現 shm main candidate 靜態變量 col aof 摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 在上一篇中已經完成了XML文檔到GenericBeanDe
Spring源碼分析(十)註冊解析的BeanDefinition
emp int style ash table 針對 全局變量 我們 名稱 摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 對配置文件解析完成後,獲取的beanDefiniton已經可以進行使用了,
Spring源碼分析(十三)緩存中獲取單例bean
ould for 目的 存儲 不同 單例 color 正在 span 摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。 介紹過FactoryBean的用法後,我們就可以了解bean加載的過程了。前面已
(4)Spring學習記錄---Spring_bean(屬性配置細節)
這一節主要學了bean的詳細配置 特殊符號的解決方法: 如果字串裡有特殊符號需要用<![CDATA[]]> 引用其他bean 通過引用來使用bean。有時某類bean包含另一類bean。這裡要用到ref引用
Spring入門學習筆記(4)——JDBC的使用
目錄 Spring JDBC框架概覽 JdbcTemplate類 配置資料來源 資料訪問物件(Data Access Object,DAO) 執行SQL命令 Spring JDBC框架概覽 使用傳統的JDBC連線資料庫,需要編寫不必要的程式碼來處理
第三章 spring-bean之FactoryBeanRegistrySupport(4)
前言 從FactoryBeanRegistrySupport類的名字可以看出FactoryBeanRegistrySupport負責FactoryBean的註冊與支援。如果想知道FactoryBean相關的資料,請閱讀spring-bean中關於FactoryBean的解讀。