SpringCloud-Eurka-Zuul-Ribbon-Fegin負載均衡訪問叢集服務過程實戰
場景描述
應用程式A登入需要訪問使用者的資料;
在普通的mvc程式中可能就是一個控制器和DAO的實現,假設這個使用者的程式A的登入頻率異常高,那麼後臺服務的響應能力會越來越差;
通過使用SpringCloud微服務,是將一個請求使用者轉發至 Zuul 閘道器服務、由Zuul 服務在叢集服務中找個服務來給這個請求服務;這樣一來請求的頻率壓力會被叢集服務化解。
那麼本文就依照以上的應用場景來寫我們的SpringCloud服務
1、第一步建立EurekaServer
我們首先需要一個管理註冊服務的工具Eureka服務
package com.example.eurekaServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class SpingCloudEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(SpingCloudEurekaServerApplication.class, args); } }
application.properties
server.port=8888
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
eureka.client.serviceUrl.defaultZone:http://localhost:8888/eureka/
logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF
第二步 我們需要一個3個Userserver用來提供程式A的請求
可以寫一個標準的SpringBoot的rest服務
package com.example.UserServer.Controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.example.UserServer.Entity.User; import com.example.UserServer.Service.UserServiceInterface; import javax.servlet.http.HttpServletRequest; @RestController @Api(value = "Shop") public class UserServerController { @Autowired UserServiceInterface UserServiceInterface; @GetMapping @ApiOperation(value="獲取指定id使用者詳細資訊", notes="根據user的id來獲取使用者詳細資訊") @ApiImplicitParam(name = "id",value = "使用者id", dataType = "String", paramType = "path") @RequestMapping(value = "/user/{id}", method = RequestMethod.GET) public User FindUserById(@PathVariable String id , HttpServletRequest request) { System.out.println("我在被呼叫了請注意了"+request.getLocalPort()); int Userid= request.getLocalPort(); return UserServiceInterface.FindUserById(Userid); } }
但是我們的服務也要註冊到Eureka中去
package com.example.UserServer;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableDiscoveryClient
public class SpingCloudUserServerRegistryEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpingCloudUserServerRegistryEurekaApplication.class, args);
}
@RestController
class ServiceInstanceRestController {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/service-instances/{applicationName}")
public List<ServiceInstance> serviceInstancesByApplicationName(
@PathVariable String applicationName) {
return this.discoveryClient.getInstances(applicationName);
}
}}
server.port=8280
eureka.client.serviceUrl.defaultZone=http://localhost:8888/eureka/
eureka.instance.prefer-ip-address=true
spring.application.name=UserServerRegistry
通過修改不同的埠來實現註冊叢集服務啟動可以檢視下圖、說明已經註冊完畢;
第三步、我需要一個zuul閘道器元件註冊到Eureka並進行反向代理我註冊的叢集服務USERSERVERREGISTRY
package com.example.main;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class SpingCloudServerZuulEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpingCloudServerZuulEurekaApplication.class, args);
}
}
spring.application.name = Sping-Cloud-Server-Zuul
server.port=8889
eureka.client.serviceUrl.defaultZone=http://localhost:8888/eureka/
eureka.instance.instance-id= ${spring.application.name}:${spring.application.instance_id:${server.port}}
eureka.instance.prefer-ip-address=true
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds= 5000
#表示使用/userserver/user/1 代替從eureka伺服器中的userserverregistry的例項IP:埠/user/1
#其中/userserver 表示的是ServerceId的例項
zuul.routes.api-a.path = /userserver/**
zuul.routes.api-a.serviceId = userserverregistry
#配置對應服務ID的負載均衡規則
#userserverregistry.ribbon.NFLoadBalancerRuleClassName= com.netflix.loadbalancer.RandomRule
啟動該服務後Eureka中可看到第四步、使用FEIGN客戶端模擬(程式A)訪問zuul節點代理的User服務並執行請求;
配置檔案
server.port=8089
spring.application.name=user-client-byFeign
eureka.client.serviceUrl.defaultZone=http://localhost:8888/eureka/
首先要寫FeginClient
package com.example.UserConsumer.RestController;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.UserConsumer.Entity.User;
@Component
@FeignClient("Sping-Cloud-Server-Zuul")
public interface UserFeignClient {
// 這樣的方式是知道serviceid的情況
// @RequestMapping(value = "/zuul/user/{id}", method = RequestMethod.GET)
@RequestMapping(value = "/userserver/user/{id}", method = RequestMethod.GET)
public User FindUserById(@PathVariable("id") String id);
}
再寫正常的控制器、處理請求時將請求由FeginClient類處理
package com.example.UserConsumer.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.UserConsumer.Entity.User;
import org.springframework.web.client.RestTemplate;
@RestController
public class UserServerController {
/**
* 此種訪問的方式是直接通過RestTemple ribbon形式方法可以支援Serviceid訪問
*/
@Autowired
private UserFeignClient UserFeignClient;
@GetMapping
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public User FindUserById(@PathVariable String id)
{
System.out.println(id);
User findUserById = UserFeignClient.FindUserById(id);
System.out.println("我在使用通過FeignClient形式方法訪問");
return findUserById ;
}
}
最後是啟動類package com.example.UserConsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpingCloudUserConsumerZuulFeignApplication {
public static void main(String[] args) {
SpringApplication.run(SpingCloudUserConsumerZuulFeignApplication.class, args);
}
}
啟動後的效果圖
第五步;測試叢集的效果
1、有沒有發生叢集效應呢?
通過訪問http://localhost:8089/user/16565 執行3次
通過以上請注意檢視帥哥後面的埠號:
這個埠號是伺服器端的埠號 為了方便測試我將埠號返回了、由此證明訪問過程是叢集的
2、叢集返回服務的策略如何配置?
由5-1問題發現預設的叢集策略是輪詢,也就是我有10個服務 那麼訪問就一個一個來;
如果想配置其他方式也是可以的,這裡可以在zuul的服務中修改
#配置對應服務ID的負載均衡規則
userserverregistry.ribbon.NFLoadBalancerRuleClassName= com.netflix.loadbalancer.RandomRule
#userserverregistry是服務的ID
#com.netflix.loadbalancer.RandomRule是規則的全路徑
修改後重啟即可生效;
3、如果叢集中某個服務掛了、是否影響服務可用性?
如果是手動點選程式關閉是不影響的;
我們模擬一下系統強殺程序的情況來看一下是否影響
執行一下
將工作管理員中的PID為5752的java.exe立即結束;
瘋狂重新整理http://localhost:8089/user/16565
結果:完全不影響服務的可用性8080埠被強殺後、8180/8280埠仍然繼續服務;
本文相關的原始碼:https://github.com/379753498/SpringCloudDevStart
本文為原創、轉載請註明出處;