Loading...
墨滴

努力努力再努力的石头

2021/11/21  阅读:28  主题:橙心

上手实践Spring Cloud Eureka 和 Feign

🤞 个人主页:@青Cheng序员石头
🤞 粉丝福利:加粉丝群 一对一问题解答,获取免费的丰富简历模板、提高学习资料等,做好新时代的卷卷王!

在微服务时代,服务的注册发现主要是为了解决两个问题,一个是屏蔽服务与服务之间依赖的细节,即解耦;另一个是满足对服务的动态管理。这篇文章就服务注册和发现,上手实现Netflix的Eureka和Feign。

一、服务注册发现模式

在实践之前,我们先来了解服务注册与发现的一些简单概念。
服务发现与注册 一般有两种实现模式:

  • 服务器端模式
  • 客户端模式

服务器端模式通过使用一个中间的服务器,来屏蔽被调用服务的复杂性与变动性,当有新的服务加入或老服务剔除时,只需要修改中间服务器上的配置即可。

这种模式,常见的做法是提供一个具备负载均衡的服务器作为中间层,比如Nginx,F5,网络传输层的Ip负载均衡,即配置集中在独立的中间服务器端完成,对代码没有任何侵入性。缺点是,调用链过程中,要透穿中间服务器,中间层势必成为一个调用链中的单点,很有可能成为性能的瓶颈。

蓝图编排设计.png
蓝图编排设计.png

客户端服务发现模式允许服务在没有硬编码主机名和端口的情况下彼此查找和通信。这种架构中比较核心的概念是,服务必须统一注册到服务注册中心。比较有代表性的有Eureka、Consul、Zookeeper等等,其异同如下:

image.png
image.png

这种模式不需要穿透中间服务器,所以性能损耗比较小,但是需要在服务内部维护注册信息,负载均衡策略,对代码有侵入性,并且要引入一个新的注册中心服务,如果要考虑到服务的可用性以及可靠性,其维护维护成本也会增加。

image.png
image.png

二、Eureka

Eureka作为Spring Cloud的服务注册中心,我们需要引入Spring Cloud相关的依赖,其次我们需要启动一个Eureka注册服务中心,最后为了验证服务注册的功能,需要启动一个web 服务注册到注册中心。

2.1 Eureka的Spring Cloud 依赖

首先,我们将创建一个新的 Maven pom 项目模块,并将Spring Cloud的的依赖放入,这个依赖将决定Spring Cloud 相关组件Starter的版本。

<properties>
    <version.spring-cloud>2020.0.1</version.spring-cloud>
</properties>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>${version.spring-cloud}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Spring Cloud 依赖的版本我用的比较新,根据实际工程选择合适的即可。

2.2 注册中心

我们新建一个子模块管理Eureka的注册中心服务,在这里要引入Eureka的Server依赖包。

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

然后写一个启动类Launcher,目的是把服务启动起来,包含的内容如下。

@SpringBootApplication
@EnableEurekaServer
public class Launcher {

    public static void main(String[] args) {
        SpringApplication.run(Launcher.class,args);
    }
}

application.yml的配置信息如下。

server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

此时启动服务,浏览器上访问URLhttp://{yourhost}:8761,如下图所示,表示服务注册中心启动成功,能提供服务注册和发现的功能。

screenshot-127-0-0-1-8761-1636959093343.png
screenshot-127-0-0-1-8761-1636959093343.png

2.3 服务提供方

在有了服务注册中心后,我们可以启动一个服务去注册到服务注册中心,这些服务都统统成为Eureka Client,所以要引入Client相关的依赖。

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

我们提供一个简单的greeting api接口。

public interface GreetingController {

    @GetMapping("/greeting")
    String greeting();
}

然后在启动类Launcher去实现这个接口。

@SpringBootApplication
@RestController
public class Launcher implements GreetingController {

    @Autowired
    @Lazy
    private EurekaClient eurekaClient;

    @Value("${spring.application.name}")
    private String appName;

    @Override
    public String greeting() {
        return String.format(
            "Hello from '%s'!", eurekaClient.getApplication(appName).getName());
    }

    public static void main(String[] args) {
        SpringApplication.run(Launcher.class,args);
    }
}

配置文件application.yml的内容如下。

spring:
  application:
    name: spring-cloud-eureka-client

server:
  port: 0
eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}
  instance:
    preferIpAddress: true

然后启动这个服务,观察Eureka的服务管理页面,可以看到有服务注册成功。

screenshot-127-0-0-1-8761-1636959488655.png 此时,服务的提供方也准备好了,接下来就需要去消费这个服务了。

三、Feign

这一章节我们从三个方面递进的讲Feign,第一如果没有Feign,我们将如何调用注册中心的服务;第二Feign是什么,能为我们带来哪些便利?第三,如何上手使用Feign。

