SPRING CLOUD micro service DEMO- Part I

1. Micro Services Architecture

System Architecture Evolution from a single application, according to the vertical resolution of each module, the distributed services, SOA, now evolved into the micro-service state.

Features Micro services

  • Single Responsibility: micro-services Each service corresponds to a unique business ability, so single responsibility
  • Micro: Split Service small size micro-services, for example, a user can be managed as a service. Each service is small, but "perfectly formed."
  • Service-oriented: each service-oriented service is said to be exposed to the external service interface API. Do not care about technology services, has nothing to do with the platform and language, is not limited by what technology, as long as the interface to provide Rest.
  • Autonomy: Autonomy is a saying among service independent of each other without disturbing each other
    • Team Independent: Each service is an independent development team, the number of not too much.
    • Technology Independence: Because it is service-oriented, providing Rest interfaces, what technology does not interfere with others
    • Before and after the end of the separation: The separation of front and back end development, Rest provide a unified interface to the back-end is no longer PC, mobile segment development of different interfaces
    • Database Separation: Each service uses its own data sources
    • Independent deployment, although there is room service calls, but to do the service restarted without affecting other services. Conducive to continuous integration and continuous delivery. Each service component is independent, reusable, alternatively, reduce the coupling, easy to maintain

2. Remote invocation

2.1 RPC/RMI

RPC: Remote Produce Call the remote procedure call, there are similar RMI. Custom data formats, native TCP-based communication, high speed and efficiency . Early webservice, now popular dubbo, are typical RPC

2.2 Http

Http: http actually a network transmission protocol, based on TCP, specifies the format of data transmission. Now the client browser and server communications are basically using Http protocol. It can also be used for remote service call. The disadvantage is that encapsulation message bloated.

2.3 How to choose

Since the two methods can achieve remote call, how do we choose?

  • Speed ​​point of view, RPC faster than http, although the underlying are TCP, but the information is often more bloated http protocol, but gzip compression can be used.
  • The difficulty of view, RPC achieve more complex, http relatively simple
  • Flexibility of view, http better, because it does not care about the implementation details, cross-platform, cross-language. RPC needs to be packaged in a manner API level, limiting the development of the language environment.

Therefore, both have different usage scenarios:

  • If higher efficiency requirements, and development processes using a unified technology stack, then use RPC is good.
  • If you need to be more flexible, cross-language, cross-platform, is clearly more appropriate http

Micro service, greater emphasis is independent, autonomous and flexible. RPC is limited way more, so micro-services framework, usually based Http Rest style of service.

3. Http Client Tools

You can use some of the popular open-source tool Http client requests Rest Interface

  • HttpClient
  • OKHttp
  • URLConnection

3.1 Rest Template

After using Http client requests Rest tool interfaces, to obtain data deserialized into objects. It is more work, Spring provides a RestTemplatetemplate-based tool for Http client package (using URLConnection default), to achieve the objects and serialization and deserialization of Json, very convenient. Spring Boot project to build a following, while demonstrating how to use RestTemplate.

4. Spring Boot building project

An important feature is the micro-services each service is an independently run project , if built according to the previous way of SSM can not be done quickly build and deploy services. So Spring Boot came into being, its concept is greater than the agreed configuration, you choose the right module, automatically help you build a good environment, very convenient.

Next Spring Boot with a simple user to build two micro-services: user-serviceand user-consume, the functions are: the User-Consume use RestTemplate call user-service service .

With specific reference to this note (sub-article) SPRING BOOT build two micro-service module

5. Spring Cloud Profile

Spring Cloud technology is micro-services architecture. It incorporates a number of micro Netflix's service components. (If you do not know this company, then you certainly do not like to watch American TV.)

Netflix micro Services Architecture Figure

  • Eureka: Registry
  • Zuul: Services Gateway
  • Ribbon: Load Balancing
  • Feign: service call
  • Hystix: Fuse

6. The micro-simulation scenario Service

In the fourth quarter we have built a good user-serviceand user-consumetwo micro-services.

Use rest interfaces consume RestTemplate calls the service provided by the data obtained json, User deserialized into objects to return to the foreground. Where there are some problems:

  • Address rest interfaces consume calls is hard-coded, convenient maintenance.
  • If the rest of the service interface to change or shut down, consume and knowledge, ultimately nothing.
  • only one service station, once down, the entire service is not available. If more than one extension, that consume but also to consider their own load balancing.

The next several components is introduced to solve these problems and students.

7. Eureka registry

7.1 Introduction

Eureka responsible for micro-management services.

If a project dozens of micro-services, the caller wants to find himself a suitable, available micro-services it is a very troublesome thing.

