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

本文为原创、转载请注明出处;


猜你喜欢

转载自blog.csdn.net/qq_19239339/article/details/80593464
今日推荐