Zuul閘道器進行灰度釋出
阿新 • • 發佈:2020-07-29
微服務中,新版服務上線的時候,為了保證不出什麼問題,可以將少量的請求轉發到新的服務上,
然後其他的請求還是轉發到舊的服務上去,等線上的新服務測試通過以後,就可以重新平均分配
請求。這種功能就稱為灰度釋出。
要完成灰度釋出,要做的就是修改ribbon的負載均衡策略,通過一些特定的標識,比如我們針對某個
介面路徑/gray/publish/test。將10%的請求轉發到新的服務上,將90%的請求轉發到舊的服務上,諸
如此類,我們可以制定各種規則進行灰度測試。
在微服務中,我們可以通過eureka的metamata進行自定義元資料,然後來修改ribbon的負載均衡策略。
在此,可以先通過程式碼進行簡單地灰度釋出,在實際應用中,可以通過資料庫配置進行灰度靈活釋出。
首先,我們如果要部署新版的服務user-server,我們用不同的埠啟動這個服務,並配置不同的自定義
元資料,配置如下:
server: port: 8181 #Eureka註冊配置 eureka: client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/ instance: metadata-map: forward: 1
server: port: 8182 #Eureka註冊配置 eureka: client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/ instance: metadata-map: forward: 2
我們啟動了8181和8182兩個服務,並分別定義了元資料forward: 1和forward: 2
然後,開始修改zuul閘道器,首先匯入修改ribbon負載均衡策略的依賴
<!-- 修改Zuul的負載均衡策略,也就是進行灰度釋出使用的 --> <dependency> <groupId>io.jmnarloch</groupId> <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId> <version>2.1.0</version> </dependency>
然後,開始修改ribbon的負載均衡策略
package com.dkjk.gateway.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import io.jmnarloch.spring.cloud.ribbon.support.RibbonFilterContextHolder; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.*; /** * @author: qjc * @createTime: 2020/7/29 * @Description: 介面安全驗證過濾器 */ @Component @Slf4j public class ValidFilter extends ZuulFilter { @Override public String filterType() { return PRE_TYPE; } @Override public int filterOrder() { return PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { // 進行跨域請求的時候,並且請求頭中有額外引數,比如token,客戶端會先發送一個OPTIONS請求來探測後續需要發起的跨域POST請求是否安全可接受 // 所以這個請求就不需要攔截,下面是處理方式 RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); if (request.getMethod().equals(RequestMethod.OPTIONS.name())) { log.info("OPTIONS請求不做攔截操作"); return false; } return true; } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String requestURI = request.getRequestURI(); if (requestURI.contains("/gray/publish/test")){ int send = (int) (Math.random() * 100); if (send >= 0 && send < 10) { //也就是百分之10的請求轉發到forward=1的服務上去 RibbonFilterContextHolder.getCurrentContext().add("forward", "1");//這句話就代表將請求路由到metadata-map裡forward為1的那個服務 } else { //百分之90的請求轉發到forward=2的服務上去 RibbonFilterContextHolder.getCurrentContext().add("forward", "2");//這句話就代表將請求路由到metadata-map裡forward為2的那個服務 } } return null; } }
接下來就可以測試介面/gray/publish/test的轉發情況了,結果就是
10%的請求轉發到了8181上(即forward為1的服務上),90%的請求轉發到了8182(即forward為2的服務上)
PS:在生產上使用的時候,可以通過建立資料庫表來動態配置負載均衡策略,比如建立一張資料表:
CREATE TABLE `gray_release_config` ( `id` int(11) NOT NULL AUTO_INCREMENT, `server_name` varchar(255) DEFAULT NULL, //服務名 `path` varchar(255) DEFAULT NULL,//需要進行灰度釋出的介面路徑 `percent` int(11) DEFAULT NULL,//負載均衡策略,百分之percent的請求轉發到forward上 `forward` int(11) DEFAULT NULL,//自定義元資料值 PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
然後每隔一段時間同步配置表中的資訊,也就是寫個定時任務。