微服务day01-认识微服务与Eureka注册中心

一.什么是微服务?

微服务≠springcloud,是一种经过良好架构设计的分布式解决方案,微服务架构特征

  • 单一职责:微服务拆分力度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立,技术独立,数据独立,部署独立,每个服务有自己独立的数据库
  • 隔离性强:服务调用做好隔离,容错,降级,避免出现级联问题

单体架构

将业务的所有的功能集成到一个项目中开发,打成一个包部署

优点:

  • 架构简单
  • 部署成本低
  • 适合面向企业内部的小项目

缺点:

  • 耦合度高

分布式架构

根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。

优点:

  • 降低了耦合度
  • 有利于服务的拓展升级

二.springcluod

springcluod是目前全球使用最广泛的微服务框架,集成了各种微服务功能组件,并基于springboot实现了这些组件的自动装配
springcloud与springboot的兼容版本

2.1服务的拆分及远程架构

服务拆分

  • 不同的微服务,不开发重复的功能
  • 微服务数据库独立,不要访问其他微服务的数据库
  • 微服务可以将自己的业务暴露为接口,供其他微服务调用

创建数据库以及执行sql语句的小插曲

  创建数据库时,编码使用utf8mb4(我的mysql版本是8.0.33),而给定的资料中是用5版本的mysql导出的sql脚本,因此直接运行可能有些问题。主要是字符集和排序规则的问题,MySQL 8.0 会自动将会话字符集设置为 utf8mb4,因此不需要再手动设置 SET NAMES utf8mb4;mysql5.0常用的字符集是utf8,因此导出的内容可能也涉及utf8字符集的设置,修改为适合MySQL 8.0的utf8mb4即可;另外,不需要再在表级别上设置utf8mb4字符集以及排序规则,我整理了适合5版本以及8版本两个版本的sql脚本

2.1.1 服务拆分的准备工作

cloud-order数据库 MySQL 5.0版本

sql 复制代码
-- cloud-order数据库 MySQL 5.0版本
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_order
-- ----------------------------
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品名称',
  `price` bigint(20) NOT NULL COMMENT '商品价格',
  `num` int(10) NULL DEFAULT 0 COMMENT '商品数量',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of tb_order
-- ----------------------------
INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);
INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);
INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);
INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);
INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);
INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);
INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);
INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);

SET FOREIGN_KEY_CHECKS = 1;

cloud-order数据库 MySQL 8.0版本

sql 复制代码
-- cloud-order数据库 MySQL 8.0版本
-- SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_order
-- ----------------------------
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品名称',
  `price` bigint(20) NOT NULL COMMENT '商品价格',
  `num` int(10) NULL DEFAULT 0 COMMENT '商品数量',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 ROW_FORMAT = Compact;

-- ----------------------------
-- Records of tb_order
-- ----------------------------
INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);
INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);
INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);
INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);
INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);
INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);
INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);
INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);

SET FOREIGN_KEY_CHECKS = 1;

运行结果

cloud-user数据库 MySQL 5.0版本

sql 复制代码
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人',
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');
INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');
INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');
INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');
INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');
INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');

SET FOREIGN_KEY_CHECKS = 1;

cloud-user数据库 MySQL 8.0版本

sql 复制代码
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人',
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 109 ROW_FORMAT = Compact;

-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');
INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');
INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');
INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');
INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');
INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');

SET FOREIGN_KEY_CHECKS = 1;

运行结果

微服务拆分Demo

1.准备工作

 1.创建2个不同的数据库cloud-order与cloud-user

 2.导入相应的sql文件

 3.导入demo

 4.运行两个服务端程序OrderApplication与UserApplication

2.准备工作运行结果


2.1.2 服务拆分

1.远程调用方式分析与案例

用户模块对外暴露接口@GetMapping("/user/{id}"),只要能够发送HTTP请求即可请求目标地址并获得返回结果

使用RestTemplate对象,可以被直接注入,基础案例

java 复制代码
	@Service
	public class OrderService {
	
	    @Autowired
	    private OrderMapper orderMapper;
	
	    @Autowired
	    private RestTemplate restTemplate;
	
	    public Order queryOrderById(Long orderId) {
	        // 1.查询订单
	        Order order = orderMapper.findById(orderId);
	        // 2.利用RestTemplate发送请求
	        String url="http://localhost:8081/user/"+order.getUserId();
	        User user=restTemplate.getForObject(url,User.class);
	        order.setUser(user);
	        // 4.返回
	        return order;
	    }
	}

运行结果

2.提供者与消费者

提供者:暴露接口给别人调用

消费者:调用别人的接口

