基于 Nginx 的 zuul 網(wǎng)關(guān)負(fù)載均衡

我們都知道,zuul 網(wǎng)關(guān)可以攔截微服務(wù)系統(tǒng)中請求做統(tǒng)一的處理礁遵,比如說可以結(jié)合 JWT 實(shí)現(xiàn)無狀態(tài)的身份驗(yàn)證单起,拒絕 Cookie 中沒有攜帶 Token 或者 Token 解析失敗的的請求,這樣做的好處是減輕了其他微服務(wù)的壓力蛀柴,但也無疑加大 zuul 網(wǎng)關(guān)的工作量螃概,那要怎么解決這個(gè)問題呢?答案是可以使用負(fù)載均衡服務(wù)器(比如說 Nginx)鸽疾,將請求均勻地轉(zhuǎn)發(fā)到 zuul 網(wǎng)關(guān)集群吊洼,下面我來嘗試實(shí)現(xiàn)這一方案,大致的流程如下:

  1. 搭建 Eureka 注冊中心
  2. 創(chuàng)建業(yè)務(wù)相關(guān)的微服務(wù)模塊(僅作簡單的模擬)
  3. 搭建 zuul 集群
  4. 配置 Nginx制肮,實(shí)現(xiàn)負(fù)載均衡
  5. 測試

1. Eureka 注冊中心

創(chuàng)建 Maven 模塊冒窍,取名為 eureka-registry,在 pom.xml 中設(shè)置相關(guān)依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>
</dependencies>

在 resources 目錄下新建 application.yml 配置文件

server:
  port: 10086
spring:
  application:
    name: eureka-registry
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:${server.port}/eureka
    register-with-eureka: false # 把自己注冊到eureka服務(wù)列表
    fetch-registry: false # 拉取eureka服務(wù)信息
  server:
    enable-self-preservation: false # 關(guān)閉自我保護(hù)
    eviction-interval-timer-in-ms: 5000 # 每隔5秒鐘豺鼻,進(jìn)行一次服務(wù)列表的清理

編寫啟動(dòng)類

@SpringBootApplication
@EnableEurekaServer
public class RegistryApplication {
    public static void main(String[] args) {
        SpringApplication.run(RegistryApplication.class, args);
    }
}

項(xiàng)目架構(gòu)如下所示

Snipaste_2019-09-03_20-58-00.jpg

2. 創(chuàng)建業(yè)務(wù)相關(guān)的微服務(wù)模塊

創(chuàng)建 micro-service 模塊综液,在 pom.xml 文件中設(shè)置相關(guān)依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

在 resources 目錄下新建 application.yml 配置文件

server:
  port: 8084
spring:
  application:
    name: micro-service
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒發(fā)送一次心跳
    lease-expiration-duration-in-seconds: 10 # 10秒不發(fā)送就過期

編寫啟動(dòng)類

@SpringBootApplication
@EnableDiscoveryClient
public class MicroApplication {
    public static void main(String[] args) {
        SpringApplication.run(MicroApplication.class, args);
    }
}

在 cc.geekeye.micro.pojo 包下新建

package cc.geekeye.micro.pojo;

public class CommonObject {
    private Integer id;
    private String col1;
    private String col2;
    //constructors...
    //getters and setters
}

添加 controller

@Controller
@RequestMapping("common")
public class CommonController {

    @ResponseBody
    @RequestMapping("get")
    public CommonObject getCommonObject() {
        System.out.println("bfjkabfjk");
        return new CommonObject(1, "col1", "col2");
    }
}

3. 搭建 zuul 集群

創(chuàng)建 zuul-gateway 模塊,在 pom.xml 文件中設(shè)置相關(guān)依賴

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

在 resources 目錄下新建 application.yml 配置文件

server:
  port: 10010
spring:
  application:
    name: zuul-gateway
