技术标签: zookeeper eureka spring cloud Spring Cloud
使用SpringCloud版本:
2.1.1.RELEASE
单一应用架构
当网站流量很小时,只需要一个应用,所有功能打成一个包部署在一起,减少部署节点成本的框架称之为集中式框架。此时,用于简化增删改查工作量的数据访问框架(ORM)是影响项目开发的关键。
优点:
缺点:
分布式服务架构
根据业务功能对系统做拆分,每个业务功能模块作为独立项目开发,称为一个服务。
优点:
缺点:
分布式架构虽然降低了服务耦合,但是服务拆分时也有很多问题需要思考:
人们需要制定一套行之有效的标准来约束分布式架构。
微服务架构:
微服务的架构特征:
微服务的上述特性其实是在给分布式架构制定一个标准,进一步降低服务之间的耦合度,提供服务的独立性和灵活性。做到高内聚,低耦合。
因此,可以认为微服务是一种经过良好架构设计的分布式架构方案 。其中微服务架构的最佳实践是SpringCloud。
其中常见的组件包括:
由于升级和停更引发的技术变更:(圈起来的是阳哥推荐的技术)
另外,SpringCloud底层是依赖于SpringBoot的,并且有版本的兼容关系,如下:
https://spring.io/projects/spring-cloud#overview
目标:模拟一个最简单的服务调用场景,场景中保护微服务提供者(Producer)和微服务调用者(Consumer),方便后面学习微服务架构
注意:实际开发中,每个微服务为一个独立的SpringBoot工程
项目架构:
主要工作:创建SpringBoot工程(cloud-provider-payment8001)、加入依赖坐标、编写配置、编写MVC架构代码。
application.yml配置文件代码:
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.zb.springcloud.entities # 所有Entity别名类所在包
controller层代码:
注意不要忘记@RequestBody
注解
@RestController
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;
@PostMapping(value = "/payment/create")
public CommonResult crete(@RequestBody Payment payment){
//注意不要忘记@RequestBody
int result = paymentService.create(payment);
log.info("******插入结果:" + result);
if(result > 0) {
return new CommonResult(200,"插入数据库成功",result);
} else {
return new CommonResult(444, "插入数据库失败", null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
{
Payment payment = paymentService.getPaymentById(id);
log.info("*****查询结果:{}",payment);
int w = 5/2;
if (payment != null) {
return new CommonResult(200,"查询成功",payment);
}else{
return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
}
}
}
访问测试:http://localhost:8001/payment/get/3
主要工作:
注册RestTemplate实例
RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程Http服务的方法。
@Configuration
public class ApplicationContextConfig {
@Bean //注册RestTemplate实例
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
实现远程调用
@RestController
@Slf4j
public class OrderController {
public static final String PAYMENT_URL = "http://localhost:8001";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
}
存在的问题:
上面那些问题都需要利用SpringCloud中的注册中心来解决,其中最广为人知的注册中心就是Eureka。
项目架构:
新建SpringBoot注册中心服务端cloud-eureka-server7001
引入eureka依赖(eureka-server)
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
编写启动类,一定要添加一个@EnableEurekaServer
注解,开启eureka的注册中心功能:
@SpringBootApplication
@EnableEurekaServer
public class ServerMain7001 {
public static void main(String[] args) {
SpringApplication.run(ServerMain7001.class, args);
}
}
application.yml文件编写:
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/
启动微服务,然后在浏览器访问:http://127.0.0.1:7001
下面,我们将服务消费者和服务提供者注册到eureka-server中。
项目架构:
引入eureka-client依赖
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改application.yml文件,添加服务名称、eureka地址
server:
port: 8001
spring:
application:
name: cloud-payment-service # 指定服务名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包 com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
*****************************************************************************************************
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
*****************************************************************************************************
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.zb.springcloud.entities # 所有Entity别名类所在包
在启动类上添加@EnableEurekaClient
,表明是Eureka客户端
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
引入eureka-client依赖
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改application.yml文件,添加服务名称、eureka地址
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
在启动类上添加@EnableEurekaClient
,表明是Eureka客户端
@SpringBootApplication
@EnableEurekaClient
public class MainApp80 {
public static void main(String[] args) {
SpringApplication.run(MainApp80.class,args);
}
}
查看eureka管理页面:
项目结构:
新建项目cloud-eureka-server7002
,用来搭建EurekaServer集群。
修改C:\Windows\System32\drivers\etc路径下的hosts文件,加入
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
修改eureka-server
的application.yml配置文件
将服务提供者和服务消费者同时注册到两个注册中心(可以只注册集群中的一个,信息会在集群中共享),修改每个项目的配置文件application.yml
查看eureka管理页面,可以发现另一个已经成为其备份的注册中心
项目结构:
目标把搭建服务提供者集群注册到eureka-server中,并且实现负载均衡
配置服务提供者集群,新建cloud-provider-payment8002工程(参考8001)。只需要修改配置文件的端口号为8002即可。
修改服务消费者中的OrderController中的方法。修改访问的url路径,用服务名代替ip、端口号
@RestController
@Slf4j
public class OrderController {
// public static final String PAYMENT_URL = "http://localhost:8001";
// 通过在eureka上注册过的微服务名称调用
public static final String PAYMENT_URL = "http://cloud-payment-service";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
}
在服务消费者配置类中给RestTemplate这个Bean添加一个@LoadBalanced
注解,用来实现负载均衡功
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
查看eureka管理页面
访问测试,spring会自动帮助我们从eureka-server端,根据服务名称,获取实例列表,而后完成负载均衡
主机名称、服务名称修改
# 修改 Eureka Server 页面的 Status 值
eureka.instance.instance-id=payment8001
访问信息有IP信息提示
# 带 ip + port 的超链接
eureka.instance.prefer-ip-address=true
修改之前没有IP提示
修改之后有IP提示
可以通过discoveryClient查看Eureka所有注册服务:
修改cloud-provider-payment8001的controller
@RestController
@Slf4j
public class PaymentController {
@Resource
private DiscoveryClient discoveryClient; //用于服务发现
@GetMapping(value = "/payment/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
for (String element : services) {
System.out.println(element);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance element : instances) {
System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
+ element.getUri());
}
return this.discoveryClient;
}
}
访问:http://127.0.0.1:8001/payment/discovery
控制台打印结果:
什么是自我保护模式?
默认情况下,服务每隔30秒会向注册中心续约(心跳)一次,如果没有续约,EurekaServer将会注销该实例(默认90秒)——心跳检测。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式
为什么会产生Eureka自我保护机制?
自我保护机制的工作机制?
禁止自我保护:
默认情况下自我保护机制是开启的。eureka.server.enable-self-preservation=true
关闭自我保护机制,修改检查失效服务的时间
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 3000
关闭效果:
服务续约过程:
服务每隔30秒会向注册中心续约(心跳)一次,如果没有续约,租约在90秒后到期,然后服务会被失效。每隔30秒的续约操作我们称之为:心跳
检测。
lease-renewal-interval-seconds:90,租约到期时效时间,默认90秒
Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。
提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows
官网地址:https://www.consul.io/intro/index.html
首先我们从官网下载Consul,地址:https://www.consul.io/downloads.html
下载完成后只有一个exe文件,双击运行
通过consul --version
查看版本号
使用开发模式启动consul agent -dev
通过以下地址可以访问Consul的首页:http://localhost:8500
项目架构:
服务提供者注册进Consul:
加入依赖
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml配置
# consul服务端口号
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}
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args){
SpringApplication.run(PaymentMain8006.class,args);
}
}
Controller代码编写
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/consul")
public String paymentInfo() {
return "springcloud with consul: "+serverPort+"\t\t"+ UUID.randomUUID().toString();
}
}
测试
输入http://localhost:8006/payment/consul,可以看到服务提供者已经被注册
服务消费者注册进Consul
加入依赖
application.yml配置
# consul服务端口号
server:
port: 80
spring:
application:
name: cloud-consumer-order
# consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
# hostname: 127.0.0.1
service-name: ${
spring.application.name}
主启动类
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class OrderConsulMain80 {
public static void main(String[] args)
{
SpringApplication.run(OrderConsulMain80.class,args);
}
}
配置RestTemplate实体bean
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Controller代码编写,通过RestTemplate调用服务提供者
@RestController
public class OrderConsulController {
public static final String INVOKE_URL = "http://consul-provider-payment"; //consul-provider-payment
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/consul")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
System.out.println("消费者调用支付服务(consule)--->result:" + result);
return result;
}
}
测试
访问服务消费者
CAP理论:
在一个分布式系统(指互相连接并共享数据节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)
、可用性(Availability)
、分区容错性(Partition Tolerance)
三者中的两个,另外一个必须被牺牲。
CAP原则:
AP架构(Eureka)
当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统的可用性
CP架构(Zookeeper/Consul)
当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性
文章浏览阅读1.2k次,点赞18次,收藏15次。斗鱼、wasm、js逆向、web逆向。_某鱼 逆向
文章浏览阅读737次。由于中大的oj需要内网才能进去,就提供不了原始题目了,但是题目的意思就是说,开始有一对成年兔子,一对成年兔子每年能生一对幼兔,幼兔等m个月才成长为成年兔子,问d个月后总共有多少对兔子。输入m d 2 3 3 5 1 100输出 5 9 100题目意思相信大家都能明白,那么解题思路又是怎么样的呢我来大概说一下,先找到兔子增长_中大oj
文章浏览阅读1.5k次,点赞40次,收藏34次。【代码】C程序设计第五版谭浩强 || 第四章习题答案
文章浏览阅读161次。CPO-CNN-LSTM分类预测,【24新算法】冠豪猪算法CPO优化卷积神经网络-长短期记忆网络多特征分类预测
文章浏览阅读1.4k次。这样,就可以在CentOS系统中使用普通用户身份来管理和启动Nginx服务了。请注意,对于其他需要管理员权限才能完成的操作(如修改系统文件等),还需要使用sudo命令或者切换到管理员账户进行操作。下载并安装Nginx,保证Nginx可执行文件所在的路径对普通用户具有可读、可执行的权限。安装过程中,在指定 Nginx 配置文件路径时要特别注意,确保可访问并正确填写。启动Nginx服务。是您实际安装Nginx时配置文件存放的路径。_nginx用什么用户启动
文章浏览阅读6.8k次。问题描述:无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[http://java.sun.com/jsp/jstl/core]在调用<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>时出现异常调用tomcat服务器时,页面出错:原因分析:首先确认导入的jar包是否正确经过多次导包还是老样子,在网上也找了挺多方法,但都不凑效解决方案:方案一:重新导入jar包如果是jar包缺失_无法在web.xml或使用此应用程序部署的jar文件中解析绝对uri:[h
文章浏览阅读1.9k次,点赞41次,收藏32次。通过上篇文章《MySQL的体系结构与SQL的执行流程》了解了SQL语句的执行流程以及MySQL体系结构中**「连接器」「SQL接口」「解析器」「优化器」「执行器」**的功能以及在整个流程中的作用。不过上篇文章留了个尾巴,在执行器调用存储引擎后,存储引擎内部做了什么事没有进一步说明,本文会对此展开介绍,使得我们对SQL整体的执行流程有更加清晰的认识。先了解下存储引擎是干什么的。
文章浏览阅读93次。超简单灌木教程~零基础神马的都能神还原哦!优动漫PAINT下载:http://wm.makeding.com/iclk/?zoneid=18597想要Get到更多有关优动漫的信息包括软件下载,可关注优动漫PAINT中文官网哦!转载于:https://www.cnblogs.com/danzi/p/8527177.html..._优动漫边缘上色
文章浏览阅读716次,点赞24次,收藏27次。Channel与BufferJava NIO系统的核心通道(Channel)和缓冲区(Buffer)。通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理简而言之,通道负责传输,缓冲区负责存储常见的Channel有以下四种,其中FileChannel主要用于文件传输,其余三种用于网络通信Buffer有以下几种,其中使用较多的是ByteBufferByteBuffer。
文章浏览阅读2.1k次,点赞3次,收藏5次。VS 设置 C# 以下划线 _ 开头命名全局字段设置方法之前在某位大神的博客有看到这个设置方法,换电脑以后再找那个文章却找不到了,按回忆找到了设置方法,故写出来分享给大家。private readonly SearchResult _searchResult;设置方法以2019企业版为例,找到:工具 - 选项 - 文本编辑器 - C# - 代码样式 - 命名点击“管理命名样式”,然后再点左下角加号,新建一个命名规范,标题可以自己拟定,设置“必填前缀”为“_”,选择“camel 事例名称”,确_visual studio 命名规则以_开头给
文章浏览阅读184次。在开始设计测试用例前,需要了解项目产品需求,只有对需求深入了解后,才能进一步进行测试用例设计。(1)水杯有很多,有瓷水杯,纸杯,保温杯,不绣钢杯等,水杯具体需求是哪种杯子?下面以测试【纸杯】为例。(2)水杯具有的特性要求: 杯子的容量:要求最大能装多少升水(满杯),空杯,半杯杯子的型状:圆型,上面口大,下面小。 杯子的材料:纸杯 ..._面试测试用例设计
文章浏览阅读1.6k次。只适用mysql5.0以上的版本: 1.一个汉字占多少长度与编码有关: UTF-8:一个汉字=3个字节 GBK:一个汉字=2个字节2.varchar(n)表示n个字符,无论汉字和英文,Mysql都能存入n个字符,仅是实际字节长度有所区别3.MySQL检查长度,可用SQL语言: select LENGTH(fieldname) f_mysql mutipolygen 字符大小