个人博客,欢迎访问:www.live4bug.com
1.Eureka注册中心
1.1 注册服务端Eureka Server
引入依赖,其中已经包含了spring-cloud的依赖,无需再引入。
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
相应的配置文件:
server:
port: ${PORT:50101}
spring:
application:
name: xc-govern-center
eureka:
client:
register-with-eureka: true # 服务注册,是否将自己注册到Eureka服务中
fetch-registry: true # 服务发现,是否从Eureka中获取注册信息
service-url: # Eureka客户端与Eureka服务端的交互地址,高可用状态配置对方的地址,单机状态配置自己(如果不配置则默认本机8761端口)
defaultZone: ${EUREKA_SERVER:http://eureka02:50102/eureka/}
server:
enable-self-preservation: false # 是否开启自我保护,本地测试不开启,实际要开启
eviction-interval-timer-in-ms: 60000 # 服务注册表清理间隔,默认60*1000毫秒
instance:
hostname: ${EUREKA_DOMAIN:eureka01} # 主机名
其中注意,defaultZone为配置的注册中心的地址(即,需要向哪里进行注册),此处的eureka02对应的是另一配置的主机名(即另一配置的instance-hostname:eureka02),而为了使该主机名能够被正确解析,需要在本机的System32-drivers-etc-host文件中进行配置,如:
127.0.0.1 eureka01
127.0.0.1 eureka02
同时,为了启动的灵活性,可以在启动时配置VM options环境参数,如下:
-DPORT=50101 -DEUREKA_DOMAIN=eureka01 -DEUREKA_SERVER=http://eureka02:50102/eureka/
最后,在启动类标识注解@EnableEurekaServer,注明该工程为注册中心服务端。
1.2 注册客户端 Eureka Client
引入依赖,其中已经包含了spring-cloud的依赖,无需再引入。
注意,此处依赖不要引错!不是spring-cloud-netflix-eureka-client !!!
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
据说没有spring-boot-starter-web会注册失败,未验证。
org.springframework.boot
spring-boot-starter-web
相应的配置文件:
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/}
instance:
prefer-ip-address: true # 将自己的ip注册到eureka服务中
ip-address: ${IP_ADDRESS:127.0.0.1}
instance-id: ${spring.application.name}:${server.port} # 指定实例id
最后,在启动类标识注解@EnableEurekaClient,注明该工程为注册中心客户端。此处,推荐使用@EnableDiscoveryClient,异同请自己百度。
2 Ribbon负载均衡
2.1 服务端/客户端负载均衡的概念
服务端负载均衡:负载均衡器维护一份服务列表。硬件设备实现,如F5,Array等;软件实现,如LVS、Nginx等。
客户端负载均衡:客户端维护一份服务列表,例如,Ribbon从注册中心获取服务列表,Ribbon根据负载均衡算法直接请求到具体的微服务(中间省去了负载均衡服务)。
两者区别:服务端负载均衡,是客户端发送请求后的接收端(即服务端)来维护服务列表,先接收信息,再根据一定的算法对列表中的项目(各微服务)进行转发,实现服务端负载均衡。客户端负载均衡:是发起者(客户端)自己维护一份服务列表(比如像Ribbon这种,从注册中心获取服务列表),然后再根据算法对列表中的项目(各微服务)进行调用。
2.2 Ribbon负载均衡的实现
Spring Cloud引入Ribbon配合 restTemplate 实现客户端负载均衡。Java中远程调用的技术有很多,如: webservice、socket、rmi、Apache HttpClient、OkHttp等,互联网项目使用基于http的客户端较多,这里使用OkHttp实现。
首先,在客户端(发起者)添加Ribbon以及远程调用技术的依赖:由于依赖了spring-cloud-starter-eureka,会自动添加spring-cloud-starter-ribbon依赖。
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
2.0.1.RELEASE
com.squareup.okhttp3
okhttp
然后,添加配置文件:
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/}
instance:
prefer-ip-address: true # 将自己的ip注册到eureka服务中
ip-address: ${IP_ADDRESS:127.0.0.1}
instance-id: ${spring.application.name}:${server.port} # 指定实例id
ribbon:
MaxAutoRetries: 2 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试
MaxAutoRetriesNextServer: 3 #切换实例的重试次数
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 6000 #请求处理的超时时间
为了一会儿实现远程调用,这时要添加相应的Bean,注意因为调用时就要执行负载均衡策略,所以在此添加@LoadBalanced注解。
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
}
完成单元测试代码:
@Autowired
RestTemplate restTemplate;
@Test
public void testRibbon(){
//在注册中心注册的服务名称
String serviceId = "XC-SERVICE-MANAGE-CMS";
for (int i = 0;i < 7;i++){
//执行远程调用方法
ResponseEntity forEntity = restTemplate
.getForEntity("http://" + serviceId + "/get", CmsPage.class);
CmsPage cmsPage = forEntity.getBody();
System.out.println(cmsPage);
}
}
进行测试:先运行注册中心项目;再运行需要被调用(服务端)的项目,通过不同端口号运行多个实例,观察注册中心,查看这些实例是已经否完成了注册;运行测试类,进行测试。
注意,添加@LoadBalanced注解后,restTemplate会走LoadBalancerInterceptor拦截器,此拦截器中会通过 RibbonLoadBalancerClient查询服务地址,可以在此类打断点观察每次调用的服务地址和端口,两个cms服务会轮 流被调用。
最初在写测试代码时一直在思考,“远程调用时的服务列表是怎么从注册中心获取的?”。后来想明白了,要想执行负载均衡,该项目本身必须要通过Eureka在注册中心进行“发现”,也就是application.yml中配置的eureka各参数,这样,自己就和注册中心有了关联,就可以获取到服务列表(很多的 “XC-SERVICE-MANAGE-CMS” 实例)。这时,restTemplate.getForEntity()方法中的http后面的服务名称(serviceId,即 “XC-SERVICE-MANAGE-CMS”) 就会去注册中心寻找相应的地址,完成远程请求。
2.3 Feign远程调用
Spring Cloud引入 Feign并且集成了Ribbon实现客户端负载均衡调用。
首先,引入Feign的依赖,这里因为Feign集成了Ribbon,所以可以把之前的Ribbon依赖注释掉。
org.springframework.cloud
spring-cloud-starter-openfeign
然后,建立一个Feign的接口,用于远程调用。注意,这里接口的url,请求类型,返回值类型都要和正常请求一样,例如@PathVariable("xxx") , @RequestParam("xxx")都一定要写全。返回值为复杂对象时,其类型必须有无参构造函数。
import com.xuecheng.framework.domain.cms.CmsPage;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "XC-SERVICE-MANAGE-CMS")
public interface CmsFeignClient {
@GetMapping("/cms/page/get/{id}")
public CmsPage findCmsPageById(@PathVariable("id") String id);
}
启动类,一定要加上 @EnableFeignClients 注解
最后,编写测试类。
@Autowired
CmsFeignClient cmsFeignClient;
@Test
public void testFeign(){
CmsPage cmsPage = cmsFeignClient.findCmsPageById("5a754adf6abb500ad05688d9");
System.out.println(cmsPage);
}
启动顺序和上一节类似。