eureka:
  client:
    registry-fetch-interval-seconds: 5
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
zuul:
  prefix: /api
  routes:
    micro-service: /micro/**

編寫啟動(dòng)類

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

編寫網(wǎng)關(guān)過濾器

@Component
public class AccessFilter extends ZuulFilter {
    
    private static final Logger logger = LogManager.getLogger(AccessFilter.class);
    
    @Value("${server.port}")
    private String serverPort;
    
    @Override
    public String filterType() {
        return "pre"; //
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true; 
    }

    @Override
    public Object run() {
        logger.info("網(wǎng)關(guān)執(zhí)行端口號:" + serverPort);
        return null;
    }
}

這里使用端口區(qū)分集群節(jié)點(diǎn)儒飒,為了方便測試谬莹,所以將當(dāng)前處理請求的 zuul 網(wǎng)關(guān)的響應(yīng)端口輸出到日志文件,而此處使用的日志框架是 log4j2桩了。

現(xiàn)在有一個(gè)網(wǎng)關(guān)了届良,那要怎么搭建集群呢?部署3份 jar 包嗎圣猎?但如果我們還要修改一些代碼又要重新打包和部署士葫,豈不是很麻煩?其實(shí)我們可以使用 IDEA 提供的 Run Dashboard 選項(xiàng)運(yùn)行 zuul 網(wǎng)關(guān)微服務(wù)送悔,等到運(yùn)行它成功后慢显, application.yml 配置文件已被加載進(jìn) Tomcat 容器,這時(shí)我們再修改 application.yml 配置文件中的運(yùn)行端口欠啤,然后復(fù)制運(yùn)行配置就行了荚藻。

網(wǎng)關(guān)

保留默認(rèn)配置,這里只是改了個(gè)名字

修改 IDEA 啟動(dòng)配置

運(yùn)行配置洁段,結(jié)果如下所示

run dashboard

4. Nginx 負(fù)載均衡

修改 nginx.conf 配置文件应狱,在 http 節(jié)點(diǎn)中配置三個(gè)上游服務(wù)器

http {
    upstream  backServer {
        server 127.0.0.1:10010;
        server 127.0.0.1:10011;
        server 127.0.0.1:10012;
    }
    
    server {
        listen       80;
        server_name  api.blabla.com;

        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        location / {
            proxy_pass http://backServer/;
            proxy_connect_timeout 600;
            proxy_read_timeout 600;
        }
    }
}

其中 api.blabla.com 是在 host 文件中配置解析到 localhost 的。

5. 測試

現(xiàn)在環(huán)境已經(jīng)搭建好祠丝,下面先來通過一張整體的結(jié)構(gòu)圖來了解我在上面做了什么事情疾呻。

架構(gòu)
  1. 客戶端訪問 http://api.blabla.com/api/micro/common/get
  2. 由于 Nginx 代理了80端口除嘹,所以該請求交給它處理,它將解析到 http 節(jié)點(diǎn)中配置的 api.blabla.com 需要轉(zhuǎn)發(fā)的上游服務(wù)器并根據(jù)其負(fù)載均衡策略進(jìn)行轉(zhuǎn)發(fā)岸蜗。
  3. 比如說轉(zhuǎn)發(fā)到 http://127.0.0.1:10010/api/micro/common/get 尉咕,則交由監(jiān)聽該端口的網(wǎng)關(guān)處理,它將先消掉前綴 /api璃岳,進(jìn)行相關(guān)的過濾和處理后年缎,因?yàn)?/micro 匹配 micro-service,它查找其在 Eureka 注冊中心中拉取到的服務(wù)列表铃慷,若找到則進(jìn)行轉(zhuǎn)發(fā)单芜。
  4. 請求轉(zhuǎn)發(fā)到 http://127.0.0.1:8084/micro/common/get ,這時(shí) micro-service 就可以進(jìn)行處理并響應(yīng)了犁柜。

了解整個(gè)流程后就可以進(jìn)行測試缓溅,為了方便,我使用 HttpClient 訪問 http://api.blabla.com/api/micro/common/get 赁温,通過比較網(wǎng)關(guān)中輸出的日志信息檢驗(yàn)負(fù)載均衡是否成功。

public class HttpTests {

    private CloseableHttpClient httpClient;

    @Before
    public void init() {
        httpClient = HttpClients.createDefault();
    }

    @Test
    public void testGetPojo() throws IOException {
        for (int i = 0; i < 1000; i++) {
            HttpGet request = new HttpGet("http://api.blabla.com/api/micro/common/get");
            this.httpClient.execute(request, new BasicResponseHandler());
            Thread.sleep(200);
        }
    }
}

為了看得更直觀淤齐,我在日志配置文件 log4j2.xml 中過濾掉了其他類庫的日志信息股囊,測試運(yùn)行成功后查看輸出日志:

日志信息
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市更啄,隨后出現(xiàn)的幾起案子稚疹,更是在濱河造成了極大的恐慌,老刑警劉巖祭务,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件内狗,死亡現(xiàn)場離奇詭異,居然都是意外死亡义锥,警方通過查閱死者的電腦和手機(jī)柳沙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拌倍,“玉大人赂鲤,你說我怎么就攤上這事≈簦” “怎么了数初?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長梗顺。 經(jīng)常有香客問我泡孩,道長,這世上最難降的妖魔是什么寺谤? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任仑鸥,我火速辦了婚禮吮播,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锈候。我一直安慰自己薄料,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布泵琳。 她就那樣靜靜地躺著摄职,像睡著了一般。 火紅的嫁衣襯著肌膚如雪获列。 梳的紋絲不亂的頭發(fā)上谷市,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機(jī)與錄音击孩,去河邊找鬼迫悠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛巩梢,可吹牛的內(nèi)容都是我干的创泄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼括蝠,長吁一口氣:“原來是場噩夢啊……” “哼鞠抑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起忌警,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤搁拙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后法绵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箕速,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年朋譬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盐茎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡徙赢,死狀恐怖庭呜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犀忱,我是刑警寧澤募谎,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站阴汇,受9級特大地震影響数冬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一拐纱、第九天 我趴在偏房一處隱蔽的房頂上張望铜异。 院中可真熱鬧,春花似錦秸架、人聲如沸揍庄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚂子。三九已至,卻和暖如春缭黔,著一層夾襖步出監(jiān)牢的瞬間食茎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工馏谨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留别渔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓惧互,卻偏偏與公主長得像哎媚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子喊儡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 考慮一個(gè)問題拨与,外部的應(yīng)用如何來訪問內(nèi)部各種各樣的微服務(wù)呢?在微服務(wù)架構(gòu)中管宵,后端服務(wù)往往不直接開放給調(diào)用端,而是通過...
    weisen閱讀 2,105評論 1 9
  • (git上的源碼:https://gitee.com/rain7564/spring_microservices_...
    sprainkle閱讀 16,960評論 3 32
  • 我們都是追夢的人攀甚,無論你是什么年齡段的人箩朴,大概我們每個(gè)人心中都是有夢想的,有句話說的好:“夢想不去努力實(shí)現(xiàn)就是白日...
    A季敬媛820640閱讀 468評論 0 1
  • 公司:寧波大發(fā)化纖有限公司 姓名:馮玉停 期數(shù):六項(xiàng)精進(jìn)224期感謝二組學(xué)員秋度,234期感謝三組志工炸庞,260期感謝一...
    塵埃wyzh閱讀 104評論 0 0
  • 微詩三首 父親 山一樣的肩膀 承載了太多的負(fù)荷 海一樣的胸懷 容納了太多的辛酸 只為父子情深 母親 十月懷胎倍艱辛...
    岐麟散人閱讀 281評論 0 0