3.1 如果没有Feign

为什么是Feign呢,如果不使用Feign我们该如何调用注册到Eureka上的服务呢?

如果不使用Feign,为了保证正常的服务发现和调用,我们必须要做到以下核心几步:

  • 第一步,使用Ribbon进行负载均衡
  • 第二步,获取服务的实例,并且获取根URL,再拼凑方法的URL
  • 第三步,最后使用 REST 模板或者其它方式来使用指定的服务

对于第一步,使用Ribbon获取服务实例,大致的代码如下。

 @Autowired
 private LoadBalancerClient loadBalancer; 
 
 pulic void method(){
    ServiceInstance serviceInstance=loadBalancer.choose("producer"); 
 }

对于第二步,大致的代码如下:

 pulic void method(){
    String baseUrl=serviceInstance.getUri().toString(); 
    baseUrl=baseUrl+"/targetURL";
 }

最后对于第三步,执行访问,并获取结果,大致的代码如下。

pulic void method(){
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response=null;
    try{
        response=restTemplate.exchange(baseUrl,
                    HttpMethod.GET, getHeaders(),String.class);
    }catch (Exception ex)
    {
            System.out.println(ex);
    }
    System.out.println(response.getBody());
}

在整个调用过程中,是很复杂的,我们还需要处理一些空异常等等,我们使用Feign可以做到简化以上的步骤。

image.png
image.png

3.2 Feign介绍

Feign旨在简化HTTP API客户端,它是一个声明式Web Service客户端。Fegin是一个java调用HTTP的客户端binder,其灵感来自于Retrofit、JAXRS-2.0和WebSocket。

使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解,并且Feign也支持可拔插式的编码器和解码器。

那么Feign是如何工作的呢?简单地说,Feign基于将注解转换成请求模板的方式工作,参数会简单直接的应用到模板上。具体原理不做过深的阐述。

像上面提供的未使用Feign的例子,使用Feign后其调用链图如下。

image.png
image.png

正如Eureka,Spring Cloud也提供了方便使用的OpenFeign Starter,我们将看到如何使用 Netflix Feign 使服务发现和调用变得更加容易和整洁。

3.3 上手实践

在这里,我们就使用上篇文章介绍提供的服务注册中心,和服务提供方。
首先新建一个模块,引入相关依赖。

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

注意,我们因为要去发现Eureka的提供的服务,所以还是要引入Eureka Client的依赖。
接下来提供与服务方调用一模一样的接口GreetingClient

@FeignClient("spring-cloud-eureka-client")
public interface GreetingClient {
    
    @GetMapping("/greeting")
    String greeting();
}

所以这里就有一个问题,服务提供方和消费要声明同样一套接口,按照最佳工程实践,建议把这部分接口抽象出来作为单独Modeling,然后对应的服务提供方和消费方引入这个包。

接下来是,写启动类和Web服务,为了方便,把两者都写到启动类Launcher吧。

@SpringBootApplication
@EnableFeignClients
@RestController
public class Launcher {

    @Autowired
    private GreetingClient greetingClient;

    public static void main(String[] args) {
        SpringApplication.run(Launcher.class,args);
    }

    @GetMapping("/get-greeting")
    public String greeting(){
        return greetingClient.greeting();
    }
}

application.yml配置信息如下。

spring:
  application:
    name: spring-cloud-eureka-feign-client
server:
  port: 8080
eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}

然后启动这个消费服务,观察Eureka的管理页面,可以看到这个消费方也注册到Eureka注册中心了。

screenshot-127-0-0-1-8761-1636963294276.png
screenshot-127-0-0-1-8761-1636963294276.png

然后访问http://{yourhost}:8080/get-greeting,即得到hello...的回复,代表调用链通畅。

在这个例子中,并没有引入负载均衡,如果想要做到,引入Ribbon的依赖后,在代码调用服务的地方,正常去调用远程服务即可。

    @Autowired
    private RemoteCallService loadBalancer;
    
    #服务方法中这样使用去调用远程方法去获取数据
    data tmp = loadBalancer.getData(); 

四、总结

相较而言,这一整篇文章还是比较简单,上手实践一点都不难,因为整个系列都是以入门教程为主,让读者认识到这些分布式组件为什么要提供,我们能用它们分别做什么。服务注册中心还有很多,比如Zuul、ZK等等,接下来的教程会一一讲到,敬请期待!


少年,没看够?点击石头的详情介绍,随便点点看看,说不定有惊喜呢?欢迎支持点赞/关注/评论,有你们的支持是我更文最大的动力,多谢啦!扫码关注微信公众号。

努力努力再努力的石头

2021/11/21  阅读:28  主题:橙心

作者介绍

努力努力再努力的石头