springCloud Learning 2 (service discovery)

First, the service discovery architecture

  Service discovery architecture typically has the following four concepts:

  1. Service Registration: how to use the service discovery service agents to register?
  2. Customer service address can find: what services the client is to find service information?
  3. Information sharing: How to share service information across nodes?
  4. Health monitoring: how to serve its health information back to the service discovery agent?

The following figure shows the flow of these four concepts, as well as cases usually occur in the implementation of service discovery mode:

  Examples of services usually found only in one instance registered service, then the service discovery data transmission, so that each service instance between instances registered to all service discovery instance. Service after the discovery of registration to the service instance, this service can be called a service consumer. Service consumers can use a variety of models to "discover" service.

  1. Each time a service call to get the target service address through service discovery layer and make the call. This use is relatively small, many drawbacks. First, each service invocation is done by the service discovery layer, it will be time-consuming than a direct call. The most important is that this method is very fragile, totally dependent on the consumer side service discovery layer to locate and invoke the service.
  2. A more robust approach is to use a so-called client load balancing.

  As shown below:

  In this model, when service consumers need to call a service:

  (1) Information service discovery layers get all service instances of the requested service, and then into the local cache.

  (2) Each time the service call, a location service consumer withdraws from the cache service instance, typically the 'remove' simple copy equalization algorithm, such as "polling", "random", to ensure distribution of the service invocation in between all instances.

  (3) The client will periodically communicate with the service discovery layer, and flush the cache service instance.

  (4) If during a call to service, a service call fails, then the local cache will refresh the data layer service discovery, try again.

Two, spring cloud combat

  Use spring cloud and Netflix Eureka build a service discovery instance.

1, Spring Eureka building service

  eurekasvr POM main configuration is as follows:

<!-- 其他依赖省略 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
复制代码

  applicaiton.yml configuration is as follows:

server:
  port: 8761

eureka:
  client:
    #不注册自己
    register-with-eureka: false
    #不在本地缓存注册表信息
    fetch-registry: false
  server:
    #接受请求前的等待实际,开发模式下不要开启
    #wait-time-in-ms-when-sync-empty: 5
复制代码

  Finally comments in the class start @SpringBootApplicationto start the service center. Service Management Center page: HTTP: // localhost: 8761

2, the service registered with the service center

  Here we write a new service registration to the service center, organizationservice: organization services. And on one of two services: confsvr: Configuration Center, licensingservice: Authorized Service registration to the service center.

a, confvr registration

  To modify the POM file:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
复制代码

  Then modify the configuration file application.yml:

server:
  port: 8888

eureka:
  instance:
    #注册服务的IP,而不是服务器名
    prefer-ip-address: true
  client:
    #向eureka注册服务
    register-with-eureka: true
    #拉取注册表的本地副本
    fetch-registry: true
    service-url:
      #Eureka服务的位置(如果有多个注册中心,使用,分隔)
      defaultZone: http://localhost:8761/eureka/

spring:
  profiles:
    # 使用文件系统来存储配置信息,需要设置为native
    active: native
  application:
    name: confsvr
  cloud:
    config:
      server:
        native:
          # 使用文件来存放配置文件,为每个应用程序提供用逗号分隔的文件夹列表
          searchLocations: file:///D:/configFolder/licensingservice,file:///D:/configFolder/organizationservice
复制代码

  Finally startup class annotations @EnableDiscoveryClient, start page can be found at eureka management.

b, licensingservice registration

  To modify the POM

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
复制代码

  Then modify the configuration file bootstrap.yml

spring:
  application:
    #指定名称,以便spring cloud config客户端知道查找哪个配置
    name: licensingservice
  profiles:
    #指定环境
    active: dev
  cloud:
    config:
      #设为true便会自动获取从配置中心获取配置文件
      enabled: true
eureka:
  instance:
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/
复制代码

  Finally, start adding annotations like @EnableDiscoveryClientto start this service instance can be found in eureka management page.

c, create organizationservice

  First in the folder file: /// D: / configFolder / organizationservice created under two profiles: organizationservice.yml, organizationservice-dev.yml, the contents are as follows:

#organizationservice-dev.yml
server:
  port: 10012
复制代码
#organizationservice.yml
spring:
  application:
    name: organizationservice
复制代码

  The main POM configuration is as follows:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-client</artifactId>
</dependency>
复制代码

  Then modify the configuration file, bootstrap.yml

spring:
  application:
    #指定名称,以便spring cloud config客户端知道查找哪个配置
    name: organizationservice
  profiles:
    #指定环境
    active: dev
  cloud:
    config:
      enabled: true
eureka:
  instance:
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/
复制代码

  Finally, add an annotation classes start @EnableDiscoveryClient, start.

3, using the service to find discovery service

  There are already two registrars, and now the license to make a service call service organization, access to organizational information. First, a controller class in organizationservice added service package controller, it is possible to respond to the request:

//OrganizationController.java
@RestController
public class OrganizationController {

    @GetMapping(value = "/organization/{orgId}")
    public Object getOrganizationInfo(@PathVariable("orgId") String orgId) {
        Map<String, String> data = new HashMap<>(2);
        data.put("id", orgId);
        data.put("name", orgId + "公司");
        return data;
    }
}
复制代码

  Let license service to find the actual location of the service organization by Eureka, then call the interface. In order to achieve the purpose, we are going to learn three different Spring / Netflix client library, service consumers can use them to interact and Ribbon. From the lowest level to the highest level, these libraries contain different levels of abstraction packages to interact with the Ribbon:

  • Spring DiscoveryClient
  • Enabled RestTemplate of Spring DiscoveryClient
  • Neflix Feign client