服务A调用服务B,服务B调用服务C,此时服务B既可以是提供者也是消费者。

3.Eureka注册中心原理

使用硬编码服务地址,后期有多个提供服务的人时,会造成问题...

Eureka的2个概念

  • eureka-server服务端,注册中心,记录和管理服务
  • eureka-client客户端,无论是服务的提供者还是消费者,都是eureka的客户端

Eureka的使用流程

  • 只要是eureka-client客户端,无论是服务的提供者还是消费者,在启动时都会被注册到eureka-server注册中心,当游人需要调用服务时,不是直接找服务的提供者,而是找Eureka-server,询问是否有相应的服务,Eureka-server找到之后会直接提供给对方。
  • 然后使用负载均衡,在这些服务之中选择一个。为了保证不会找到挂掉的服务,Eureka每三十秒发送一次请求,如果有的服务没有响应,就认为该服务已经挂掉,将其从注册中心里边清除;

4.搭建Eureka服务

  • 1.创建项目,导入依赖spring-cloud-starter-netflix-eureka-server(Eureka服务端依赖)
xml 复制代码
<dependency>
	<goupId>org.springframework.cloud</goupId>
	<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

由于在父工程中已经指定了spring-cloud依赖库,所以里边的各种spring-cloud组件都已经被指定,因此子工程中eureka依赖不需要指定版本。

2.启动类添加@EnableEurekaServer

java 复制代码
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

3.添加配置信息(**由于eureka本身也是一个微服务,所以在启动时会将自己也注册到eureka上,为了将来eureka集群的使用),需要特别注意设置fetch-registry为false ,否则会报错,因为此时并没有其他服务的信息,所以如果让它拉取会报错, register-with-eureka,fetch-registry默认都为true

yml 复制代码
server:
  port: 10087 # 服务端口


spring:
  application:
    name: eurekaserver # 服务名称

# eureka服务注册信息
eureka:
  client:
    register-with-eureka: true # 是否注册自己的信息到EurekaServer
    fetch-registry: false # 是否拉取其它服务的信息
    service-url:
      defaultZone: http://127.0.0.1:10087/eureka

运行结果:

注册到eureka的实例(一个服务每注册一份就是一个实例)

5.服务注册

1.导入依赖

xml 复制代码
		<!--eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

2.新增配置,以user-service为例(只需要将服务名称改为对应的服务名称即可),其余同理

yml 复制代码
spring:
  application:
    name: userservice # user服务名称
# eureka服务注册信息
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10087/eureka

3.运行结果,可以看到已经注册了三个服务实例

6.同一个服务多次启动

这是我们当前IDEA的运行面板:

似乎并不是非常的方便,于是我们将其修改为Run Dashboard面板,点击下图所示的"服务"

添加springboot配置即可,运行结果(适用于2020,2021版本):

右键单击一个服务,以orderservice为例,点击"复制配置"

随后弹出窗口

由于启动同样的服务使用同样的端口会造成冲突,所以重新配置新的服务的端口为8082。

点击应用,启动之,运行结果:

此时,在eureka注册中心中配置了2个orderserivce服务

7.服务的发现

  比如在orderservice中完成服务拉取,"服务拉取"就是**基于服务名称获取服务列表,然后对服务列表做负载均衡。

  • 修改OrderService代码,修改访问的URL路径,用服务名代替IP,端口号
java 复制代码
 String url="http://userservice/user/"+order.getUserId();
  • 在RestTemplate中添加负载均衡注解@LoadBalanced
java 复制代码
	@Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
相关推荐
混凝土拌意大利面8 分钟前
基于MQ(消息队列)的RPC框架
架构
小荷才露尖尖角,早有蜻蜓立上头24 分钟前
过滤器的4种创建方式
java
大圣编蚕34 分钟前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
程序员阿明1 小时前
idea把插件啥的不默认放在C盘
java·ide·intellij-idea
小艾.pino1 小时前
MiniMax M3顶住新一代多模态大模型的架构与实战
人工智能·架构
linweidong1 小时前
中科闻歌Java面试题及参考答案
java·python·大模型·提示词·ai agent·mcp·rag原理
OpenAnolis小助手2 小时前
一句话看透 JVM,SysOM 诊断 Skill 新增 Java 应用诊断能力
java·开发语言·jvm·阿里云·操作系统控制台·sysom
ForteScarlet2 小时前
Kotlin 2.4.20 现已发布,新特性多不多?
android·java·开发语言·开源·kotlin·jetbrains
萧瑟余晖2 小时前
Java深入解析篇六十二之安全机制详解
java·开发语言
小刘在重生~2 小时前
Java 常用类|包装类 装箱拆箱、Integer 缓存面试题
java·python·缓存