微服务介绍

嚴華  金牌会员 | 2022-8-11 19:08:23 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 626|帖子 626|积分 1878

前言

为什么要将1个整体的应用程序,拆分成1堆无法再继续拆分的微服务呢?
架构化整为零之后,就可以针对某1个功能模块进行针对性的性能扩展;
 
一、微服务介绍

从互联网早起到现在,系统架构大体经历了下面几个过程: 单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构
1.单体应用架构

互联网早期,一般的网站应用流量较小,只需一个应用,将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本。
比如说一个电商网站,里面会包含很多用户管理,商品管理,订单管理,物流管理等等很多模块,我们会把它们做成1个web项目,然后部署到1台Tomcat上。

1.1.优点

项目架构简单,小型项目的话, 开发成本低;项目部署在一个节点上, 维护方便
1.2.缺点

全部功能集成在1个工程中,对于大型项目来讲上限之后,无法针对不同模块进行针性的性优化和水平扩展;
 
2.垂直应用架构

随着访问量的逐渐增大,单一应用只能依靠增加节点来应对,但是这时候会发现并不是所有的模块都会有比较大的访问量。
还是以上面的电商为例子,用户访问量的增加可能影响的只是用户和订单模块,但是对消息模块的影响就比较小。
那么此时我们希望只多增加几个订单模块,而不增加消息模块,此时单体应用就做不到了,垂直应用就应运而生了。
所谓的垂直应用架构,就是将原来的一个应用拆成互不相干的几个应用,比如我们可以将上面电商的单体应用拆分成

  • 电商系统(用户管理 商品管理 订单管理)
  • 后台系统(用户管理 订单管理 客户管理)
  • CMS系统(广告管理 营销管理)
这样拆分完毕之后,一旦用户访问量变大,只需要增加电商系统的节点就可以了,而无需增加后台和CMS的节点。
 
 
 
2.1.优点

系统拆分实现了流量分担,解决了并发问题,而且可以针对不同模块进行优化和水平扩展;
2.2.缺点

系统之间相互独立,子模块之间无法相互调用,扩展新模块是需要重复开发依赖模块;
 
3.分布式架构

当垂直应用越来越多,重复的业务代码就会越来越多。这时候,我们就思考可不可以将重复的代码抽取出来,做成统一的业务层作为独立的服务,然后由前端控制层调用不同的业务层服务呢?
这就产生了新的分布式系统架构。它将把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。

 
 
3.1.优点

抽取公共的功能为服务层,提高代码复用性
3.2.缺点

系统间耦合度变高,调用关系错综复杂,难以维护
 
4.SOA架构

在分布式架构下,当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心对集群进行实时管理。
此时,用于资源调度和治理中心(SOA即Service Oriented Architecture,面向服务的架构)是关键。

4.1.优点

使用注册中心解决了服务间调用关系的自动调节;
4.2.缺点

服务间会有依赖关系,一旦某个环节出错会影响较大,服务关系复杂,运维、测试部署困难;
 
5.微服务架构

微服务架构在某种程度上是面向服务的架构SOA继续发展的下一步,它更加强调服务的"彻底拆分。
简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是1个可以独立运行的项目。
 

5.1.优点

服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展
5.2.缺点

分布式系统开发的技术成本高;
 
二、认识微服务

微服务架构,就是将应用拆分成无法再继续拆分的微服务,每个服务都是一个可以独立运行的项目。其主要特点如下:

  • 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立(不同的团队负责不同的模块开发维护)、技术独立(可使用不同的编程语言实现不同的子模块)、数据独立(每个子模块使用不同的数据库)、部署独立(每个子模块可部署到不同的服务器上)
  • 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题 
一旦采用微服务系统架构,就势必会遇到这样几个问题:

  • 这么多小服务,如何管理他们?服务治理(电话本)
  • 这么多小服务,他们之间如何通讯?(RPC/HTTP-->RestTemplate)
  • 这么多小服务,客户端怎么访问他们?(服务网关)
对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对以上几个问题,提供了相应的组件来解决它们。
 
三、实现微服务的方案

微服务这种方案需要具体的技术框架来落地,全球的互联网公司都在积极尝试自己的微服务落地技术。
目前最知名的就是SpringCloud和SpringCloudAlibaba


  • SpringCloud:Spring基于NetFlix微服务组件进行封装,提供微服务一站式解决方案
  • SpringCloudAlibaba:在SpringCloud NetFlix基础上封装了阿里巴巴的微服务解决方案 

 
