SpringCloud 微服务分布式
软件行业分类:
传统软件行业
互联网软件行业
软件架构分类:
微服务
单体架构
单体应用
一个归档包(可以是JAR、WAR、EAR或其它归档格式)包含所有功能的应用程序,通常称为
单体应用。
优点
- 便于共享: 单个归档文件包含所有功能,便于在团队之间以及不同的部署阶段之间共享。
- 易于测试:
单体应用一旦部署,所有的服务或特性就都可以使用了,这简化了测试过程。
因为没有额外的依赖,每项测试都可以在部署完成后立刻开始。- 易于部署: 只需将单个归档文件复制到单个目录下。
缺点
- 复杂性高:
由于是单个归档文件,所以一个文件 等于 整个项目,文件包含的模块非常多,导致模块的边界模糊。
依赖关系不清晰、代码的质量参差不齐,混乱的堆在一起,使得整个项目非常复杂。
以致每次修改代码,都非常小心,可能添加一个简单的功能,或者修改一个Bug都会带来隐藏的缺陷。- 技术债务:
随着时间的推移、需求的变更和技术人员的更替,会逐渐形成应用程序的技术债务,并且越积越多。- 扩展能力受限:
单体应用只能作为一个整体进行扩展,无法根据业务模块的需要进行伸缩。
(为了提高项目性能可以, 将一个项目复制多份部署多台服务器~)- 阻碍技术创新:
对于单体应用来说,技术是在开发之前经过慎重评估后选定的,
每个团队成员都必须使用相同的开发语言、持久化存储及消息系统。
微服务
2014 ,martin fowler马丁·福勒
提出的:微服务架构风格
常听的:分布式微服务
优点:
一个应用拆分为一组小型服务
每一个服务: 运行在自己的进程内,也就是可独立部署和升级,拥有自己独立的数据库。通过HTTP的方式进行互通;
• 优点
• 服务围绕业务功能拆分
• 可以由全自动部署机制独立部署
• 微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。
• 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
• 去中心化,服务自治。服务可以使用不同的语言、不同的存储技术;只要实现功能即可~
•微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。
•每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。
上图:微服务分布式架构,每一个点表示一个功能, 使用时只需要调用需要的功能模块组合即可!
缺点:
- 运维要求高: 更多的服务意味着要投入更多的运维。
- 分布式固有的复杂性:
使用微服务构建的是分布式系统。对于一个分布式系统,系统容错、网络延迟、
分布式事务等都会带来巨大的问题。- 接口调整成本高:
微服务之间通过接口进行通信。
如果修改某一个微服务的API,可能所有用到这个接口的微服务都需要进行调整。
远程调用、服务发现、负载均衡、服务容错、配置管理、服务监控、链路追踪、日志管理、任务调度……
相关概念
Provider和Consumer
分布式微服务架构中,把一个应用差分为多个 功能模块; 每个功能模块专注做自己的事情…
当需要实现某一功能时候, 只需要对多个需要的 功能模块直接相互调用即可…
那么每个模块即是 Provider也是Consumer
(提供者和调用者)…
RPC和Restful
什么叫RPC
- RPC【Remote Procedure Call】是指
远程过程调用
是一种进程间通信方式,他是一种技术的思想,而不是规范。
它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,
而不用程序员显式编码这个远程调用的细节。
即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。即网络通信
什么是REST
- REST是一种
架构风格
,指的是一组架构约束条件和原则。 - 满足这些约束条件和原则的应用程序或设计就是 RESTful。
- REST规范把所有内容都视为资源,网络上一切皆资源。
- REST并没有创造新的技术,组件或服务,只是使用Web的现有特征和能力。
- 可以完全通过HTTP协议实现,使用 HTTP 协议处理数据通信。
- REST架构对资源的操作包括获取、创建、修改和删除资源的操作
正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。 - 这个之前学MVC时候学习过…
分布式
一个应用拆分为多个不同的功能模块,做不同的事情
!
集群
一台服务器,承受不住某个工作,为了减轻服务器压力,做集群 负载均价…多个设备做同一见事情!
选择SpringCloud作为微服务
选型依据
- 整体解决方案和框架成熟度
- 社区热度
- 可维护性
- 学习曲线
当前各大IT公司用的微服务架构有哪些?
- 阿里Dubbo/HSF
- 京东JSF
- 新浪微博Motan
- 当当网DubboX
各微服务框架对比
分布式基础理论
什么是分布式系统?
《分布式系统原理与范型》定义:
“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
分布式系统(distributed system)是建立在网络之上的软件系统。
发展演变
单一应用架构——垂直应用架构——分布式服务架构——流动计算架构
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,
以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
适用于小型网站,小型管理系统,将所有功能都部署到一个功能里,简单易用。
缺点:
性能扩展比较难 协同开发问题 不利于升级维护...
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用
以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
通过切分业务来实现各个模块独立部署:
降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性。
缺点: 公用模块无法重复利用,开发性的浪费
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,
作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。
此时,用于提高业务复用及整合的分布式服务框架(RPC)
是关键。
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,
此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。
提高机器利用率的资源调度 和 治理中心(SOA)[ Service Oriented Architecture]
是关键。
springClond入门 应用开发
SpringBoot和SpringCloud的区别
- SpringBoot专注于快速方便的开发单个个体微服务。
- SpringCloud是关注全局的微服务协调整理治理框架
它将SpringBoot开发的一个个单体微服务整合并管理起来:为各个微服务之间提供
配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务… - SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于
依赖的关系
- SpringBoot专注于快速、方便的开发单个微服务个体
- SpringCloud关注全局的服务治理框架。
搭建springcloud工程 分布式服务架构
创建一个普通的Maven项目
为了方便开发使用 Maven高级应用...
开发项目:当然你也可以不用Maven来测试,多起几个项目工程...
这里删掉主工程的src (反之也用不上
主工程的pom.xml
中加入公共依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>SpringCloudBJ</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<!-- Maven父工程包含管理的子工程... -->
<modules>
<module>common_api</module>
<module>common_orderService</module>
<module>common_userService</module>
</modules>
<!-- SpringBoot父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<!-- 统一设置Maven项目编码 jdk环境 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- spring-boot的web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-boot的应用日志依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- spring-boot的单元测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok的依赖组件,别忘了要下载Idea lombok的插件哦~ -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- 指定SpringCloud配置必要!! -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version> <!-- 版本... -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- maven的默认下载资源.. -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
关于SpringCloud版本:Greenwich
SpringCloud版本更新非常快!A B C D E F G H目前最高已经到H了
我凑!!
2021年初
创建Maven子工程common_api实体模块
主要存放项目开发所需要的实体类…
这里只有一个实体类…没有什么太复杂的操作
Order.Java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@AllArgsConstructor
@RequiredArgsConstructor
//创建一个实体类: 并根据lombok 及其注解生产对应的 构造函数,toString(); get/set...
public class Order {
private Integer id;
private String title;
private Double price;
private Integer uid;
}
pom.xml
不用任何添加或改动…看一下我其它Maven子工程如果调用;
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common_api</artifactId>
</project>
创建Maven子工程common_orderService订单模块
编写订单模块相对于的代码…
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common_orderService</artifactId>
<!-- 关键!! -->
<dependencies>
<!-- common_orderService工程引入common_api -->
<dependency>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>common_api</artifactId>
</dependency>
</dependencies>
</project>
OrderService.Java
import com.wsm.entity.Order;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class OrderService {
//模拟假订单集合...
private static List<Order> orders = new ArrayList<>();
//类加载时候默认获取一些数据..模拟假订单..
static {
orders.add(new Order(1, "订单11", 10.0, 1));
orders.add(new Order(2, "订单21", 10.0, 2));
orders.add(new Order(3, "订单31", 10.0, 1));
orders.add(new Order(4, "订单41", 10.0, 2));
}
//根据输入用户id获取当然用订单集合..
public List<Order> findOrderByUser(Integer uid) {
List<Order> myorders = new ArrayList<>();
//遍历集合从中获取 uid一致的数据存放在集合中返回...
for (Order order : orders) {
if (order.getUid() == uid) {
myorders.add(order);
}
}
return myorders;
}
}
OrderController.Java
import com.wsm.entity.Order;
import com.wsm.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class OrderController {
@Autowired
private OrderService os;
//REST风格进行请求..
@GetMapping("/findOrderByUser/{uid}") //参数是以 /请求名/{参数1}/{参数2} 进行访问的...
public List<Order> findOrderByUser(@PathVariable Integer uid){
//REST风格参数需要使用 @PathVariable获取!!
return os.findOrderByUser(uid);
}
}
SpringBoot的主工程类:MyOrderServer.Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyOrderServer {
public static void main(String[] args) {
SpringApplication.run(MyOrderServer.class, args);
}
}
SpringBoot application.yml
配置文件
server:
port: 6001 #设置端口6001 当有多个微服务时候注意端口号可别冲突了..
spring:
application:
name: order-server #设置当然微服务名,后面的 注册/调用服务,都是根据这个来的;
创建Maven子工程common_userService 用户模块
编写用户模块相对于的代码…
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common_userService</artifactId>
<dependencies>
<!-- common_userService工程引入common_api -->
<dependency>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
<artifactId>common_api</artifactId>
</dependency>
</dependencies>
</project>
UserService.Java
@Service
@Slf4j //加载lo4g使用...
public class UserService {
@Autowired
private RestTemplate restTemplate;
//通过restTemplate进行网络通信,返回..其它远程模块的数据(虽然现在都是本地的不过就是模拟了..)
public List<Order> currentUserOrder(Integer uid) {
log.info("用户服务调用订单服务");
//硬编码的调用!! 这里的请求都写死的...这好吗?这不好...后面修改;
String myurl = "http://localhost:6001/findOrderByUser/" + uid;
log.info(myurl
);
List<Order> list = restTemplate.getForObject(myurl, List.class);
return list;
}
}
UserController.Java
//编程控制层,接受请求响应结果
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/showUserOrder")
public List<Order> showUserOrder(Integer uid){
return userService.currentUserOrder(uid); //调用Service层
//Service又是通过网络调用 订单模块来响应的结果,因此在此基础上要缺点订单模块是运行中的...
}
}
SpringBoot的主工程类:MyUserServer.java
@SpringBootApplication
public class MyUserServer {
public static void main(String[] args) {
SpringApplication.run(MyUserServer.class, args);
}
@Bean
//实例化 RestTemplate 方便Service
//可别忘了@SpringBootApplication复合注解底层可以有@SpringBootConfiguration 它也是一个Spring的配置类!
public RestTemplate createRestTemplate() {
return new RestTemplate();
}
}
SpringBoot application.yml
配置文件
server:
port: 6002 #设置端口6002 当有多个微服务时候注意端口号可别冲突了..
spring:
application:
name: user-server #设置当然微服务名,后面的 注册/调用服务,都是根据这个来的;
服务调用
前文已经编写了三个基础的微服务,在用户下单时需要调用商品微服务获取商品数据。
商品微服务提供了供人调用的HTTP接口
- 所以可以再下定单的时候使用http请求的相关工具类完成,
如常见的HttpClient,OkHttp,当然也可以使用Spring提供的RestTemplate
RestTemplate介绍
Spring框架提供的RestTemplate类可用于在应用中调用rest服务
它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接
- 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,
- RestTemplate是一种更优雅的调用RESTful服务的方式。
- RestTemplate类的设计原则与许多其他Spring 模板类(例如JdbcTemplate、JmsTemplate)相同
为执行复杂任务提供了一种具有默认行为的简化方法。 - RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection)
如果有需要的话也可以通过setRequestFactory方法替换为例如
Apache HttpComponents、Netty或OkHttp等其它HTTP library。 - 考虑到RestTemplate类是为调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了
后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。
RestTemplate类具有headForHeaders()、getForObject()、postForObject()、put()和delete()等方法。
硬编码存在的问题
至此已经可以通过RestTemplate调用商品微服务的RESTFul API接口。
但是我们把提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:
- 应用场景有局限
- 无法动态调整
- …
那么应该怎么解决呢,就需要通过:注册中心
动态的对服务注册和服务发现
总结
以上就是一个典型的分布式模块架构
多模块业务之间的相互调用 但↓↓↓↓
因为是用户模块—引用—订单模块
订单是提供者provide
用户是调用者Consumer
- 而如果订单模块服务未开启的情况下,会影响用户模块的使用!
注意!
- 而对应大量的模块之间的调用, 随着项目业务扩大…模块之间的引用也会越来越复杂!!
- 而对于 A模块服务停止 B模块服务受影响…如果加剧呢 C模块 D模块…
B依赖A C依赖B D依赖C 而这时候A没了会之间的造成服务的崩塌!!
为了解决这种问题, 注册中心
就出现了
服务注册Eureka基础
注册中心可以说是微服务架构中的 ”通讯录“,它记录了服务和服务地址 映射关系在分布式架构中
服务会注册到这里,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。
注册中心的主要作用
服务注册中心是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。
注册中心一般包含如下几个功能:
- 服务发现:
提供者/调用者需要注册声明在注册中心中才可以相互使用.
服务注册/反注册:保存服务提供者和服务调用者的信息
服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
服务路由(可选):具有筛选整合服务提供者的能力。 - 服务配置:
代码上, 服务提供者/调度者需要配置注册中心
配置订阅:服务提供者和服务调用者订阅微服务相关的配置
配置下发:主动将配置推送给服务提供者和服务调用者 - 服务健康检测
服务要定时的向注册中心提供心跳♥
告诉注册中心我还在能干活
当然注册中心一般都有自我保护机制…
检测服务提供者的健康情况
常见的注册中心
- Zookeeper
zookeeper它是一个分布式服务框架,是Apache Hadoop 的一个子项目
它主要是用来解决分布式应用中经常遇到的一些数据管理问题,
如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
简单来说zookeeper=文件系统+监听通知机制。 - Eureka
Eureka是在Java语言上,基于Restful Api开发的服务注册与发现组件,Springcloud Netflflix中的重要组件 - Consul
Consul是由HashiCorp基于Go语言开发的支持多数据中心分布式高可用的服务发布和注册服务软件
采用Raft算法保证服务的一致性,且支持健康检查 - Nacos
是阿里巴巴推出来的一个新开源项目
Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
简单来说 Nacos 就是注册中心 + 配置中心的组合,提供简单易用的特性集
帮助我们解决微服务开发必会涉及到的服务注册与发现,服务配置,服务管理等问题。
**Nacos 还是 Spring Cloud Alibaba 组件之一,负责服务注册与发现。 **
Eureka的基本架构
Spring Cloud 封装了 Netflix 公司开发的 Eureka
Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
- 使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。
- 这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。
- Eureka包含两个组件:
Eureka Server
和Eureka Client
- Eureka Server提供服务注册
服务
各个节点启动后,会在EurekaServer中进行注册,
这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,
服务节点的信息可以在界面中直观的看到 - EurekaClient是一个Java客户端,用于简化Eureka Server的交互
客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。
如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
三大角色
- Eureka Server 提供服务注册和发现
- Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
- Service Consumer 服务消费方从Eureka获取注册服务列表,从而能够消费服务
使用时先启动注册中心——Provider提供者——Consumer调用者
重构SpringCloud工程 流动计算架构
基于上面的SpringCloud的分布式服务架构
开发
创建Maven子工程eureka-server 注册中心
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eureka-server</artifactId>
<!-- Eureka-server服务依赖,必须! -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 7001 #设置注册中心的 端口;
spring:
application:
name: eureka-server #注册中心应用名称;
#配置注册中心....
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/ #注册中心对外暴漏的注册地址...
#要不要去注册中心获取其他服务的地址,默认为true (目前只有一个注册中心而且,当前就是注册中心..)
fetch-registry: false
#是否将允许自己注入注册中心,默认为true (目前只有一个注册中心而且,当前就是注册中心..自己注册自己?)
register-with-eureka: false #如果一个应用中有两个注册中心可以开启,达到集群注册中心的目的...
主程序类MyEurekaServer.Java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //注解主程序开启 Eureka服务
public class MyEurekaServer {
public static void main(String[] args) {
SpringApplication.run(MyEurekaServer.class, args);
}
}
@EnableEurekaServer
启动注册中心的服务, 表示当前项目作为SpringCloud中的注册中心
现在启动程序就可以访问当前的注册中心了…
修改上面SpringBoot微服务 注册到注册中心中去!
common_orderService/userService注册到注册中心去:
加载注册服务依赖
pom.xml
<!--- 注册服务的依赖.. -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
主程序中加入 @EnableEurekaClient 注入注册中心
以订单的主程序为例子, 其它也都这么做
MyOrderServer.Java
@SpringBootApplication
@EnableEurekaClient
public class MyOrderServer {
public static void main(String[] args) {
SpringApplication.run(MyOrderServer.class, args);
}
}
@EnableEurekaClient 启动注册中心客户端
表示当前主程序注册到注册中心去…
@EnableDiscoveryClient与@EnableEurekaClient区别
@EnableDiscoveryClient,一种为@EnableEurekaClient,用法上基本一致。
- @EnableEurekaClient是针对于 Eureka注册中心专门的启动注册
注解
- @EnableDiscoveryClient在包含了@EnableEurekaClient
它是对于所以注册中心的一个统一开启注解…
SpringBoot .yml文件的Eureka的配置
配置文件配置注册中心 Eureka
(以业务order的为例子)
application.yml
server:
port: 6001 #设置端口6001 当有多个微服务时候注意端口号可别冲突了..
spring:
application:
name: order-server #设置当然微服务名,后面的 注册/调用服务,都是根据这个来的;
eureka:
client:
service-url: #修改注册中心不上本地的ip 更改为无线网的ip 实现多设备连接...
defaultZone: http://localhost:7001/eureka/ #指定服务注册的注册中心;
instance:
prefer-ip-address: true #在Eureka上使用ip号..
instance-id: ${spring.cloud.client.ip-address}:${server.port} #在Eureka上显示ip号..
最后别忘了把 common_userService中硬编码解决了
UserService.Java
import com.wsm.entity.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient; //这个DiscoveryClient别搞错
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Service
@Slf4j //加载lo4g使用...
public class UserService {
@Autowired
private RestTemplate restTemplate;
//通过restTemplate进行网络通信,返回..其它远程模块的数据(虽然现在都是本地的不过就是模拟了..)
@Autowired //实现动态调用...
private DiscoveryClient discoveryClient;
public List<Order> currentUserOrder(Integer uid) {
//获取注册中心上的微服模块实例 根据服务名;
//返回一个集合: 有可能这个服务在多个注册中心上存在,`负载均衡~` 所以是一个集合;
List<ServiceInstance> instances = discoveryClient.getInstances("order-server");
ServiceInstance serviceInstance = instances.get(0); //而本次只有一个...
log.info("用户服务调用订单服务");
//动态调用服务 服务的host 服务端口号 这个就是服务controller请求 给其参数uid
String myurl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/findOrderByUser/" + uid;
log.info(myurl);
List<Order> list = restTemplate.getForObject(myurl, List.class);
return list;
}
}
动态的从注册中心Eureka上获取ip
查看这里的 ip 192.168.1.1
- windows+r
- cmd
- 输入ipconfig
- 如果是在同一个网段下, 可以实现不同电脑通过同一个注册中心进行使用…
但我这个目前没有弄无线局域网配置器...
- 把代码的的Eureka 服务配置本地 修改为 无线网的 ip 地址这样同一个网络下。
多个设备写的服务连接同一个注册中心…
可以实现 A,C电脑——连接B的注册中心——A可以去B注册中心中调用 C的服务… 可以尝试~
Eureka的服务剔除问题
在服务客户端Client 配置的~
默认 30秒心跳💓 90秒续约时间…
服务客户端Client 配置的 .yml
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/ #指定服务注册的注册中心;
instance:
prefer-ip-address: true #在Eureka上显示ip号..
instance-id: ${spring.cloud.client.ip-address}:${server.port} #在Eureka上显示ip号..
lease-renewal-interval-in-seconds: 5 #客户端向注册中心发送心跳时间
lease-expiration-duration-in-seconds: 10 #如果没有发送心跳的延迟续约时间...
如果客户端的服务因为某些原因关闭了。Eureka会根据心跳检测到你没了而移除你的服务…
- 客户端定时向
注册中心
发送心跳如果超过时间没有发送 默认30秒 - 会有一个延迟等待时间. 默认90秒
两分钟~
如果还没有启动Eureka会把服务剔除… - 但, 因为
Eureka自我保护机制
服务并不会真的 移除…而是会给你一个时间如果还没有回来~则报错!
Eureka自我保护机制
一般不会关闭自我保护机制,因为如果服务又好了又可以立刻注册会来使用...
在服务端即 注册中心
关闭保护机制。。。
注册中心的.yml
#配置注册中心....
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/ #注册中心对外暴漏的注册地址...跟随注册中心 提供的一致~
#要不要去注册中心获取其他服务的地址,默认为true (目前只有一个注册中心而且,当前就是注册中心..)
fetch-registry: false
#是否将允许自己注入注册中心,默认为true (目前只有一个注册中心而且,当前就是注册中心..自己注册自己?)
register-with-eureka: false #如果一个应用中有两个注册中心可以开启,达到集群注册中心的目的...
server:
enable-self-preservation: false #默认是ture 开启的
eviction-interval-timer-in-ms: 4000 #默认是0 从不剔除!
保护机制只要关闭就会报错!
而且只要服务失效就会移除…
nice 终于写完了,建议三联!!