1.负载均衡

    负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。

 

2.服务器端负载均衡和客户端负载均衡

    1)服务器端负载均衡

        我们通常所说的负载均衡都是指服务器端的负载均衡,其分为硬件和软件负载均衡方式。

        * 硬件负载均衡:通过在服务器节点之间专门安装用于负载均衡的设备,比如F5等。

        * 软件负载均衡:通过在服务器上安装一些具有均衡负载功能或模块的软件阿里完成请求分发工作,比如Nginx等

 

    2)客户端负载均衡

        与服务器端负载均衡最大不同在于服务清单所存储的位置。

        * 服务器端负载均衡中,硬件或软件设备都会维护一个下挂可用的服务器清单列表,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常我访问的节点

        * 客户端负载均衡中,所有客户端节点都要维护着自己要访问的服务端清单列表。而这些服务端的清单来自于服务注册中心。通过心跳来维护服务端清单健康需要服务注册中心配合完成。

 

3.Ribbon的三种使用方式

    准备工作:

        1)启动一个高可用的Eureka-server

        2)创建一个服务应用,以对外提供接口服务

        3)复制一份该服务端服务,除了端口号不一致其他都保持一致,尤其spring.application.name要保持一致,用于验证在外部请求到达时是否负载均衡

        具体可参考笔者另一篇文章   

        笔者在本示例中服务应用名称设置为 part-1-sms-interface ,全部四个应用启动后,访问eureka可看到

负载均衡器IP hash 负载均衡器配置_负载均衡

    可以看到part-1-eureka为高可用eureka-server,part-1-sms-interface为服务应用集群

        4)创建项目part-1-website项目充当客户端(以下几种方式都是在该项目中实现,注意:同样需要注册到eureka中)

 

    1)RestTemplate方式(配置方式采用Eureka)

        1> 添加ribbon依赖,完整的pom.xml如下所示,同样,需要添加spring-cloud-starter-parent和spring-cloud-dependencies依赖,可以参考part-1-eureka项目

<dependencies>
		<!-- spring-boot-starter-web web项目,集成容器tomcat -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- spring-boot-starter-actuator 管理工具/web 查看堆栈,动态刷新配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- cloud eureka组件 客户端 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
		
		<!-- Ribbon依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
	</dependencies>

        2> 在Application中添加如下代码

@LoadBalanced
	@Bean
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}

重点是@LoadBalanced注释,创建RestTemplate该bean后,以后在远程调用时直接引入该RestTemplate即可

 

        3> 在Controller中添加RestTemplate依赖,并调用sms服务,代码如下

@Autowired
	private RestTemplate restTemplate;

	@RequestMapping(value="ribbontest",method=RequestMethod.GET)
	public String ribbonTest(){
		String res = "";
		ResponseEntity<String> resp = restTemplate.getForEntity("http://"+ {application_name} +"/sms/test", String.class);
		res = resp.getBody();
		return res;
	}

注意:{application_name}在本例中即为 part-1-sms-interface ,是提供给我们服务接口的应用名称

 

        4> 观察结果

        可以发现接口调用成功,笔者在不同的服务项目中打上端点,可以发现,两个服务项目都有被调用到,可以验证Ribbon的负载均衡生效。

 

    2)LoadBalancerClient(配置方式采用Eureka)

        1> 添加maven依赖,pom.xml同上

        2> 在Controller中添加LoadBalancerClient依赖,获取sms服务实例,进而获取URI等信息,并调用,代码如下

@Autowired
	private LoadBalancerClient loadBalancerClient;
	
	@Value("${part-1-sms}")
	private String application_name;
	
	// eureka发现方式
	@RequestMapping("/eureka")
	public void eureka() {
		ServiceInstance serviceInstance = loadBalancerClient.choose(application_name);
		System.out.println(serviceInstance.getUri());
		//TODO 获取URI后可以通过HTTPclient调用该URL 
	}

        注意:此时的application_name为 part-1-sms-interface,是提供给我们服务接口的应用名称

        

    3)FeginClient(配置方式采用Eureka)

        1> 添加maven依赖,pom.xml除了同上之外,还需要添加fegin依赖

