SpringCloud-整体学习(一)SpringCloud简介+版本选择
SpringCloud-整体学习(二)项目初始构建-加公共部分提取
SpringCloud-整体学习(三)Eureka、zookeeper、Consul(注册中心)
SpringCloud-整体学习(四)Ribbon(负载均衡+手写轮询算法)
SpringCloud-整体学习(五)OpenFeign(服务调用)
SpringCloud-整体学习(六)Hystrix(服务降级)
SpringCloud-整体学习(七)GateWay(服务网关)
SpringCloud-整体学习(八)Config、Bus、Stream(服务配置和消息交互)
SpringCloud-整体学习(九)Sleuth(分布式请求链路追踪)
SpringCloud-整体学习(十)SpringCloudAlibaba(注册中心+配置中心)
SpringCloud-整体学习(十一) Sentinel(服务降级)
SpringCloud-整体学习(十二) Seata(分布式事务)
git :
https://github.com/lucine-maker/cloud2020
gitee:
https://gitee.com/lucine_li_tao/springcloud
Eureka基础知识
为什么要用注册中心
我们在上面不是已经实现了服务之间的调用了吗?需求应该已经满足了啊,但是量变引起质变,当服务数量增加后,我们就需要对服务进行管理,我们需要知道服务现在的情况和一些信息,以及流量控制。
这个时候我们就需要中服务之前加一个类似于前台一样的注册中心。
Eureka包含两个组件 Eureka Server 和Eureka Client
Eureka Server 提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server 中的服务注册表中将会存储所有可用的服务节点信息,服务节点的信息可以在界面中看到。
Eureka Client 通过注册中心进行访问
是一个java客户端,用于简化Eureka Server交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法和负载均衡器。
在应用启动后,将会向Eureka Server发送心跳(默认周期30second)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90second)。
一句话理解:
Eureka 有一个客户端一个服务端(java客户端),客户端用来连接Eureka,服务端用来管理监测连接进来的服务。
Eureka服务端安装
创建新的module
结构如下
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不像注册中心注册自己
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护实例,并不需要去检测服务
fetch-registry: false
service-url:
#设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
并且在主启动类上添加@EnableEurekaServer
标志是服务端。
http://localhost:7001/ 访问地址出现如下页面就表示成功
支付微服务8001入驻进eurekaServer
改pom:
在cloud-provider-payment8001 pom中加入坐标
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
写yml:
eureka:
client:
#表示是否将自己注册进入EurekaServer默认是true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true,单点无所谓,集群必须设置为true,才能ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
并且在8001 main中加入@EnableEurekaClient
启动8001就会在Eureka中 成功入驻
订单微服务80入驻进eurekaServer
1、改pom
2、main中加入@EnableEurekaClient
与上面8001一致
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
#表示是否将自己注册进入eurekaServer默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有信息,默认为true,单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka/
Eureka集群原理说明
集群主要方法就是相互注册,相互守望。
如果是3台也要相互注册
1 -》2、3
2-》1、3
3-》2、3
Eureka集群环境构建
参考7001创建一个类似的7002
在hosts下面加上 用不同的地址映射同一个本地。(模拟不同的地址)
7001 yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false表示不像注册中心注册自己
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护实例,并不需要去检测服务
fetch-registry: false
service-url:
#设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka
7002 yml
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
#false表示不像注册中心注册自己
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护实例,并不需要去检测服务
fetch-registry: false
service-url:
#设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001:7001/eureka
http://eureka7002.com:7002 也是类似的页面
订单支付两微服务注册进Eureka集群
80/8001中都加入
在yml中加入
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
然后启动7001/7002
后面再启动80/8001
http://eureka7002.com:7002/
http://eureka7001.com:7001/
访问正常
如果想要更改访问的eureka路径(其他注册改服务的地方都更改名称即可)
eureka:
dashboard:
path: /aa
如果失败检查对应注册的路径是否正常。
支付微服务集群配置
在业务场景中支付微服务可能要部署多个,这时候我们就需要创建多个支付的服务
同时注册进入。
参考8001
新建8002 (复制的话记得改yml的端口)
注:
坑1:
我刚开始在创建的8002的时候,没有按照流程直接新建,直接粘贴的,导致目录结构混乱 ,然后把8002删了
,当我再次新建项目8002(同样名字的)的时候我的pom正常,但是我的下图是空白的。
导致我的项目中没有依赖。解决方法 在项目的.idea文件中misc.xml 中删除
该部分内容!
然后测试8002可以正常加入然后由于我们之前访问的地址端口是写死的,不能够进行集群。
private static final String PAYMENT_URL=“http://CLOUD-PAYMENT-SERVICE”;
我们用服务名称去访问,并且在RestTemplate 的配置中加入@LoadBalanced
测试的话:使用@value注解把端口号加载进来,分别在8001、8002中加入,这样访问就可以验证了。
actuator微服务信息完善(不是很重要)
更改之前显示的本地ip或者localhost,更改可设置的信息
在鼠标放上去在左下角要显示ip信息
instance:
instance-id: payment8001
prefer-ip-address: true #访问路径可以显示ip
效果图:
服务发现Discovery
在8001 controller中加上下面的代码 ,并在启动上加@EnableDiscoveryClient 注解
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/payment/discovert")
public Object getDiscoveryClient(){
List<String> services = discoveryClient.getServices();
for (String server:
services) {
log.info("***element"+server);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance:
instances) {
log.info(instance.getInstanceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return this.discoveryClient;
}
效果图:
eureka自我保护机制
-
故障现象:
-
导致原因:
某时刻某一个微服务不可用了,Eureka不会立刻清除掉,依旧会对微服务的信息进行保存。
属于CAP里面的AP分支。 -
为什么会产生Eureka自我保护机制?
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通,Eureka不会立刻清除EurekaClient服务剔除。
我的理解:防止网络波动,产生短期的不可用,误以为服务停止。
再次加深理解:
怎么禁止Eureka自我保护
为了方便我切换了单机,没有连接7001,但是我截图没有截出来,可以自行更改。
在7002(客户端)yml
server:
#关闭自我保护机制,保证不可用服务被及时剔除
enable-self-preservation: false
#过期实例应该启动并运行的时间间隔
eviction-interval-timer-in-ms: 2000
在8001(服务端)yml
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
坑:
可能是由于版本原因我服务本身就会直接剔除服务
所以我试了下让他不剔除,但是当我用idea的直接结束客户端(8001)的时候,他把的的客户端直接剔除了。
解决:
关闭客户端是通过idea关闭,idea让它们正常的走了应用消亡的生命周期,让资源得到了回收。使用命令 ps -ef |grep 8001 找到指定的id,kill 杀掉进程。就ok了。
Eureka停更说明
https://github.com/Netflix/eureka/wiki
由于没有后续代码上的提升,更新维护。
所有需要其他的提供注册发现的代替品。
支付服务注册进zookeeper
服务注册的基本理念都是互通的
在eureka使用中在yml中加入的信息,在启动类中配置相关注解,
可以大概推算出zookeeper或其他的一些服务注册也是类似的配置。
新建项目8004
pom:(于其他800*类似,只替换了eureka的相关dependency为zookeeper)
<!--springboot整个zookeeper-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
yml (端口等写自己服务启动的信息。)
server:
port: 8004
#服务别名---注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 127.0.0.1:2181
zookeeper 快速安装
https://blog.csdn.net/cainiao_ACCP/article/details/72942894
主要命令和步骤:
zoo.cfg文件内容
tickTime=2000
dataDir=/Users/admin/Java/zookeeper-3.4.9/data
dataLogDir=/Users/admin/Java/zookeeper-3.4.9/logs
clientPort=2181
启动: ./zkServer.sh start
停止:./zkServer.sh stop
也可以执行zkServer.sh start-foreground命令,非后台运行ZooKeeper Server进程
controller:(目的知识监测是否成功注入,写的如下信息监测。)
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/zk")
public String paymentzk(){
return "springCloud with zookeeper :"+serverPort+"\t" + UUID.randomUUID().toString();
}
}
说下遇到的问题
:
可能是版本问题并没有遇到视频中说的问题,但是遇到了
解决方案:
主启动类中更改下面的注解
@SpringBootApplication(exclude = {DruidDataSourceAutoConfigure.class,DataSourceAutoConfiguration.class})
原因在下面的地址(该文章的评论区解决方法还不错):
https://blog.csdn.net/qq_40223688/article/details/88191732
zookeeper临时还是持久节点
第一个框框是刚停止
第二个框框是停止了一段时间
第三个框框是再次注册进入
可得出
在服务停止后不会马上移除,而是在一定的心跳周期内,如果之后还没有回复的话后面就直接移除,再次注册会是新的节点。
节点是临时的。
订单服务注册进zookeeper
新建consumerzk80并配置zookeeper
1、更改pom:
从8004里面找pom 下面的依赖部分
2、yml (找8004的yml 更改端口号即可)
3、restTemplate (和之前80一致)
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
4、controller (在后面有部分图中consumer 单词不对 因为懒得换图就没重新截
,引以为戒)
@RestController
@Slf4j
public class OrderZKController {
private static final String INVOKE_URL="http://cloud-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value ="/consumer/payment/zk")
public String paymentInfo(){
String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
return result;
}
}
效果图:
Consul简介(Go写的)
官网:
https://www.consul.io/docs/intro
下载地址:
https://www.consul.io/downloads
中文文档:
https://www.springcloud.cc/
中的
我本身是mac的,需要配置环境变量,解压完成后
sudo scp consul /usr/local/bin/ 执行该命令
window的去下载地址下载window,启动exe文件就好了。
consul --version 验证结果
consul agent -dev
访问
本地8500端口
服务提供者注册进Consul
新建8006 cloud-provider-payment8006
结构
pom (与其他provider相差不大,只写区别):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
yml
server:
port: 8006
spring:
application:
name: consul-provider-payment
#consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
# hostname: 127.0.0.1
service-name: ${spring.application.name}
Controller:
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul(){
return "springCloud with consul :"+serverPort+"\t" + UUID.randomUUID().toString();
}
}
服务消费者注册进Consul
新建cloud-consumer-consul80
pom (其他部分与其他的80消费者差不多)
<!--consul-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
yml (跟8006的consul服务差不多 — 改了端口和服务名称)
server:
port: 80
spring:
application:
name: consul-consumer-payment
#consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
# hostname: 127.0.0.1
service-name: ${spring.application.name}
controller 和config (基本其他消费者一致)
唯一需要注意就是 1、调用的服务名称2、调用的服务地址url
效果
三个注册中心异同点
如果想详细了解CAP
https://blog.csdn.net/ywl470812087/article/details/102616602