四、微服务环境搭建

微服务的构建应遵循以下原则:

  • 单一职责:不同微服务,不要重复开发相同业务
  • 独立数据库:微服务数据独立,不要访问其它微服务的数据库
  • 暴露接口:微服务可以将自己的业务暴露为接口,供其它微服务调用

1.微服务构建示例

今日我来实现一个简单的微服务调用,以用户模块和订单模块这2个模块为例

1.1.创建微服务项目


springcloud-demo:父工程,管理依赖

  • order-service:订单微服务,负责订单相关业务
  • user-service: 用户微服务,负责用户相关业务
1.2.导入数据库

cloud_order数据库

  1. /*
  2. Navicat Premium Data Transfer
  3. Source Server         : local
  4. Source Server Type    : MySQL
  5. Source Server Version : 50622
  6. Source Host           : localhost:3306
  7. Source Schema         : heima
  8. Target Server Type    : MySQL
  9. Target Server Version : 50622
  10. File Encoding         : 65001
  11. Date: 01/04/2021 14:57:18
  12. */
  13. create database cloud_order;
  14. use cloud_order;
  15. SET NAMES utf8mb4;
  16. SET FOREIGN_KEY_CHECKS = 0;
  17. -- ----------------------------
  18. -- Table structure for tb_order
  19. -- ----------------------------
  20. DROP TABLE IF EXISTS `tb_order`;
  21. CREATE TABLE `tb_order`  (
  22.   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
  23.   `user_id` bigint(20) NOT NULL COMMENT '用户id',
  24.   `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品名称',
  25.   `price` bigint(20) NOT NULL COMMENT '商品价格',
  26.   `num` int(10) NULL DEFAULT 0 COMMENT '商品数量',
  27.   PRIMARY KEY (`id`) USING BTREE,
  28.   UNIQUE INDEX `username`(`name`) USING BTREE
  29. ) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
  30. -- ----------------------------
  31. -- Records of tb_order
  32. -- ----------------------------
  33. INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);
  34. INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);
  35. INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);
  36. INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);
  37. INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);
  38. INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);
  39. INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);
  40. INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);
  41. SET FOREIGN_KEY_CHECKS = 1;
复制代码
cloud_order.sqlcloud_user数据库

  1. /*
  2. Navicat Premium Data Transfer
  3. Source Server         : local
  4. Source Server Type    : MySQL
  5. Source Server Version : 50622
  6. Source Host           : localhost:3306
  7. Source Schema         : heima
  8. Target Server Type    : MySQL
  9. Target Server Version : 50622
  10. File Encoding         : 65001
  11. Date: 01/04/2021 14:57:18
  12. */
  13. create database cloud_user;
  14. use cloud_user;
  15. SET NAMES utf8mb4;
  16. SET FOREIGN_KEY_CHECKS = 0;
  17. -- ----------------------------
  18. -- Table structure for tb_user
  19. -- ----------------------------
  20. DROP TABLE IF EXISTS `tb_user`;
  21. CREATE TABLE `tb_user`  (
  22.   `id` bigint(20) NOT NULL AUTO_INCREMENT,
  23.   `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人',
  24.   `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
  25.   PRIMARY KEY (`id`) USING BTREE,
  26.   UNIQUE INDEX `username`(`username`) USING BTREE
  27. ) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
  28. -- ----------------------------
  29. -- Records of tb_user
  30. -- ----------------------------
  31. INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');
  32. INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');
  33. INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');
  34. INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');
  35. INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');
  36. INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');
  37. SET FOREIGN_KEY_CHECKS = 1;
复制代码
cloud_user.sql1.3.pom依赖

springcloud-demo
  1. <?xml version="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.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.itheima</groupId>
  7.     <artifactId>springcloud-demo</artifactId>
  8.     <packaging>pom</packaging>
  9.     <version>1.0-SNAPSHOT</version>
  10.     <modules>
  11.         <module>order-service</module>
  12.         <module>user-service</module>
  13.     </modules>
  14.    
  15.     <parent>
  16.         <groupId>org.springframework.boot</groupId>
  17.         <artifactId>spring-boot-starter-parent</artifactId>
  18.         <version>2.3.9.RELEASE</version>
  19.         <relativePath/>
  20.     </parent>
  21.    
  22.     <properties>
  23.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  24.         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  25.         <java.version>1.8</java.version>
  26.         <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
  27.         <mysql.version>5.1.47</mysql.version>
  28.         <mybatis-plus.version>3.4.0</mybatis-plus.version>
  29.         <spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
  30.     </properties>
  31.    
  32.     <dependencyManagement>
  33.         <dependencies>
  34.             
  35.             <dependency>
  36.                 <groupId>org.springframework.cloud</groupId>
  37.                 <artifactId>spring-cloud-dependencies</artifactId>
  38.                 <version>${spring-cloud.version}</version>
  39.                 <type>pom</type>
  40.                 <scope>import</scope>
  41.             </dependency>
  42.             
  43.             <dependency>
  44.                 <groupId>com.alibaba.cloud</groupId>
  45.                 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  46.                 <version>${spring-cloud-alibaba.version}</version>
  47.                 <type>pom</type>
  48.                 <scope>import</scope>
  49.             </dependency>
  50.             
  51.             <dependency>
  52.                 <groupId>mysql</groupId>
  53.                 <artifactId>mysql-connector-java</artifactId>
  54.                 <version>${mysql.version}</version>
  55.             </dependency>
  56.             
  57.             <dependency>
  58.                 <groupId>com.baomidou</groupId>
  59.                 <artifactId>mybatis-plus-boot-starter</artifactId>
  60.                 <version>${mybatis-plus.version}</version>
  61.             </dependency>
  62.         </dependencies>
  63.     </dependencyManagement>
  64.    
  65.     <dependencies>
  66.         <dependency>
  67.             <groupId>org.projectlombok</groupId>
  68.             <artifactId>lombok</artifactId>
  69.         </dependency>
  70.     </dependencies>
  71. </project>
复制代码
pom.xmlorder-service
  1. <?xml version="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>springcloud-demo</artifactId>
  7.         <groupId>com.itheima</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>order-service</artifactId>
  12.     <dependencies>
  13.         <dependency>
  14.             <groupId>org.springframework.boot</groupId>
  15.             <artifactId>spring-boot-starter-web</artifactId>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>mysql</groupId>
  19.             <artifactId>mysql-connector-java</artifactId>
  20.         </dependency>
  21.         <dependency>
  22.             <groupId>com.baomidou</groupId>
  23.             <artifactId>mybatis-plus-boot-starter</artifactId>
  24.         </dependency>
  25.     </dependencies>
  26.     <build>
  27.         <plugins>
  28.             <plugin>
  29.                 <groupId>org.springframework.boot</groupId>
  30.                 <artifactId>spring-boot-maven-plugin</artifactId>
  31.             </plugin>
  32.         </plugins>
  33.     </build>
  34. </project>
复制代码
pom.xmluser-service
  1. <?xml version="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>springcloud-demo</artifactId>
  7.         <groupId>com.itheima</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>user-service</artifactId>
  12.     <dependencies>
  13.         <dependency>
  14.             <groupId>org.springframework.boot</groupId>
  15.             <artifactId>spring-boot-starter-web</artifactId>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>mysql</groupId>
  19.             <artifactId>mysql-connector-java</artifactId>
  20.         </dependency>
  21.         <dependency>
  22.             <groupId>com.baomidou</groupId>
  23.             <artifactId>mybatis-plus-boot-starter</artifactId>
  24.         </dependency>
  25.     </dependencies>
  26.     <build>
  27.         <plugins>
  28.             <plugin>
  29.                 <groupId>org.springframework.boot</groupId>
  30.                 <artifactId>spring-boot-maven-plugin</artifactId>
  31.             </plugin>
  32.         </plugins>
  33.     </build>
  34. </project>
复制代码
pom.xml 1.4.实现远程调用

根据订单id查询订单的同时,把订单所属的用户信息一起返回
 
 
在服务调用关系中,会有2个不同的角色;


  • 服务提供者:被其它微服务调用的服务
  • 服务消费者:调用其它微服务的服务
注意:在微服务中服务提供者与服务消费者的角色并不是绝对的,而是相对于业务而言。
1.5.技术分析

order-service服务向user-service服务发起1个HTTP的请求,调用user-service服务的http://localhost:8081/user/{userId}接口;

  • HttpClient
    Apache的一个网络框架,网络请求做了完善的封装,api众多,但是代码复杂 。
  • OkHttp
    高效的HTTP客户端,它能允许同一ip和端口的请求重用一个socket,这样能够降低网络连接的时间
  • RestTemplate
    Spring提供的用于访问Rest服务的客户端,提供多种便捷访问远程Http服务的方法,大大提高客户端的编写效率

1.6.代码实现

1.6.1.注入RestTemplate对象

SpringBoot启动类就是1个配置类,因此可以在启动类中向IOC容器注入RestTemplate 对象
  1. package com.itheima.order;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.web.client.RestTemplate;
  7. @MapperScan("com.itheima.order.mapper")
  8. @SpringBootApplication
  9. public class OrderApplication {
  10.     public static void main(String[] args) {
  11.         SpringApplication.run(OrderApplication.class, args);
  12.     }
  13.     //SpringBoot启动是,在Spring容器中放入1个restTemplate对象
  14.     @Bean
  15.     public RestTemplate restTemplate() {
  16.         return new RestTemplate();
  17.     }
  18. }
复制代码
OrderApplication.java1.6.2.OrderService调用用户微服务

在OrderService中调用用户微服务的方法http://localhost:8081/user/{userId},根据id获取user对象
  1. @Service
  2. public class OrderService {
  3.     @Autowired
  4.     private OrderMapper orderMapper;
  5.     @Autowired
  6.     private RestTemplate restTemplate;
  7.     public Order findById(Long orderId) {
  8.         // 1.查询订单
  9.         Order order = orderMapper.selectById(orderId);
  10.         //2.调用user-service服务查询当前订单的用户信息
  11.         String url = "http://127.0.0.1:8081/user/" + order.getUserId();
  12.         User user = restTemplate.getForObject(url, User.class);
  13.         //3.user封装到order对象
  14.         order.setUser(user);
  15.         // 4.返回
  16.         return order;
  17.     }
  18. }
复制代码
五、Eureka注册中心实现服务治理

当前已经可以通过RestTemplate实现微服务之间的调用,但是服务提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:

  • 一旦服务提供者地址变化,就需要手工修改代码
  • 一旦是多个服务提供者,无法实现负载均衡功能
  • 一旦服务变得越来越多,人工维护调用关系困难
那么应该怎么解决呢? 这时候就需要通过注册中心动态的实现服务治理。
1.服务治理

服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化服务注册与服务发现。

  • 服务注册在服务治理框架中,都会构建1个注册中心(电话本),每个微服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成1张服务的清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。
  • 服务发现服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。
 
 
 
2.Eureka简介

Eureka是SpringCloud技术栈中提供的用作微服务注册中心的组件,它可以实现微服务的自动注册、发现、状态监控。

  • Eureka-Server:就是服务注册中心(可以是一个集群),对外暴露自己的地址。
  • 提供者:服务提供方,它启动后向Eureka注册自己信息(地址,服务名称等),并且定期进行服务续约(提供者定期通过http方式向Eureka刷新自己的状态)
  • 消费者:服务调用方,它会定期去Eureka拉取服务列表,然后使用负载均衡算法选出一个服务进行调用。
 

3.搭建Eureka服务端

通过源码的方式搭建1个Eureak注册中心,实现微服务的治理;
注册中心一般都是集群架构,这里我使用单机;
3.1.pom依赖
  1.   <dependencies>
  2.         
  3.         <dependency>
  4.             <groupId>org.springframework.cloud</groupId>
  5.             <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  6.         </dependency>
  7.     </dependencies>
复制代码
 
3.2.application.yml
  1. server:
  2.   port: 8761
  3. spring:
  4.   application:
  5.     name: eureka-server
  6. eureka:
  7.   client:
  8.     # 注册中心的职责是维护服务实例,不需要去检索服务
  9.     fetch-registry: false
  10.     # 默认设置下,注册中心会将自己作为客户端来尝试注册自己,设置为false代表不向注册中心注册自己
  11.     register-with-eureka: false
复制代码
3.3.EurekaApplication
  1. package com.zhanggen;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
  5. @SpringBootApplication
  6. @EnableEurekaServer// 开启注册中心功能
  7. public class EurekaApplication {
  8.     public static void main(String[] args) {
  9.         SpringApplication.run(EurekaApplication.class,args);
  10.     }
  11. }
复制代码
 
4.注册微服务到注册中心

想要把1个微服务注册到Eureka注册中心需要设置微服务为Eureka的客户端;

4.1.订单微服务注册到注册中心

4.1.1.在pom.xml中添加Eureka客户端的依赖
  1. eureka:
  2.   client:
  3.     service-url:
  4.       defaultZone: http://localhost:8761/eureka
复制代码
4.1.2.在主类上添加@EnableDiscoveryClient注解


4.1.3.在application.yaml中添加eureka服务的地址
  1. # eureka服务器地址eureka:
  2.   client:
  3.     service-url:
  4.       defaultZone: http://localhost:8761/eureka
复制代码
 
4.1.3.调整RestTemplate添加@LoadBalanced注解
  1. package com.zhanggen.order;
  2. import org.mybatis.spring.annotation.MapperScan;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  6. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.web.client.RestTemplate;
  9. @MapperScan("com.zhanggen.order.mapper")
  10. @SpringBootApplication
  11. @EnableDiscoveryClient
  12. public class OrderApplication {
  13.     public static void main(String[] args) {
  14.         SpringApplication.run(OrderApplication.class, args);
  15.     }
  16.     //SpringBoot启动是,在Spring容器中放入1个restTemplate对象
  17.     @Bean
  18.     @LoadBalanced
  19.     public RestTemplate restTemplate() {
  20.         return new RestTemplate();
  21.     }
  22. }
复制代码
4.1.4.修改OrderService实现微服务调用
  1. @Autowired
  2.     private RestTemplate restTemplate;
  3.     public Order findById(Long orderId) {
  4.         // 1.查询订单
  5.         Order order = orderMapper.selectById(orderId);
  6.         //2.调用user-service服务查询当前订单的用户信息
  7.     //String url = "http://127.0.0.1:8081/user/" + order.getUserId();
  8.         String url = "http://user-service/user/" + order.getUserId();
  9.         User user = restTemplate.getForObject(url, User.class);
  10.         //3.user封装到order对象
  11.         order.setUser(user);
  12.         // 4.返回
  13.         return order;
  14.     }
复制代码
4.2.用户微服务注册到注册中心

操作同上
 
5.客户端负载均衡

我们前面添加了@LoadBalanced注解,它除了支持简单的服务调用之外,更加强大的功能是支持客户端负载均衡。
负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元上进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡:指的是发生在服务提供者一方,比如常见的nginx负载均衡。
客户端负载均衡:指的是发生在消费的一方,也就是在发送请求之前已经选好了由哪个实例处理请求。
 
 
我们在微服务架构中,调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。5.
5.1.客户端负载均衡测试

我将使用2个提供者(user-service),测试服务消费者(order-service)配置的客户端负载均衡是否配置生效?

 5.1.1.启动微服务


 
6.客户端负载均衡策略

负载均衡的规则都定义在IRule接口中,它有很多不同的实现类,分别代表不同规则
内置负载均衡规则类规则描述RoundRobinRule简单轮询, 服务列表来选择服务器。第一次到8081,第二次就到8082,第三次又到8081,第四次又到8082…AvailabilityFilteringRule可用过滤规则,其实它功能是先过滤掉不可用的Server实例,再选择并发连接最小的实例。WeightedResponseTimeRule为每一个服务器计算一个==权重==范围区间,权重区间的宽度越大,而权重区间宽度越大被选中的概率就越大。ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做==轮询==。BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。RandomRule==随机==选择一个可用的服务器。RetryRule轮询重试(重试采用的默认也是轮询) 
7.配置客户端负载均衡策略

SpringCloud允许通过定义IRule修改负载均衡规则,有两种方式:
注意配置客户端负载均衡的策略,需要在消费方配置;
配置实现的目的是服务消费方调用---->服务提供方时应采用什么负载均衡策略?
7.1.配置全局
  1. package com.zhanggen.order;
  2. import com.netflix.loadbalancer.IRule;
  3. import com.netflix.loadbalancer.RandomRule;
  4. import org.mybatis.spring.annotation.MapperScan;
  5. import org.springframework.boot.SpringApplication;
  6. import org.springframework.boot.autoconfigure.SpringBootApplication;
  7. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  8. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.web.client.RestTemplate;
  11. @MapperScan("com.zhanggen.order.mapper")
  12. @SpringBootApplication
  13. @EnableDiscoveryClient
  14. public class OrderApplication {
  15.     public static void main(String[] args) {
  16.         SpringApplication.run(OrderApplication.class, args);
  17.     }
  18.     //SpringBoot启动是,在Spring容器中放入1个restTemplate对象
  19.     @Bean
  20.     @LoadBalanced
  21.     public RestTemplate restTemplate() {
  22.         return new RestTemplate();
  23.     }
  24.     //全局方式:向Spring容器中直接放入想要使用的策略对象
  25.     @Bean
  26.     public IRule randomRule(){
  27.         return new RandomRule();
  28.     }
  29. }
复制代码
7.1.配置局部
  1. eureka:
  2.   client:
  3.     service-url:
  4.       defaultZone: http://localhost:8761/eureka#当前微服务调用user-service微服务时,使用 com.netflix.loadbalancer.RandomRule负载均衡规则user-service:  ribbon:    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
复制代码
 
8.客户端负载均衡实现原理

我们在调用服务提供方的时候,发出的HTTP请求URL明明是http://user-service/user/1是怎么变成了http://localhost:8081/user/1的呢?
显然有人帮我们根据service名称,获取到了服务实例的ip和端口,它就是Ribbon组件的LoadBalancerInterceptor。
这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

9.饥渴加载

Ribbon默认是采用懒加载,即第1次访问时才会去创建LoadBalanceClient,所有导致第1次请求时间会很长。
而饥饿加载则会在项目启动时即要创建,延长了项目启动的时间,降低第1次访问的耗时,通过下面配置开启饥饿加载:
  1. ribbon:  
  2.     eager-load:   
  3.         enabled: true # 开启饥饿加载   
  4.         clients:      
  5.         - user-service  # 指定饥饿加载的服务名称
复制代码
 
六、Nacos注册中心实现服务治理

Nacos是阿里巴巴的产品,和Eureka功能一样,也可以作为服务注册中心使用,相比Eureka功能更加丰富,在国内受欢迎程度较高。
1.使用Nacos

下面我使用Nacos搭建1个注册中心,让order-service和user-service两个自动发现微服务客户端,来注册中心完成自动注册;

1.1.搭建Nacos服务端

在企业开发过程中,我们比较习惯使用Nacos提供的压缩包直接运行Nacos服务,而不是向Eureka那样使用源代码启动

  • 将资料中的nacos-server-1.4.2.zip解压即安装
  • 进入安装路径的bin目录,通过cmd命令行输入startup.cmd -m standalone即可启动
  • 访问http://127.0.0.1:8848/nacos/#/login管理页面,完成登录:用户名和密码:nacos
 
1.2.微服务配置

在微服务自动发现的客户端配置SpringBoot项目的支持Nacos客户端依赖,配置文件配置Nacos服务的地址;
1.2.1.pom文件
  1.   
  2.         <dependency>
  3.             <groupId>com.alibaba.cloud</groupId>
  4.             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  5.         </dependency>
复制代码
1.2.2.application.yml
  1.   #Nacos注册中心的地址
  2.   cloud:
  3.     nacos:
  4.       discovery:
  5.         server-addr: localhost:8848
复制代码
 

2.服务分级存储

 1个服务(类)可以有多个实例(对象),例如我们的user-service服务,可以有以下3个实例

  • 127.0.0.1:8081
  • 127.0.0.1:8082
  • 127.0.0.1:8083
假如这3个实例部署在全国各地的不同机房,例如:

  • 127.0.0.1:8081,在北京机房
  • 127.0.0.1:8082,在北京机房
  • 127.0.0.1:8083,在上海机房
我们可以把1个服务产生的多个实例,划分到多个不同的集群(逻辑管理单位)中;
这样设计的目的是为了使服务消费者调用服务提供者时,优先选择本地集群中的服务提供者;
避免服务消费者跨集群(区域)调用非本地集群的服务提供者,造成网络较高的网络延时;

2.1.配置服务消费者

服务消费者在Beijing集群中
  1. Nacos注册中心的地址
  2.   cloud:
  3.     nacos:
  4.       discovery:
  5.         server-addr: localhost:8848
  6.         cluster-name: Beijing
  7. user-service:
  8.   ribbon:
  9.     NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
复制代码
2.2.配置服务提供者

2个服务提供者也在Beijing集群中
  1.   cloud:
  2.     nacos:
  3.       discovery:
  4.         server-addr: localhost:8848
  5.         cluster-name: Beijing # 服务所在集群名称
复制代码
1个服务提供者也在Shanghai集群中
  1. -Dserver.port=8083 -Dspring.cloud.nacos.discovery.cluster-name=SH
复制代码
 
2.3.测试

此时服务消费者在Beijing集群中,那么该服务在调用服务提供者时,会优先选择Beijing集群中的那2个服务提供者;

 
 
3.实例权重配置


Nacos支持权重配置来控制不同实例的访问频率,权重越大则访问频率越高。0

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

嚴華

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表