<!-- spring feign-->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
		</dependency>

        2> 在Application中添加@EnableFeignClients注释,如下所示

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application {
	public static void main(String[] args) {
		new SpringApplicationBuilder(WebsiteApp.class).web(true).run(args);
	}
}

        3> Controller如下所示

@RestController
@RequestMapping("/feign")
public class TestFeignController {

	private static final String application_name = "part-1-sms-interface";
	
	@Autowired
	private FeignEurekaClient feignEurekaClient;
	
	@RequestMapping("/eureka")
	public void index(){
		System.out.println(feignEurekaClient.smsTest());
	}
	
	@FeignClient(name = application_name)
	interface FeignEurekaClient{
		@RequestMapping("/sms/test")
		public String smsTest();
	}
}

 

        注意:

        * 需要手动写一个interface FeignEurekaClient,

        * @FeignClient中的name即我们需要调用的服务名称

        * @RequestMapping方法对应的value即我们需要调用的具体服务接口路径;

        * 需要手动添加FeignEurekaClient依赖

 

        4> 观察结果,同前

 

4.Ribbon的三种配置方式

    Ribbon有三种配置方式:Eureka方式、Annotation方式、Properties方式

    下面展示RestTemplate的使用方式下三种配置方式的具体实现(注意:客户端配置同上即可)

    1)Eureka配置方式(查看上述方式3-1即可)

    2)Annotation方式

        1> 创建类RibbonAnnotationConfiguration,代码如下

@Configuration
public class RibbonAnnotationConfiguration {

	@Bean
	public ServerList<Server> ribbonServerList() {
		// 实例列表
		String listOfServers = "http://localhost:1108,http://localhost:1109";
		String[] splits = listOfServers.split(",");
		int len = splits.length;
		
		Server[] servers = new Server[len];
		for (int i = 0; i < len; i++) {
			servers[i] = new Server(splits[i].trim());
		}
		return new StaticServerList<Server>(servers);
	}
	
	@Bean
	public IRule ribbonRule() {
		return new RoundRobinRule();
	}
}

    注意:方法名要保持一致,重点是ribbonServerList方法,将服务接口所在地址需列出

        2> 在Controller类上添加注解@RibbonClients,并调用相关方法

@RestController
@RequestMapping("/web")
@RibbonClients(value={@RibbonClient(name="service-by-annotation",configuration = RibbonAnnotationConfiguration.class)})
public class TestController {

    注意:此时就定义了Configuration与name的对应关系,下面我们在接口中直接使用该name

@RequestMapping(value="ribbonAnnotest",method=RequestMethod.GET)
	public String ribbonAnnotest(){
		
		String res = "";
		ResponseEntity<String> resp = restTemplate.getForEntity("http://"+ "service-by-annotation" +"/sms/test", String.class);
		res = resp.getBody();
		return res;
	}

        3> 验证,结果同上

 

    3)Properties方式

        1> 在application.yml文件中添加服务相关配置文件

# 定义一个针对service-by-properties服务的负载均衡器。服务实例信息来自配置文件
# 服务名
service-by-properties:
  # 服务实例列表
  listOfServers: http://localhost:1108,http://localhost:1109
  # 这个负载均衡器不做重试
  MaxAutoRetriesNextServer: 0
  MaxAutoRetries: 0
  ribbon:
    # 负载策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    # 设置它的服务实例信息来自配置文件, 如果不设置NIWSServerListClassName就会去euereka里面找
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList

    注意:listOfServers即服务接口所在地址

 

        2> 在Controller类中添加相关调用方法

@RequestMapping(value="ribbonProptest",method=RequestMethod.GET)
	public String ribbonProptest(){
		
		String res = "";
		ResponseEntity<String> resp = restTemplate.getForEntity("http://"+ "service-by-properties" +"/sms/test", String.class);
		res = resp.getBody();
		return res;
	}

    注意:service-by-properties即我们在yml文件中定义的服务名

 

        3> 验证,结果同上

 

通过以上配置方式的使用,可以发现最好用的还是Eureka方式,让注册中心维护服务所在地址,我们只需要调用服务名即可,负载均衡和服务发现交给框架来解决即可