• SpringCloud之微服务实用篇1


    今天我们主要学习的内容包含5个部分,分别为认识微服务,分布式服务架构案例,euraka注册中心,Ribbon负载均衡原理,nacos注册中心。

    目录

    一、微服务

    1.1、认识微服务

    1.2、服务的拆分及远程调用

    1.3、 euraka注册中心

    1.4、Ribbon负载均衡原理 

    1.5、 nacos注册中心

    1.6、Eureka和Nacos对比


    一、微服务

    1.1、认识微服务

    首先我们看一下微服务的架构,首先看一下单体架构,一般适用于小型的项目,将所有业务的功能在一个项目中开发,然后进行打包放到服务器中,客户端就可以进行访问了,这种部署简单,但是代码耦合度较高,不适合大型项目的发布和维护。

    对于大型的项目一般采用分布式架构,分布式架构就是根据功能拆分成不同的项目,每个功能对应一个项目,即对应一个服务,分布式架构有利于降低模块之间的耦合性,当然分布式结果也会带来一些问题。

    我们可以看到微服务也面临下面几个问题,比如:怎么去拆分,拆分模块的力度怎么把握?对与服务需要集群,集群的地址怎么维护呢?由于服务都是在不同的项目下,如果需要调用别的服务的接口怎么调用呢?为了防止调用坏掉的服务,防止级联失败,怎么去感知服务是否健康呢?

    目前常用的是分布式微服务架构,微服务架构特征如下:

    包括:单一职责,面向服务,独立,隔离性强;本质上 就是为了实现高内聚和低耦合,降低服务之间的影响范围。

    下面我们看一下常用的微服务技术的对比:

    我们先了解一下SpringCloud微服务体系,具体如下:
    SpringCloud是集成了各种微服务的组件,基于SpringBoot实现了这些组件的自动装配,使得实现了开箱即用的效果。

     下面看一下SpringCloud和SpringBoot的版本兼容介绍,我们学习用的版本是boot版本的。

    1.2、服务的拆分及远程调用

    1)服务的拆分

    在进行服务拆分之前,我们需要注意以下几个问题,首先,需要注意要保证不同的微服务开发不同的业务,防止业务的重复开发;微服务的数据应该独立,应该做到仅访问自己的数据库,不访问其它微服务的数据库;微服务应该可以将自己的业务暴露为接口,供其它微服务调用。

    我们使用了一个已有的demo演示服务的拆分和远程调用,首先我们把订单查询和id查询拆分成两个不同的业务,两个数据表去模拟两个不同的数据库。

    启动两个微服务,如下有两个运行的微服务,分别是根据id查用户和根据id查订单。

    我们现在 浏览器测试一下两个微服务是否能正常工作,如下:

     

    2) 服务的远程调用

    根据正常的需求要求根据id查询订单同时返回订单消息和用户消息,因为属于不同的服务,那么就需要涉及服务的远程调用了。

     

    一般可以使用注册RestTemplate实现服务的远程调用,首先在启动类创建RestTemplate对象,并注入Spring容器。

    1. import org.mybatis.spring.annotation.MapperScan;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.web.client.RestTemplate;
    6. @MapperScan("cn.itcast.order.mapper")
    7. @SpringBootApplication
    8. public class OrderApplication {
    9. public static void main(String[] args) {
    10. SpringApplication.run(OrderApplication.class, args);
    11. }
    12. @Bean //创建RestTemplate对象,并注入Spring容器
    13. public RestTemplate restTemplate(){
    14. return new RestTemplate() ;
    15. }
    16. }

    然后就可以在表现层注入RestTemplate对象,并使用该对象发送http请求,实现服务器的远程调用,具体如下:

    1. import cn.itcast.feign.pojo.User;
    2. import cn.itcast.order.pojo.Order;
    3. import cn.itcast.order.service.OrderService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.PathVariable;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import org.springframework.web.client.RestTemplate;
    10. @RestController
    11. @RequestMapping("order")
    12. public class OrderController {
    13. @Autowired
    14. private OrderService orderService;
    15. @Autowired
    16. private RestTemplate restTemplate ;
    17. @GetMapping("{orderId}")
    18. public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
    19. // 根据id查询订单并返回
    20. Order order = orderService.queryOrderById(orderId) ;
    21. // 利用restTemplate发送http请求,查询用户
    22. String url = "http://localhost:8081/user/" + order.getUserId();
    23. //发送http请求实现远程调用
    24. User user = restTemplate.getForObject(url, User.class);
    25. // 封装uer对象到order中
    26. order.setUser(user) ;
    27. return order;
    28. }
    29. }

    测试结果如下:可以看到在查询用户订单信息,同时把用户信息也查询出来了。

    1.3、 euraka注册中心

    我们在之前的案例中可以发现order-service是调用user-service,所有前者是服务的消费者,后者是服务的提供者。对于服务可以存在调用和调用的情况,即服务既是消费者又是提供者。

    我们看一下Eureka的基本原理,服务提供者会向注册中心注册自己的信息,消费者需要信息时候,直接根据服务名称从注册中心拉去即可。如果服务提供者提供多个服务,一般会根据负载均衡原理从服务列表中挑一个。服务提供者每30s会向注册中心提供一次心跳,这样就可以感知服务的健康状态了,有效地避免了消费者拉去到不健康的服务。

    接下来我们进行实践练习一下,该实践一共分为3步,具体如下,首先搭建注册中心,然后将服务都注册到注册中心,最后在order-service中完成服务拉取,通过负载均衡挑选一个服务实现远程调用。

    1)搭建注册中心

    主要分为三个步骤:1、引入依赖;2、加入启动注解;3、配置eureka地址。

    引入依赖:

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>cloud-demoartifactId>
    7. <groupId>cn.itcast.demogroupId>
    8. <version>1.0version>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>eureka-serverartifactId>
    12. <properties>
    13. <maven.compiler.source>8maven.compiler.source>
    14. <maven.compiler.target>8maven.compiler.target>
    15. properties>
    16. <dependencies>
    17. <dependency>
    18. <groupId>org.springframework.cloudgroupId>
    19. <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    20. dependency>
    21. dependencies>
    22. project>

    在启动类加入启动注解:

    1. import org.springframework.boot.SpringApplication;
    2. import org.springframework.boot.autoconfigure.SpringBootApplication;
    3. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    4. @EnableEurekaServer
    5. @SpringBootApplication
    6. public class EurekaApplication {
    7. public static void main(String[] args) {
    8. SpringApplication.run(EurekaApplication.class, args);
    9. }
    10. }

    配置eureka地址:

    1. server:
    2. port: 10086 # 服务端口
    3. spring:
    4. application:
    5. name: eurekaserver # eureka的服务名称
    6. eureka:
    7. client:
    8. service-url: # eureka的地址信息
    9. defaultZone: http://127.0.0.1:10086/eureka

    在浏览器测试效果如下,即说明搭建注册中心成功。

    2)服务注册

    服务注册一共两步:导入依赖、配置eureka地址。

    将user-service和order-service分别进行注册,具体如下:

    在pom.xml配置依赖如下:

    1. <dependency>
    2. <groupId>org.springframework.cloudgroupId>
    3. <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    4. dependency>

    在.yml文件种配置地址,当然也可以把服务的名称加上。

    1. eureka:
    2. client:
    3. service-url: # eureka的地址信息
    4. defaultZone: http://127.0.0.1:10086/eureka

    在浏览器测试注册效果如下,可以发现服务均注册到eureka注册中心。

     

    另外,可以再次启动user-service服务,模拟多个实例部署,方法如下:

     部署完实例后,启动,可以在浏览器的注册中心看到新注册的实例,一个服务有两个实例,如下:

     3)在order-service中完成服务拉取,通过负载均衡挑选一个服务实现远程调用

    只需要将表现层的硬编码获取url方式,改成通过服务名称从注册中心拉取即可,然后需要加上负载 均衡注解。

    1. import cn.itcast.feign.pojo.User;
    2. import cn.itcast.order.pojo.Order;
    3. import cn.itcast.order.service.OrderService;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.PathVariable;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import org.springframework.web.client.RestTemplate;
    10. @RestController
    11. @RequestMapping("order")
    12. public class OrderController {
    13. @Autowired
    14. private OrderService orderService;
    15. @Autowired
    16. private RestTemplate restTemplate ;
    17. @GetMapping("{orderId}")
    18. public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
    19. // 根据id查询订单并返回
    20. Order order = orderService.queryOrderById(orderId) ;
    21. // 利用restTemplate发送http请求,查询用户
    22. String url = "http://userservice/user/" + order.getUserId();
    23. //发送http请求实现远程调用
    24. User user = restTemplate.getForObject(url, User.class);
    25. // 封装uer对象到order中
    26. order.setUser(user) ;
    27. return order;
    28. }
    29. }

    在启动类的远程调用服务对象RestTemplate中加入负载均衡注解即可。

    1. import org.mybatis.spring.annotation.MapperScan;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    5. import org.springframework.context.annotation.Bean;
    6. import org.springframework.web.client.RestTemplate;
    7. @MapperScan("cn.itcast.order.mapper")
    8. @SpringBootApplication
    9. public class OrderApplication {
    10. public static void main(String[] args) {
    11. SpringApplication.run(OrderApplication.class, args);
    12. }
    13. @LoadBalanced
    14. @Bean //创建RestTemplate对象,并注入Spring容器
    15. public RestTemplate restTemplate(){
    16. return new RestTemplate() ;
    17. }
    18. }

    总结:本节主要学习搭建注册中心,注册服务,发现服务(按照负载均衡从注册中心拉去服务)

    1.4、Ribbon负载均衡原理 

    1)负载均衡流程

    我们先看一下负载均衡的流程,具体如下 ,首先是消费服务发送请求到Ribbon,Ribbon向注册中心拉去服务,然后通过负载均衡原理选取一个实例完成服务。

    那么Ribbon中做负载均衡的具体流程是什么样?我们看一下,首先Ribbon客户端会使用拦截器拦截请求,交给Dynamic**对象去获取url中的id并从eureka注册中心中拉去服务列表,根据IRule中的负载均衡规则选择某个服务交给Ribbon客户端,由Ribbon客户端选择一个服务完成请求。

     2)负载均衡策略

    负载均衡的规则有很多,常见的规则如下所示,有轮循,随机等规则。

    既然知道了有上述的规则,那么如何自定义选择实现具体的负载均衡策略呢,如下:

    有两种方式,第一种,使用代码的方式,自定义负载均衡的规则,这种是全局方案。

     第二种是针对某一个具体的微服务而言的,直接在配置文件中修改该服务的负载聚恒规则。

    3)Ribbon饥饿加载

    对于Ribbon的懒加载,第一次加载项目会耗时较大,一般可以配置成饥饿加载的方式。

    总结:本节学习了Ribbon负载均衡的原理,主要包含三个方面,第一,负载均衡的规则,第二,负载均衡的定义方式,第三,设置饥饿加载。

    1.5、 nacos注册中心

    1)认识和安装Nacos

    首先Nacos注册中心是阿里的产品,是springcloud的一个组件,使用度还是比较高的,值得学习。

    去官网下载即可,下载后解压,在bin目录下,使用命令行启动Nacos,如下:

    然后可以通过给出的浏览器地址进行访问,初始的用户名和密码都是nacos,如下:

    2)Nacos快速入门

    对于Nacos注册中心的使用,首先需要配置主配置文件管理依赖。

    1. <dependency>
    2. <groupId>com.alibaba.cloudgroupId>
    3. <artifactId>spring-cloud-alibaba-dependenciesartifactId>
    4. <version>2.2.5.RELEASEversion>
    5. <type>pomtype>
    6. <scope>importscope>
    7. dependency>

    然后修改原来的user-service中的eureka注册中心依赖换成Nacos注册中心依赖,如下:

    1. <dependency>
    2. <groupId>com.alibaba.cloudgroupId>
    3. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    4. dependency>

    然后需要在.yml文件中配置nacos的服务器地址,具体如下:

    1. server:
    2. port: 8081
    3. spring:
    4. datasource:
    5. url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
    6. username: root
    7. password: 123456
    8. driver-class-name: com.mysql.jdbc.Driver
    9. application:
    10. name: userserver # user的服务名称
    11. cloud:
    12. nacos:
    13. discovery:
    14. server-addr: localhost:8848 #配置nacos服务器地址
    15. mybatis:
    16. type-aliases-package: cn.itcast.user.pojo
    17. configuration:
    18. map-underscore-to-camel-case: true
    19. logging:
    20. level:
    21. cn.itcast: debug
    22. pattern:
    23. dateformat: MM-dd HH:mm:ss:SSS
    24. #eureka:
    25. # client:
    26. # service-url: # eureka的地址信息
    27. # defaultZone: http://127.0.0.1:10086/eureka

    将order-service注入到nacos中的方法和这个一样,不再赘述。

    最后,启动两个服务,在注册中心nacos服务器的业面可以观察到注册的服务,user服务有2个实例,order服务有一个实例。 

    3)Nacos服务器分级存储模型

    Nacos服务分级存储模型主要包含三级,服务包含多个集群,每个集群中包含若干个实例。

    如果像设置服务的集群属性,我们呢首先创建三个user服务,然后需要在.yml文件中进行配置,如下属性,并启动服务,则该服务即属于该集群。

    然后就可以在nacos的服务端看到三个实例分布在三个集群中,如下:

    我们总结一下NacosRule负载均衡的策略,就是优先选择同一集群的实例,没有找到,才去采用负载均衡挑选实例。

    另外,对于负载均衡问题,实际部署的场景中,有些服务器的性能好,一些差,根据服务器性能分配负载任务,即服务器性能好的分配的权重大一些。 

    直接在nacos服务端的控制台修改权重就可以了,权重越大,服务被访问的概率越大。

     

    4)Nacos环境隔离

    Nacos的服务和数据存储最外层都有一个名叫namespace的用来做外层隔离的东西。

    在Nacos服务端建立一个命名空间,如下所示:

    需要在.yml文件中配置命名空间,主要是根据上面命名空间生成的id进行配置。

    然后重启order-service服务,可以在Nacos中发现该服务已经放到新的命名空间dev中,而不是在命名空间public中。

    最后,需要注意的是namespace用来做环境隔离,每个namespace都有唯一的id,不同的namespace下服务不可见。

    1.6、Eureka和Nacos对比

    注册中心Eureka和Nacos都支持服务注册和周期性拉取,都支持用心跳方式做健康检测。

    它们俩的区别在于Nacos支持注册检测提供者的健康状态,对于临时实例和非临时实例采用不同检测模式。两个注册中心各有优势。

  • 相关阅读:
    Spark安装
    Termux安装node
    商品管理修改实现
    LLM实战:当网页爬虫集成gpt3.5
    【JAVA案例】判断电话号码运营商
    【Python】AppUI自动化—appium自动化元素定位、元素事件操作(17)下
    【word格式】mathtype公式插入 | 段落嵌入后格式对齐 | 字体大小调整 |空心字体
    使用GitHub来Merge代码
    语音识别接口试用
    find命令查找文件
  • 原文地址:https://blog.csdn.net/nuist_NJUPT/article/details/127934486