微服务SpringCloud

个人博客,欢迎访问:www.live4bug.com

1.Eureka注册中心

1.1 注册服务端Eureka Server

引入依赖,其中已经包含了spring-cloud的依赖,无需再引入。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
 </dependency>

相应的配置文件:

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 !!!
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
    
据说没有spring-boot-starter-web会注册失败,未验证。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>            

相应的配置文件:

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依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>
    
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
</dependency>

然后,添加配置文件:

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<CmsPage> 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依赖注释掉。

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

然后,建立一个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);
}

启动顺序和上一节类似。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容