1. 程式人生 > >SpringCloud-Eurka-Zuul-Ribbon-Fegin負載均衡訪問叢集服務過程實戰

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

本文為原創、轉載請註明出處;