建父pom项目,主要用来控制依赖版本
父项目的pom文件中的 pom
为pom,
其次,pom文件中的dependencyManagement标签,使用dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
其次,dependencyManagement中依赖并没有导入,只是申明了版本号,真正的导入需要在子项目中
2.做项目的步骤
(1):建model
(2) : 改pom
(3) : 写yml
(4) : 主启动
(5) : 业务类
3.注意事项
1.实体类需要继承Serializable(序列化接口)
2.在mapper的xml文件中,插入方法需要多写两个参keyProperty=“id” useGeneratedKeys=“true”
分别是这两个,第一个代表主键名字,第二个表示返回的值
具体作用
3.Lombok注解失效的问题
在写子项目时,因为注解失效一直报错,但是导入的
@Data注解却没有问题,因为Lombok需要依赖和插件配合使用,我去查看了Lombok插件是ok的,
最后发现是版本兼容问题,Lombok插件在0.27版本之后需要使用1.18.8以上的Lombok依赖,
我自己的现在是0.32版本,使用1.18.8也没有用,最后去找了最新版本1.18.20,注解才生效
4.在写mapper的xml文件时,在写具体的方法时,当返回值是一个类的时候,最好使用使用resultMap,避免当字段复杂时,字段不匹配的情况,如图
<resultMap id="payment" type="com.atguigu.springcloud.entities.payment">
<id column="id" property="id" />
<result column="serial" property="serial" jdbcType="VARCHAR"/>
resultMap>
4.错误
1.在设置端口号时
将server写成了service导致设置的端口号失效了,而且port写成了post
正确写法
server:
port: 8001
2.在设置mybatis的mapper文件位置时
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities
正确的应该是上面的,我错误的把classpath的c大写了,导致mybatis找不到mapper文件
项目重构
因为在每个微服务中可能都需要使用到某个实体类或者工具类,为了使代码不重复,我们将重复的的地方提取出来,建成一个内部项目,放到maven上,需要的项目就直接导入就好了,例如
其他项目需要使用时,直接导入依赖即可
<dependency>
<groupId>org.examplegroupId>
<artifactId>cloud-api-commonsartifactId>
<version>1.0-SNAPSHOTversion>
<scope>compilescope>
dependency>
注册中心
首先对注册中心的个人理解:
因为spring cloud有许多微服务的提供比如(支付模块,订单模块)。
服务注册中心的作用就是提供服务的信息的访问地址,客户端就可以通过服务注册中心去调用需要的服务。
注册中心是服务发现的核心。它保存了各个可用服务实例的网络地址(IP Address和Port)。服务注册中心必须要有高可用性和实时更新功能
1. eureka注册中心
在2018年停更,但是要了解他的原理。
微服务通过eureka服务端进行注册,客户端将需要的服务通过服务端找到对应服务的网络地址。
eureka集群:
假若这个eureka服务端发生故障,就会导致整个系统发生问题,所以我们需要做eureka集群,即存在多个eureka服务端,相互注册,这样其中一个发生问题,不会导致整个系统发生问题。
负载均衡
负载均衡,就是将负载,均衡的分布,不能让客户端全部访问同一个服务的同一个机器,因为相同的微服务可能有10个,在10台机器上运行,但是eureka可以将整个这个服务看成一个整体,当客户端访问时,可以轮询将客户端的访问分布到每一个机器,这样不会导致某一台负载过大,(通俗的说,就是比如有1w个人在拼夕夕买东西,同时拼夕夕的支付模块同时有100个微服务在同时运行,负载均衡就是将这1w个人的支付请求分布到这100个微服务上,避免这1w个人同时访问某一个微服务。
首先要使用eureka,首先需要导入依赖,在eureka 2.X版本之后,依赖相对于第一版有了区别在依赖名字上直接可以分别出来。
eureka服务端
(1):建model
(2): 导入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
(3):写yml
server:
port: 7003
eureka:
instance:
hostname: eureka7003.com
# hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
#集群指向其它eureka
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
#单机就是7001自己
# defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
#server:
#关闭自我保护机制,保证不可用服务被及时踢除
#enable-self-preservation: false
#eviction-interval-timer-in-ms: 2000
这里的eureka.instance.hostname=eureka7003.com
是eureka服务端的ip地址,微服务需要注册时通过IP加端口可以进行注册。
(4):主启动
在eureka服务端上主函数上要用@EnableEurekaServer进行注解
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class,args);
}
}
service-url:
defaultZone:
这里当需要做eureka集群时,每个eureka需要互相注册,即在后面加上需要注册的服务器URL,不需要做集群时就放自己的url就行了。
微服务端(服务端)
(1):建model
(2):改pom
需要导入以下依赖,与服务端不同是是,名字后面改成了eureka-client。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
(3):写yml
server:
port: 8000
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
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
# instance:
# instance-id: payment8001
# #访问路径可以显示IP地址
# prefer-ip-address: true
# #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
# #lease-renewal-interval-in-seconds: 1
# #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
# #lease-expiration-duration-in-seconds: 2
将自己注册进eureka服务端。
defaultZone:
http://eureka7001.com:7001/eureka,
http://eureka7002.com:7002/eureka,
http://eureka7003.com:7003/eureka
这里表示将自己注册到eureka集群中,即每个eureka服务端。
其中spring: application: name: cloud-order-service=cloud-order-service
的cloud-order-service表示自己注册在eureeka服务端的名字
(4): 主启动
微服务需要注册到eureka服务端的每个微服务启动类上需要有
@EnableEurekaClient注解
@SpringBootApplication
@EnableEurekaClient
public class orderMain80 {
public static void main(String[] args) {
SpringApplication.run(orderMain80.class,args);
}
}
使用负载均衡
项目结构图
项目中7001,7002,7003这里是eureka集群,
8001,8002都是支付模块微服务提供者,8000是客户端。
其中8000注册在eureka服务端的名字是cloud-order-service
8001和8002的名字为cloud-provider-service。
负载均衡即是将8000的访问分布到8001,8002两个支付模块上。
如图
在没有使用eureka时,8000是没有通过eureka直接使用RestTemplate与服务提供端进行连接的。
但是我们使用了eureka,这里我们将访问地址设置成微服务注册在eureka上的名字CLOUD-PROVIDER-SERVICE,然后在
@Configuration
public class webAppConfig implements WebMvcConfigurer {
@Bean
@LoadBalanced //通过LoadBalanced注解赋予了RestTemplate负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
配置类上,通过LoadBalanced注解赋予了RestTemplate负载均衡的能力,然后我们用客户端使用支付模块时,eureka会轮询的请求放到每个服务上。
eureka的自我保护机制
默认开启,即注册在eureka服务端的微服务, 微服务正常情况下每30s(默认)需要向服务端发送心跳包,表示自己还存在,保护机制即当微服务因为网络堵塞导致没有在30s内发送心跳包时,不会立即移除这个注册的微服务,
而是等待90s(默认)之后才移除,这样就保证了不会因为网络等其他原因移除了健康的服务。
在eureka服务端可以关闭,在yml的eureka:下面的client:下面加入
#server:
#关闭自我保护机制,保证不可用服务被及时踢除
#enable-self-preservation: false
#eviction-interval-timer-in-ms: 2000
可以关闭自我保护,这里将90s改为2s,即当2秒没有收到微服务端的心跳包就移除微服务,这里还需要设置一下微服务端发送心跳包的时间
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
# #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
这样就关闭了自我保护机制。
eureka前端显示问题
这里的payment8001与8002,本来是主机名的,通过yml文件的eureka下添加
instance:
instance-id: payment8002
# #访问路径可以显示IP地址
prefer-ip-address: true
首先安装zookeeper,我在云服务器上安装了zookeeper,安装步骤
安装完成后在bin下
./zkCli.sh 启动zookeeper
需要注意的是安装的zookeeper版本与导入依赖版本的兼容问题,这里我的zookeeper安装版本是3.7,依赖版本是3.0.5
微服务端
(1): 建model
(2): 改pom
zookeeper的依赖是这个
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
<version>3.0.5version>
dependency>
(3):写yml
server:
port: 8003
spring:
application:
name: cloud-provider-service
cloud:
zookeeper:
connect-string: xxx.x.xxx.xxx:2181
这里的绑定zookeeper打开的端口,我这里是公网ip加2181端口。
(4)主启动
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向注册中心注册服务(当注册中心使用zookeeper或者consul时)
public class paymentMain8003 {
public static void main(String[] args) {
SpringApplication.run(paymentMain8003.class,args);
}
}
这里的@EnableDiscoveryClient并不是cookeeper特有的,而是spring cloud用来向注册中心注册的。
消费端
(1):建model
(2):改pom
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
<version>3.0.5version>
dependency>
(3)写yml
server:
port: 8000
spring:
application:
name: cloud-consumer-order
cloud:
zookeeper:
connect-string: 121.5.199.228:2181
(4)主启动
@SpringBootApplication
@EnableDiscoveryClient
public class consumerOrderMain80 {
public static void main(String[] args) {
SpringApplication.run(consumerOrderMain80.class,args);
}
}
(5)业务类
配置类
这里需要在config类中在注入RestTemplate时,同样要加**@LoadBalanced** ,这个注解也是spring cloud提供的
@Configuration
public class webConfig implements WebMvcConfigurer {
@Bean
@LoadBalanced
public RestTemplate RestTemplate(){
return new RestTemplate();
}
}
conroller
@Autowired
private RestTemplate restTemplate;
public static final String INVOKE_URL="http://cloud-provider-service";
@GetMapping("/payment/getZK")
public String getdata(){
String xx=restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
return xx;
}
这里的url直接使用的是http://cloud-provider-service
其中cloud-provider-service是服务端在zookeeper注册的名字。
基本使用方法与zookeeper相似
1.去官网下载Linux版本或者windows版本安装
注意安装版本与导入依赖版本
pom
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
<version>3.0.0version>
dependency>
yml
server:
port: 8000
spring:
application:
name: cloud-consumer-order
cloud:
consul:
host: local
port: 8500
discovery:
service-name: ${spring.application.name}
依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-ribbonartifactId>
<version>1.3.5.RELEASEversion>
dependency>
作用是可以修改负载均衡的方式,例如有
随机,轮询等。
在消费者的主启动类上使用
@RibbonClient(value = "cloud-provider-service",configuration = MySelfRule.class)
注解,cloud-provider-service表示需要的服务名。后面的类可以在config上注入到spring boot中,可以在方法中修改负载均衡的匹配方式
@Bean
public IRule myRule(){
return new RandomRule(); //随机
}
详细项目在cloud-consumer-order80项目中,
配合使用7001,cloud-provider-payment8001和8001可以查看手写的轮询算法。
一般在客户端使用,消费者端
详细作用
具体查看 cloud-consumer-openFeign-order80项目,配合7001与基本的8001可以查看效果,相当于是一个接口插件。
使用时需要在主启动类上
@EnableFeignClients
注解启动openFeign,配合在并在接口上使用
@FeignClient("cloud-provider-service")
后面为需要的服务名。
日志增强功能:
logging:
level:
com.atguihu.springcloud.service.paymentOnService: debug #openFeign的日志增强功能
再在配置类中配置需要的等级
@Configuration
public class FeignConfig {
@Bean
public Logger.Level leiel(){
return Logger.Level.FULL;
}
}
超时控制功能:
因为openfeign的包包含Ribbon包,所以设置超时
控制即为
ribbon:
ReadTimeout: 5000 #链接超时时长 超过5秒就报超时
ConnectTimeout: 5000 #读取超时时长
# MaxAutoRetries: 0 #同一台服务实例重试次数,不包括首次调用
# MaxAutoRetriesNextServer: 1 #重试负载均衡其他的服务实例最大重试次数,不包括首次调用
# OkToRetryOnAllOperations: false # 是否所有操作都重试
超过时间就报错。
发生场景,因为微服务之间相互调用,如果其中一个微服务因为(运行问题,超时,宕机)会导致调用者用等待返回值,这样就容易发送雪崩式的服务崩溃。
Hystrix实现了断路器模式,当某个服务发生故障时,通过断路器的监控,给调用方返回一个错误响应,而不是长时间的等待,这样就不会使得调用方由于长时间得不到响应而占用线程,从而防止故障的蔓延。Hystrix具备服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。
Hystrix详细教程
下载安装: Github安装地址
启动:
windows
直接到bin目录下使用
Linux
暂时启动
startup.cmd -m standalone
yml
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
service: nacos-server
pom
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
官方中文文档
安装:点击此处
sentinel的默认端口是8080
pom
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
yml
server:
port: 8899
spring:
application:
name: cloud-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
service: cloud-sentinel-service
sentinel:
transport:
dashboard: localhost:8080
port: 8719
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelMain {
public static void main(String[] args) {
SpringApplication.run(SentinelMain.class,args);
}
}
通过ip加8080,进入sentinel,账户密码均是sentinel
当QPS每秒超过10个,sentinel直接返回友好提示
直接_Warm UP(预热)
预热,不会让请求从一个很小的数直接爆发到一个很大的数 ,通过 ,前5秒的阈值是按单机阈值除于3的数,如当前例子,前5秒的阈值为3,经过5秒之后,阈值变成10
直接_排队等待
接收所有QPS,让其一个一个来排队出来,如果新来的预计处理时间大于超时时间,则直接返回友好信息