a、使用 Spring DiscoveryClient

  The tool provides access to the lowest level registered in Service Ribbon and Ribbon cache can be queried by all services registered with Eureka and the URL corresponding to those services.

  First class licensingservice added to the start of the @EnableDiscoveryClientannotation to enable DiscoveryClient and Ribbon library.

  Then create OrganizationService.java in the service pack

@Service
public class OrganizationService {

    private static final String SERVICE_NAME = "organizationservice";
    private DiscoveryClient discoveryClient;

    @Autowired
    public OrganizationService(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    /**
     * 使用Spring DiscoveryClient查询
     *
     * @param id
     * @return
     */
    public Organization getOrganization(String id) {
        RestTemplate restTemplate = new RestTemplate();
        List<ServiceInstance> instances = discoveryClient.getInstances(SERVICE_NAME);
        if (instances.size() == 0) {
            throw new RuntimeException("无可用的服务");
        }
        String serviceUri = String.format("%s/organization/%s", instances.get(0).getUri().toString(), id);
        ResponseEntity<Organization> responseEntity = restTemplate.exchange(serviceUri, HttpMethod.GET
                , null, Organization.class, id);
        return responseEntity.getBody();
    }
}
复制代码

  Then a new packet in the controller LicensingController.java

@RestController
public class LicensingController {

    private OrganizationService organizationService;

    @Autowired
    public LicensingController(OrganizationService organizationService) {
        this.organizationService = organizationService;
    }

    @GetMapping("/licensing/{orgId}")
    public Licensing getLicensing(@PathVariable("orgId") String orgId) {
        Licensing licensing = new Licensing();
        licensing.setValid(false);
        licensing.setOrganization(organizationService.getOrganization(orgId));
        return licensing;
    }
}
复制代码

  Start all items, visit localhost: 10011 / Licensing / 12 , we can see the return the following results:

{
  "organization": {
    "id": "12",
    "name": "12公司"
  },
  "valid": false
}
复制代码

  In the actual development, essentially less than this, except for the query Ribbon for all instances of a service of information, it will be used directly. If it exists directly using the following two questions:

  1. Do not use the Ribbon client load balancing
  2. And business-independent code writing too much

b, using a function with Ribbon Spring RestTemplate call service

  This method is one of the micro-mechanism more common service communication. To activate this feature, you need to use Spring Cloud @LoadBanced annotation to define the constructor RestTemplate bean. Convenience defined directly in the starting bean class:

#LicensingserviceApplication.java
@SpringBootApplication
@EnableDiscoveryClient  //使用不带Ribbon功能的Spring RestTemplate,其他情况下可删除
public class LicensingserviceApplication {

    /**
     * 使用带有Ribbon 功能的Spring RestTemplate,其他情况可删除
     */
    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(LicensingserviceApplication.class, args);
    }
}
复制代码

  Then increased at a service package type: OrganizationByRibbonService.java

@Component
public class OrganizationByRibbonService {

    private RestTemplate restTemplate;

    @Autowired
    public OrganizationByRibbonService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public Organization getOrganizationWithRibbon(String id) {
        ResponseEntity<Organization> responseEntity = restTemplate.exchange("http://organizationservice/organization/{id}",
                HttpMethod.GET, null, Organization.class, id);
        return responseEntity.getBody();
    }
}
复制代码

  The last is an access path in LicensingController.js Canada:

//不要忘记注入OrganizationByRibbonService服务
@GetMapping("/licensingByRibbon/{orgId}")
    public Licensing getLicensingByRibbon(@PathVariable("orgId") String orgId) {
        Licensing licensing = new Licensing();
        licensing.setValid(false);
        licensing.setOrganization(organizationService.getOrganization(orgId));
        return licensing;
    }
}
复制代码

  Access localhost: 10011 / licensingByRibbon / 113 , you can see the results.

c, use Netflix Feign client calls

  Feign Spring-enabled client is an alternative to the Ribbon RestTemplate class. Developers only need to define an interface, and then use the Spring annotation to mark the interface, you can call the target service. In addition to writing other auxiliary interface definition without writing code.

  First start classes plus a @EnableFeignClientscomment feign enabled client. Was then added in the POM dependent Feign

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
复制代码

  Then a new client package at OrganizationFeignClient.java

@FeignClient("organizationservice")//使用FeignClient注解指定目标服务
public interface OrganizationFeignClient {

    /**
     * 获取组织信息
     *
     * @param orgId 组织id
     * @return Organization
     */
    @RequestMapping(method = RequestMethod.GET, value = "/organization/{orgId}", consumes = "application/json")
    Organization getOrganization(@PathVariable("orgId") String orgId);
}
复制代码

  Last modified LicensingController.javaby adding a routing calls Feign.

//注入OrganizationFeignClient,使用构造注入

@GetMapping("/licensingByFeign/{orgId}")
public Licensing getLicensingByFeign(@PathVariable("orgId") String orgId) {
    Licensing licensing = new Licensing();
    licensing.setValid(false);
    licensing.setOrganization(organizationFeignClient.getOrganization(orgId));
    return licensing;
}
复制代码

Access localhost: 10011 / licensingByFeign / 11313 , you can see the results.

to sum up

  This section lounged wrote for several days, although the example is very simple, but believe it should be able to read it. Due to space reasons not all codes affixed, want to see the complete code, click on the link under the hair.

Benpian code to be placed on: GitHub

Benpian Original Posted: tapme.top/blog/detail...

Scan code concerned about micro-channel public number: FleyX study notes, for more dry goods

Reproduced in: https: //juejin.im/post/5d01a69251882519371f2fae

Guess you like

Origin blog.csdn.net/weixin_34100227/article/details/93181402