就比如你想要坐车出门,自己上街拦出租车就很麻烦,要么司机拒载,要么车里已经有人了,要么干脆就没有车来...后来就出现了滴滴,做为一个网约车的“注册中心”,可以为你分配离你最近的空闲出租车。

Eureka就好比是滴滴,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。

同时,服务提供方与Eureka之间通过“心跳”机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。

这就实现了服务的自动注册、发现、状态监控。

7.2 原理图

  • EurekaServer:注册中心,可以是多个Eureka的集群,对外暴露自己的地址。
  • 服务提供者:启动后在注册中心中注册,成功后定期使用http方法向注册中心发送心跳包,表明自己还活着。
  • 客户端消费者:向注册中心订阅服务。注册中心会向消费者发送合适的服务提供者列表,并且定期更新。需要使用某个服务时,可以从列表中找到并调用。

7.3 搭建注册中心

搭建过程和第4节说的一样,注意选择Eureka模块即可。

7.3.1 代码和配置文件

  • 启动类

@EnableEurekaServer注解表示这是一个注册中心

@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}
  • 配置文件

现在我们只启动一个eureka作为注册中心。

这是Spring官方文档中的Standalone Eureka Server的建议配置。

注意eureka下的client配置,这个配置意思是eureka应用作为一个客户端,对注册中心的动作。

其中service-url的配置必须要填写,内容是注册中心的地址,如果有多个,逗号隔开。

defaultZone路径后面必须加上/eureka后缀,别问我为啥。

server:
  port: 10086 # 端口
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中显示
eureka:
  client:
    register-with-eureka: false # 是否注册自己的信息到EurekaServer,默认是true
    fetch-registry: false # 是否拉取服务列表,默认是true
    service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要加上其它Server的地址。
      defaultZone: http://127.0.0.1:${server.port}/eureka

访问http://localhost:10086即可看到注册中心的内容,eureka只有一个,服务列表为空:

7.4 将user-service注册到eureka

7.4.1 添加依赖

eureka客户端依赖

<!-- Eureka客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Spring Cloud的依赖,注意我这里的版本是Greenwich.SR1

    <!-- SpringCloud的依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!-- Spring的仓库地址 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

7.4.2 开启EurekaClient功能

添加@EnableDiscoveryClient注解

@SpringBootApplication
@EnableDiscoveryClient // 开启EurekaClient功能
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

7.4.3 配置eureka客户端属性

server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/XXXXX?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: XXXXX
    password: XXXXX
    hikari:
      maximum-pool-size: 20
      minimum-idle: 10
  application:
    name: user-service # 应用名称
mybatis:
  type-aliases-package: com.vplus.demo.userservice.pojo
eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

7.4.4 效果

7.5 user-consume从eureka中获取服务

7.5.1 添加依赖

同上7.4.1

7.5.2 开启EurekaClient功能

同上7.4.2

7.5.3 配置eureka客户端属性

server:
  port: 8082
spring:
  application:
    name: user-consume # 应用名称
eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

7.5.4 修改UserService

  • 之前是调用UserDao,UserDao使用RestTemplate请求远程接口得到数据。
  • 现在我们在service层,从eureka中拉取服务列表,得到接口地址后请求数据。
@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;// Eureka客户端,可以获取到服务实例信息

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        // String baseUrl = "http://localhost:8081/user/";
        // 根据服务名称,获取服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        // 因为只有一个UserService,因此我们直接get(0)获取
        ServiceInstance instance = instances.get(0);
        // 获取ip和端口信息
        String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
        ids.forEach(id -> {
            // 我们测试多次查询,
            users.add(this.restTemplate.getForObject(baseUrl + id, User.class));
            // 每次间隔500毫秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return users;
    }

}

7.6 eureka集群

7.6.1 搭建集群

Eureka可以集群搭建形成高可用的注册中心。多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。

我们要两个Eureka,端口号分别是10086、10087

可以使用Idea的启动器复制功能复制eureka的启动器。

将应用A的启动器复制出一个A2,A启动后,修改配置再启动A2,这样我们就可以得到两个配置不同的应用了。

先把原来的eureka配置信息改为

server:
  port: 10086 # 端口
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中显示
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10087/eureka

启动EurekaApplication,启动起来后再将配置改为

server:
  port: 10087 # 端口
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中显示
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

再启动EurekaApplication2,此时两个注册中心就形成了集群。

两个eureka相互注册,10086的defaultZone的url地址的端口号为10087,注意这一点。

再将两个客户端的Eureka相关配置改为

defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka

访问http://localhost:10086http://localhost:10087都可以看到效果:

7.7 Eureka相关配置

7.7.1 服务提供者

服务提供者主要做两个动作:服务注册服务续约

  • 服务注册的对应配置,true表示服务启动后会向注册中心发送注册请求,默认就是开着的。
eureka
    client
        register-with-erueka: true
  • 服务续约的对应配置,这些都是默认值
