Spring Cloud 微服務實踐(1) - 用Initializr初始化

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"紙上得來終覺淺,絕知此事要躬行。這裏我們就直接用Spring Initializr來初始化Spring Cloud項目,然後作一點配置,寫幾句代碼,用比較笨的形式,“徒手”擼一個包含服務發現、網關和業務處理的開發環境版微服務。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1、先看看包含哪些模塊(子項目)"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回顧一下我們在《開篇》中提到的簡化版微服務"}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/80c9e7626ab30ac90362afe1a64b7ceb.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務發現與網關幾乎不需要寫代碼,配置一下就可以跑起來,然後業務實現也暫時Say Hello,點到爲止,重點是我們怎麼把他們揉到一起。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2、用 Spring Initializr 初始化 Eureka Server"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring Initializr 是Spring.io提供的一個Web應用,使用瀏覽器打開"},{"type":"link","attrs":{"href":"https://start.spring.io/","title":null},"content":[{"type":"text","text":"https://start.spring.io"}]},{"type":"text","text":" 就能使用,它的功能就是爲你初始化一個基本的Spring Boot項目,並根據需要來加載用到的依賴。Spring Initializr也可以在Spring Tool Suite中使用,IntelliJ IDEA也做了集成。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了體現”從零開始“,我們就用瀏覽器訪問"},{"type":"link","attrs":{"href":"https://start.spring.io","title":""},"content":[{"type":"text","text":"https://start.spring.io"}]},{"type":"text","text":"來初始化項目。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cc/ccab059ea34e79b6843fc8f4aae5369b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Project選Maven Project,使用Maven構建項目。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發語言Language選Java。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Project Metadata可以隨意填,我這裏把Artifact改成eureka-server。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打包方式(Packaging)爲Jar。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java版本選8。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然後依賴(Dependency)增加一個“Eureka Server”和“Spring Boot Actuator”。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後點擊“GENERATE”按鈕會下載一個zip文件,解壓後就是我們的服務註冊與發現項目。我這裏因爲Artifact填的“eureka-server“,所以得到的文件是eureka-server.zip,後續也會用eureka-server代指這個項目。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解壓後,就是Spring Initializr爲我們生成的eureka-server項目的基本文件和結構。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/62/62cab1937154e55bac74cfbbe7f0982f.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果熟悉maven和git,解壓後得到的這些文件就無需多說什麼了"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我們看一下pom.xml文件,主要是看依賴,中文是我加的註解,其他都是Spring Initializr生成的:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\n\n\t4.0.0\n\t\n\t\torg.springframework.boot\n\t\tspring-boot-starter-parent\n \n\t\t2.3.3.RELEASE\n\t\t \n\t\n\tcom.example\n\teureka-server\n\t0.0.1-SNAPSHOT\n\teureka-server\n\tDemo project for Spring Boot\n\n\t\n\t\t1.8\n \n\t\tHoxton.SR8\n\t\n\n\t\n \n\t\t\n\t\t\torg.springframework.cloud\n\t\t\tspring-cloud-starter-netflix-eureka-server\n\t\t\n\n \n\t\t\n\t\t\torg.springframework.boot\n\t\t\tspring-boot-starter-actuator\n\t\t\n\n \n\t\t\n\t\t\torg.springframework.boot\n\t\t\tspring-boot-starter-test\n\t\t\ttest\n\t\t\t\n\t\t\t\t\n\t\t\t\t\torg.junit.vintage\n\t\t\t\t\tjunit-vintage-engine\n\t\t\t\t\n\t\t\t\n\t\t\n\t\n\n\t\n\t\t\n\t\t\t\n\t\t\t\torg.springframework.cloud\n\t\t\t\tspring-cloud-dependencies\n\t\t\t\t${spring-cloud.version}\n\t\t\t\tpom\n\t\t\t\timport\n\t\t\t\n\t\t\n\t\n\n\t\n\t\t\n\t\t\t\n\t\t\t\torg.springframework.boot\n\t\t\t\tspring-boot-maven-plugin\n\t\t\t\n\t\t\n\t\n\n\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"熟悉Spring Boot的話,會發現大部分都是Spring Boot相關的配置,只有group id爲org.springframework.cloud的纔是微服務的內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意:"},{"type":"text","text":"Spring Boot的版本是2.3.3,Spring Cloud的版本是Hoxton.SR8,這兩者的版本一定要匹配,不然容易出一些莫名其妙的問題。我們可以訪問"},{"type":"link","attrs":{"href":"https://start.spring.io/actuator/info","title":""},"content":[{"type":"text","text":"https://start.spring.io/actuator/info"}]},{"type":"text","text":" 這個地址來獲取Spring Boot和Spring Cloud的版本對應關係,比如說:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"\"Hoxton.SR8\":\"Spring Boot >=2.2.0.M4 and <2.3.4.BUILD-SNAPSHOT\""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3、配置Eureka Server - 實現服務註冊與發現"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開源代碼: "},{"type":"link","attrs":{"href":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/eureka-server","title":""},"content":[{"type":"text","text":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/eureka-server"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開src\\main\\java\\com\\example\\eurekaserver\\EurekaServerApplication.java,添加註解@EnableEurekaServer,開啓註冊中心能力。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a8/a8890297fb0b2d9d15488d4e84827dac.png","alt":null,"title":"開啓 Eureka Server 能力","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把src\\main\\resources\\application.properties刪除,增加文件application.yml:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"server:\n port: 8761\n address: localhost\n servlet:\n context-path: /\n\nspring:\n profiles:\n active: dev\n application:\n name: eureka-server\n\neureka:\n instance:\n hostname: localhost\n client:\n #這個服務本身是註冊中心,不用自己向自己註冊\n register-with-eureka: false\n fetch-registry: false\n service-url:\n defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/\n\nmanagement:\n endpoints:\n web:\n exposure:\n include: [\"health\",\"info\", \"shutdown\"]\n endpoint:\n health:\n show-details: always\n shutdown:\n enabled: true\n server:\n port: 7761"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4、編譯和運行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Maven項目的編譯都一樣,命令是“mvn install”,我一般習慣再加一個clean先清理一下,所以就是“mvn clean install”。如果想跳過測試加快編譯速度,則可以加上“-DskipTests”參數,完整的命令就是“mvn clean install -DskipTests”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring Boot項目的運行,測試時可以在命令行或者PowerShell直接用maven運行:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"mvn spring-boot:run"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編譯成jar文件後,也可以直接運行jar文件,這裏以eureka-server爲例:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"cd target\njava -jar eureka-server-0.0.1-SNAPSHOT.jar"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5、Eureka Server自帶的UI"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"eureka-server項目啓動後,可以在"},{"type":"link","attrs":{"href":"http://localhost:8761","title":""},"content":[{"type":"text","text":"http://localhost:8761"}]},{"type":"text","text":"查看註冊到服務中心的微服務的信息。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/40/40d9dc9521c844f546473c9bdb8499d1.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前暫時還沒有服務註冊到eureka server,紅色的警告也不用管它,是Eureka的自檢,測試環境容易出現這個問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"6、網關 Spring Cloud Gateway"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了前面eureka-server的搭建經驗後,其他微服務我們就簡化一下,只列出我覺得重要的內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開源代碼: "},{"type":"link","attrs":{"href":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/gateway","title":""},"content":[{"type":"text","text":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/gateway"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還是用Spring Initializr進行項目初始化,pom.xml如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" ...\n\tgateway\n\t0.0.1-SNAPSHOT\n\tgateway\n\t...\n\n\t\n ...\n \n\t\t\torg.springframework.cloud\n\t\t\tspring-cloud-starter-netflix-eureka-client\n\t\t\n \n\t\t\n\t\t\torg.springframework.cloud\n\t\t\tspring-cloud-starter-gateway\n\t\t\n ...\n\t\n ..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"主要是添加了eureka-client和gateway的依賴。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"修改GatewayApplication.java,增加服務發現客戶端的註解,表示這是一個Eureka Client,要向服務中心(Eureka Server)註冊,以便其他服務可以發現它。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\n\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class GatewayApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(GatewayApplication.class, args);\n\t}\n\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"application.yml的配置如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\nserver:\n port: 8080\n address: localhost\n servlet:\n context-path: /\n\nspring:\n profiles:\n active: dev\n application:\n name: gateway\n cloud:\n gateway:\n discovery:\n locator:\n #自動發現並路由到微服務\n #與服務發現Eureka Server進行結合,通過Service Id轉發到具體的服務實例,默認爲false。\n enabled: true\n \n #小寫ServiceId,默認是false\n #這裏是個坑,從Eureka Server註冊中心獲取的Service Id是大寫的\n lower-case-service-id: true\n\neureka:\n client:\n service-url:\n #註冊中心的地址,要對應eureka-server的配置\n defaultZone: http://localhost:8761/eureka/\n\nmanagement:\n endpoints:\n web:\n exposure:\n include: [\"health\",\"info\", \"shutdown\"]\n endpoint:\n health:\n show-details: always\n shutdown:\n enabled: true\n server:\n port: 7080\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"網關編譯啓動後,可以去Eureka Server看看網關是否已註冊:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fc/fcc9e91c55bc2313012843d637ba6f23.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"7、微服務 Service One"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Eureka Server和Gateway都是Spring Cloud自帶的爲微服務架構服務的功能,接着我們實現一個“真正的業務”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開源代碼: "},{"type":"link","attrs":{"href":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/service-one","title":""},"content":[{"type":"text","text":"https://github.com/xiaoboey/from-zero-to-n/tree/master/zero/service-one"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還是用Spring Initializr進行項目初始化,這次是一個Spring MVC應用,pom.xml如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" ...\n\tservice-one\n\t0.0.1-SNAPSHOT\n\tservice-one\n\t...\n\n\t\n ...\n \n\t\t\torg.springframework.cloud\n\t\t\tspring-cloud-starter-netflix-eureka-client\n\t\t\n \n\t\t\n\t\t\torg.springframework.boot\n\t\t\tspring-boot-starter-web\n\t\t\n ...\n\t\n ..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"跟Gateway一樣,都通過註解開啓服務發現客戶端能力,修改ServiceOneApplication.java:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\n\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class ServiceOneApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ServiceOneApplication.class, args);\n\t}\n\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"application.yml:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"server:\n port: 8081\n #把address註釋掉,避免網關轉發請求過來時,因爲地址發生變化而拒絕連接(Connection refused)\n #address: localhost\n servlet:\n context-path: /\n\nspring:\n profiles:\n active: dev\n application:\n name: service-one\n\neureka:\n client:\n service-url:\n defaultZone: http://localhost:8761/eureka/\n\nmanagement:\n endpoints:\n web:\n exposure:\n include: [\"health\",\"info\", \"shutdown\"]\n endpoint:\n health:\n show-details: always\n shutdown:\n enabled: true\n server:\n port: 7081"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫一個Controller,實現一個hello方法:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class OneController {\n @RequestMapping(\"/hello\")\n public String hello() {\n return \"Hello!\";\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編譯啓動後,訪問"},{"type":"link","attrs":{"href":"http://localhost:8081/hello","title":""},"content":[{"type":"text","text":"http://localhost:8081/hello"}]},{"type":"text","text":" ,不出意外的話,Service One會立馬響應一個“Hello!”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再訪問"},{"type":"link","attrs":{"href":"http://localhost:8080/service-one/hello","title":""},"content":[{"type":"text","text":"http://localhost:8080/service-one/hello"}]},{"type":"text","text":" 看看,是不是一樣的效果?說明網關自動把請求轉發過來了,而Service One這個應用的信息,網關Gateway是從Eureka Server上的註冊信息裏獲取到的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"8、網關的負載均衡"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到目前爲止,我們搭建了一個最簡單的微服務“集羣”,網關(Gateway)接受外部的請求,然後轉發到內部的業務實現(Service One)上進行處理,並將結果反饋回去。如果只是這樣的話,微服務的優勢在哪裏呢?這個Service One直接暴露給外部調用也是OK的呀?"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們再擴展一下Service One,提供多一點服務,並且啓動多個Service One來看一下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"增加getPort方法,返回服務的端口(application.yml中的server.port):"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class OneController {\n @RequestMapping(\"/hello\")\n public String hello() {\n return \"Hello!\";\n }\n\n @Value((\"${server.port}\"))\n private int port;\n \n @RequestMapping(\"/getPort\")\n public int getPort() {\n return port;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編譯後啓動,訪問"},{"type":"link","attrs":{"href":"http://localhost:8080/service-one/getPort","title":""},"content":[{"type":"text","text":"http://localhost:8080/service-one/getPort"}]},{"type":"text","text":" ,得到一個端口號,這是application.yml中配置的端口(server.port)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開啓一個新的cmd或者shell,進入到service-one項目的pom.xml文件那級路徑,再啓動一個Service One,並指定不同的端口:server.port=8082,management.server.port=7082"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"mvn spring-boot:run -Dspring-boot.run.arguments=\"--server.port=8082 --management.server.port=7082\"\n#如果是PowerShell,帶=號的參數要用單引號引起來才能正確傳遞\nmvn spring-boot:run -D'spring-boot.run.arguments=\"--server.port=8082 --management.server.port=7082\"'"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在在瀏覽器裏多刷新幾次"},{"type":"link","attrs":{"href":"http://localhost:8080/service-one/getPort","title":""},"content":[{"type":"text","text":"http://localhost:8080/service-one/getPort"}]},{"type":"text","text":" ,可以發現返回的端口號發生了變化,說明網關把請求轉發到Service One的每個實例上。我們可以繼續啓動更多的服務實例,並模擬大量的請求來測試。測試的結果是網關(Gateway)把請求平均分發給每個實例,體現了微服務在“彈性伸縮、獨立部署”上的優勢。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/53/530e7e3f2c04ea80733d5d319973eb94.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"9、宕機測試"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了有計劃的停止,在實際的生產環境,服務器宕機或其他故障也可能會讓服務啞火,失去響應。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面說“彈性伸縮”,其實我們只測試了“伸”(增加更多的服務實例),還沒測試“縮”(減少實例),那就試試停止一個Service One,再去反覆刷新getPort看看會發生什麼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"反覆刷新的情況下,有時會出現響應變慢,然後錯誤“Internal Server Error, status=500”。這是因爲Client失聯或者停止後,Eureka Server還沒get到這個狀態,Gateway繼續往停擺的服務轉發請求,導致錯誤。直到註冊中心把這個失聯的服務剔除掉並通知網關,一切才恢復正常。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"宕機導致的服務異常,對終端用戶的使用是有影響的,需要解決。並且Spring Cloud Gateway代理轉發請求給後端的服務實例,這個工作其實nginx也可以勝任,在某些方面甚至更好。所以到目前爲止,微服務的優勢還沒體現出來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所謂“師傅領進門,修行在個人”,通過這篇“入門”上手找到感覺之後,剩下的就是針對具體的需求和問題,去慢慢探索解決,積累經驗,踐行微服務開發方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上一篇: 《"},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/2e804cfaf1084de339601f201","title":null},"content":[{"type":"text","text":"Spring Cloud 微服務實踐(0) - 開篇閒話"}],"marks":[{"type":"strong"}]},{"type":"text","text":"》"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下一篇: 《"},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/cd424bd23643af21a0c2eec42","title":null},"content":[{"type":"text","text":"Spring Cloud 微服務實踐(2) - Gateway重試機制 "}],"marks":[{"type":"strong"}]},{"type":"text","text":"》"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章