eureka:
  instance:
    #服务失效时间,默认值90秒
    lease-expiration-duration-in-seconds: 90
    #服务续约(renew)的间隔,默认为30秒
    lease-renewal-interval-in-seconds: 30

默认情况下每个30秒服务会向注册中心发送一次心跳,证明自己还活着。如果超过90秒没有发送心跳,EurekaServer就会认为该服务宕机,会从服务列表中移除,注意,这是服务提供者告诉注册中心我每30秒续约一次,90秒没有续约,就表示我失效了,是配置在服务提供者上的,不是配置在注册中心上的。

我实验的时候,关闭一个服务,eureka几乎是瞬间就知道服务down了

试了好几次都是这样,可能我的关闭动作出发了什么东西吧,时间有限,先不管这个问题,留个坑将来看。

后来我注意到服务关闭后会输出一句:Unregistering ...,推测服务正常关闭时会自己通知注册中心。

  • 实例ID名的修改

在页面上,服务提供者实例ID显示为:localhost:user-service:8081,

格式为:${hostname} + ${spring.application.name} + ${server.port},对应配置为

eureka:
  instance:
    instance-id: ${spring.application.name}:${server.port}

修改后启动,变成了

7.7.2 服务消费者

消费者需要拉取服务列表,拉取时间间隔默认为30秒1次,对应配置为,如果是开发环境可适当缩小方便开发

eureka:
  client:
    registry-fetch-interval-seconds: 30

7.7.3 失效剔除和自我保护

  • 失效剔除:每个一段时间剔除掉失效的服务,默认为60s,为了方便开发设置为1s。

    服务器怎么知道失效了?看看上面服务提供者的配置,注意这几个配置的联系。

  • 自我保护:生产环境中,由于网络延迟等原因,失效服务并不一定是真正失效了。如果被标记为失效的服务太多,超过了85%,此时eureka会把这些服务保护起来,先不剔除,保证大多数服务还可用。在开发中将自我保护模式关掉,方便开发。

eureka:
  server:
    enable-self-preservation: false # 关闭自我保护模式(默认为打开)
    eviction-interval-timer-in-ms: 1000 #   扫描失效服务的间隔时间为1s(默认为60s)

8. Robbin负载均衡

8.1 开启两个user-service

具体操作参照7.6.1,这里设置两个service的端口为8080和8081

8.2 开启负载均衡

注意,是在调用端即consume上开启负载均衡,Eureka中已经集成了Ribbon,无需引入新的依赖,只需要在调用端的RestTemplate的注册Bean方法上添加注解:@LoadBalanced即可。这个方法位于UserConsumerApplication里。

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

具体的调用方式也需要修改,将UserService中的queryUserByIds方法修改成这样。

public List<User> queryUserByIds(List<Long> ids) {
       List<User> users = new ArrayList<>();
        // 地址直接写服务名称即可
        String baseUrl = "http://user-service/user/";
        ids.forEach(id -> {
            // 我们测试多次查询,
            users.add(this.restTemplate.getForObject(baseUrl + id, User.class));
            // 每次间隔500毫秒
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        return users;
    }
}

8.3 默认负载均衡策略分析

org.springframework.cloud.client.loadbalancer包里面有一个LoadBalancerInterceptor,它就是实现负载均衡的拦截器。

跟踪源码,找到了RibbonLoadBalancerClient,用consume多次请求接口,断点调试

execute(String serviceId, LoadBalancerRequest<T> request, Object hint)方法:

就是轮询

8.4 修改负载均衡策略

一个配置即可修改,有多种配置规则,这里使用随机规则。

注意格式,是以服务名称开头的。

server:
  port: 8082
spring:
  application:
    name: user-consume # 应用名称
eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
    registry-fetch-interval-seconds: 5
  instance:
    prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
###################################负载均衡配置###############################################
user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

8.5 重试机制

如果有一台服务突然挂掉了,而eureka还来不及将其清除出服务列表,或者消费者拉取的服务列表还有缓存,一旦请求到这台挂掉的服务就会报错。虽然多次请求后结果也能出来,但体验非常不好。

Ribbon的重试机制就是解决这个问题的。

引入依赖

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

开启Spring Cloud的重试机制并配置

server:
  port: 8082
spring:
  application:
    name: user-consume # 应用名称
  cloud:
    loadbalancer:
      retry:
        enabled: true # 开启Spring Cloud的重试功能
eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
    registry-fetch-interval-seconds: 5
  instance:
    prefer-ip-address: true # 当其它服务获取地址时提供ip而不是hostname
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找

user-service:
  ribbon:
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数

就好了。

这篇文章参考的是黑马培训的《乐优商城》

Guess you like

Origin www.cnblogs.com/qianbixin/p/10936456.html