这是一篇关于Spring Cloud微服务架构的学习
将所有的代码及功能都包含在一个WAR包中的项目组织方式被称为Monolith(单体应用)
特点:
①编译难,部署难,测试难
②技术选择难
③扩展难
在中小型项目的情况下使用单体应用比较简单比如:
crm 物流 库存管理等
单体应用中多个模块的负载不均衡,我们扩容高负载的时候,也把低负载的模块也扩容,极大浪费了资源.
把一个单体项目,拆分为多个微服务,每个微服务可以独立技术选型,独立开发,独立部署,独立运维.并且多个服务相互协调,相互配合,最终完成用户的价值就是微服务
特点:
①复杂度可控
②每个微服务也可以独立部署
③技术选型灵活
④微服务架构下,故障会被隔离在单个服务中
⑤每个服务可以根据实际需求独立进行扩展
一般大型项目(功能比较多) 商城 erp等使用微服务比较多
首先Spring cloud是一个基于Spring Boot实现的服务治理工具包,在微服务架构中用于管理和协调服务的。并且是一系列框架的有序集合
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon/Feign
服务网关——Netflix Zuul
断路器——Netflix Hystrix
分布式配置——Spring Cloud Config
Spring Cloud共集成了19个子项目,里面都包含一个或者多个第三方的组件或者框架!
Spring Cloud 工具框架如下:
1、Spring Cloud Config 配置中心,利用git集中管理程序的配置。
2、Spring Cloud Netflix 集成众多Netflix的开源软件
3、Spring Cloud Bus 消息总线,利用分布式消息将服务和服务实例连接在一起,用于在一个集群中传播状态的变化
4、Spring Cloud for Cloud Foundry 利用Pivotal Cloudfoundry集成你的应用程序
5、Spring Cloud Cloud Foundry Service Broker 为建立管理云托管服务的服务代理提供了一个起点。
6、Spring Cloud Cluster 基于Zookeeper, Redis, Hazelcast, Consul实现的领导选举和平民状态模式的抽象和实现。
7、Spring Cloud Consul 基于Hashicorp Consul实现的服务发现和配置管理。
8、Spring Cloud Security 在Zuul代理中为OAuth2 rest客户端和认证头转发提供负载均衡
9、Spring Cloud Sleuth SpringCloud应用的分布式追踪系统,和Zipkin,HTrace,ELK兼容。
10、Spring Cloud Data Flow 一个云本地程序和操作模型,组成数据微服务在一个结构化的平台上。
11、Spring Cloud Stream 基于Redis,Rabbit,Kafka实现的消息微服务,简单声明模型用以在Spring Cloud应用中收发消息。
12、Spring Cloud Stream App Starters 基于Spring Boot为外部系统提供spring的集成
13、Spring Cloud Task 短生命周期的微服务,为SpringBooot应用简单声明添加功能和非功能特性。
14、Spring Cloud Task App Starters
15、Spring Cloud Zookeeper 服务发现和配置管理基于Apache Zookeeper。
16、Spring Cloud for Amazon Web Services 快速和亚马逊网络服务集成。
17、Spring Cloud Connectors 便于PaaS应用在各种平台上连接到后端像数据库和消息经纪服务。
18、Spring Cloud Starters (项目已经终止并且在Angel.SR2后的版本和其他项目合并)
19、Spring Cloud CLI 插件用Groovy快速的创建Spring Cloud组件应用。
如果只有一个注册中心服务器,会存在单点故障所以要集群。
3.2.1首先创建一个多模块项目
需要引入其依赖的是:
UTF-8
UTF-8
1.8
Finchley.SR1
2.0.5.RELEASE
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-dependencies
${springboot.version}
pom
import
3.2.2创建一个注册中心子模块
①pom.xml的依赖如下:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
②APP入口
@SpringBootApplication //程序入口
@EnableEurekaServer //注册中心需要对服务的支持
public class EurekaApp2 {
public static void main(String[] args) {
SpringApplication.run(EurekaApp2.class);
}
}
③配置application.yml
server:
port: 7002
eureka:
instance:
hostname: eureka-7002.com
client:
registerWithEureka: false #是否要注册到eureka
fetchRegistry: false #表示是否从Eureka Server获取注册信息
serviceUrl:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
defaultZone: http://eureka-7001.com:7001/eureka/ #集群配置,如果有多个,有逗号分割,不要包含自己
3.3.1第一步引入依赖
cn.itsource
common_interface
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
3.3.2 APP入口的代码
@SpringBootApplication
@EnableEurekaClient
public class ProviderApp2 {
public static void main(String[] args) {
SpringApplication.run(ProviderApp2.class);
}
}
3.3.3 application.yml配置
注意:
defaultZone配置了服务提供方代码可以配置到多个注册中心;完成集群操作
server:
port: 8002
spring:
application:
name: USER-PROVIDER #不要使用下划线
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true #显示客户端真实ip
3.3.4 controller层展示数据
@RestController
@RequestMapping("/provider")
public class ProviderController {
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
return new User(id,"熊瞎子8002");
}
}
3.4.1首先引入pom.xml
cn.itsource
common_interface
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-openfeign
3.4.2 APP入口的代码
@SpringBootApplication
@EnableFeignClients(basePackages = "cn.itsource.springcloud.consumer")
public class ConsumerApp2 {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp2.class);
}
}
3.4.3 接口的代码(实现可跳转到服务提供者的服务)
//此处value的值就是我们在服务提供者中的配置的name
@FeignClient(value = "USER-PROVIDER")
@RequestMapping("/provider")
public interface UserInterface {
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);
}
3.4.4 Controller层的跳转路径的代码
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserInterface userInterface;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
return userInterface.getUser(id);
}
}
注意:
(需要注意在入口APP中的注册中心注解@EnableEurekaService
而提供者和消费者都是@EnableEurekaClient)
3.5上诉的操作使用了集群和负载均衡,集群很简单下面我们说一下负载均衡
为了提供并发量,有时同一个服务提供者可以部署多个。这个客户端在调用时要根据一定的负责均衡策略完成负载调用。
SpringCloud中常见负载均衡实现技术有两个
一个是Ribbon还要一个是Feign
4.2.1 什么是Ribbon
Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。
4.2.2 单服务提供者操作
①依赖的pom.xml
cn.itsource
common_interface
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-ribbon
org.springframework.cloud
spring-cloud-starter-config
②定义一个获取bean的类来开启负载均衡
@Configuration
public class CfgBean {
@Bean
//这里代表开启负载均衡
@LoadBalanced
public RestTemplate getTemplate(){
return new RestTemplate();
}
//修改负载均衡的策略用随机策略代替轮训
@Bean
public IRule getRule(){
return new RandomRule();
}
}
③controller层的代码
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
private RestTemplate restTemplate;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
String url = "http://USER-PROVIDER/provider/user/"+id;
return restTemplate.getForObject(url, User.class);
}
}
④入口APP和application.yml都是我们上面搭建的Feign负载均衡类似
4.3.1 Feign的认识
是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。
其最大的特点是:
Feign是以接口方式进行调用,而不是通过RestTemplate来调用,feign底层还是ribbo,它进行了封装,让我们调用起来更加happy.
4.3.2其中的操作见上面我们的搭建的项目即使用的Feign负载均衡哦
*在理想状态下,一个应用依赖的服务都是健康可用的,我们可以正常的处理所有的请求。
但当某一个服务出现延迟时,所有的请求都阻塞在依赖的服务A
当依赖A阻塞时,大多数服务器的线程池就出现阻塞(BLOCK),影响整个线上服务的稳定性
所以呢?就会出现雪崩现象*
而Hystrix就是处理依赖隔离的框架,同时也是可以帮我们做依赖服务的治理和监控
一句话简单解释:
Hystrix是保证微服务群健壮框架,做了隔离,熔断,降级等操作.
最终达到不会由于某一个服务出问题而导致雪崩现象,让整体群死掉
资源隔离(限流):
包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。
融断:
当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。
降级机制:
超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。
缓存:
提供了请求缓存、请求合并实现。
①正常情况下,断路器处于关闭状态(Closed),
②如果调用持续出错或者超时,电路被打开进入熔断状态(Open),后续一段时间内的所有调用都会被拒绝(Fail Fast),
③一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试,
如果调用仍然失败,则回到熔断状态
④ 如果调用成功,则回到电路闭合状态;
有了熔断,就得有降级。
所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。
这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。
5.5.1 引入pom.xml的依赖
cn.itsource
common_interface
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
5.5.2 APP入口
@SpringBootApplication //开启springboot的入口
@EnableEurekaClient //服务器提供者需要开启springcloud的客户端
@EnableHystrix //开启熔断操作
public class ProviderApp3 {
public static void main(String[] args) {
SpringApplication.run(ProviderApp3.class);
}
}
5.5.3 application.yml的配置
server:
port: 8003
spring:
application:
name: USER-PROVIDER #不要使用下划线
eureka:
client:
service-url:
#defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
defaultZone: http://eureka-7001.com:7001/eureka,http://eureka-7002.com:7002/eureka
instance:
prefer-ip-address: true #显示客户端真实ip
5.5.4 controller层代码
@RestController
@RequestMapping("/provider")
public class ProviderController {
@RequestMapping("/user/{id}")
@HystrixCommand(fallbackMethod = "failGet")
public User getUser(@PathVariable("id") Long id){
if(id==1){
throw new RuntimeException("运行时错误");
}
return new User(id,"熊瞎子8002");
}
//此类就是用来返回拖地数据的
public User failGet(Long id){
return new User(id,"恭喜您中奖1分人民币");
}
}
5.6.1 pom.xml的代码
cn.itsource
common_interface
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-openfeign
5.6.2其中yml的配置
server:
port: 9003
eureka:
client:
registerWithEureka: false #不注册到Eureka,不在注册中心显示
service-url:
defaultZone: http://localhost:7001/eureka
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 3000
readTimeout: 3000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
5.6.3 入口APP
@SpringBootApplication
@EnableFeignClients(basePackages = "cn.itsource.springcloud.consumer")
public class ConsumerApp3 {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp3.class);
}
}
5.6.4 接口的代码
//value中的值是提供者yml配置中的name,fallback值当前接口的实现类
@FeignClient(value = "USER-PROVIDER",fallback = UserClientFall.class)
//规则类上面不能写RequestMapping不能识别
public interface UserInterface {
@RequestMapping("/provider/user/{id}")
public User getUser(@PathVariable("id") Long id);
}
5.6.5 其接口的实现类
@Component
public class UserClientFall implements UserInterface {
@Override
public User getUser(Long id) {
return new User(id,"好像你中了1元人民币");
}
}
5.6.6 然后就是Controlle层的代码
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserInterface userInterface;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
return userInterface.getUser(id);
}
}
第一天结束
Zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。
Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门,也要注册入Eureka.
通常一个业务系统会有很多的微服务.,为了让调用更简单,一般会在这些服务前端再封装一层,这一层俗称为“网关层”,其存在意义在于,将"1对N"问题 转换成了"1对1”问题(路由),同时在请求到达真正的微服务之前,可以做一些预处理(过滤),比如:来源合法性检测,权限校验,反爬虫之类…
让我们调用更加简单,有一个统一访问的接口
6.3.1引入的依赖
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-zuul
6.3.2 application.yml配置代码
server:
port: 9527
spring:
application:
name: microservice-zull
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
zuul:
routes:
user-provider: /user/** #以/user开头的所有路径都转发给user-provider进行处理
ignored-services: "*" #忽略掉服务名访问方式 使用上面/user的方式来访问
prefix: "/services" #添加 前缀访问 localhost:9527/services/user/provider/user/2
6.3.3 入口APP配置
@SpringBootApplication
@EnableZuulProxy
public class ZuulApp {
public static void main(String[] args) {
SpringApplication.run(ZuulApp .class);
}
}
然后直接输入其路径http://localhost:9527/services/user/provider/user/1
进行访问即可
微服务架构中,每个项目都有一个yml配置,管理起来麻烦。要使用spring cloud config来统一管理。
在分布式系统中,由于服务很多,为了方便配置文件的统一管理,所以我们需要配置中心组件。
它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。
一般我们操作和githup集成使用
①首先我们需要在githup创建一个配置文件
②然后我们进行依赖的配置
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-config-server
③对applicatrion.yml的配置
server:
port: 6666
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
prefer-ip-address: true
spring:
application:
name: spring-cloud-config-server
cloud:
config:
server:
git:
uri: https://github.com/hpyao/microservice-config.git
username: hpyao
password: Itsource20180731
④入口APP启动类
@SpringBootApplication
@EnableEurekaClient //加入注册中心
@EnableConfigServer //启用配置服务端
public class ConfigServerApplication_6666{
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication_6666.class);
}
}
现在 git 里面的配置弄到 configserver里面 ,我们客户端直接可以从configserver里面去取配置
①pom.xml的依赖配置
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-config
②配置bootstrap.yml
cloud:
config:
name: application-user #github上面名称
profile: test #环境
label: master #分支
uri: http://localhost:6666 #配置服务器
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿 #单机环境
instance:
prefer-ip-address: true #显示客户端真实ip
然后在整个项目中需要一个config-server 所有的其他项目都对应一个config-client,无论是provider consumer eureka等 这样就会从github拉取下来
跨了多个数据库事务管理,在微服务架构每个服务都有自己数据库,在微服务架构中必然要用到分布式事务.
微服务应用相较于单体应用有以下不足:
1)单体应用拆分为分布式系统后,进程间的通讯机制和故障处理措施变的更加复杂。
随着RPC框架的成熟,第一个问题已经逐渐得到解决。例如dubbo可以支持多种通讯协议,springcloud可以非常好的支持restful调用
2)系统微服务化后,一个看似简单的功能,内部可能需要调用多个服务并操作多个数据库实现,服务调用的分布式事务问题变的非常突出。
对于第二个问题,现在还没有通用方案很好的解决微服务产生的事务问题。分布式事务已经成为微服务落地最大的阻碍,也是最具挑战性的一个技术难题。
3)微服务数量众多,其测试、部署、监控等都变的更加困难。
对于第三个问题,随着docker、devops技术的发展以及各公有云paas平台自动化运维工具的推出,微服务的测试、部署与运维会变得越来越容易。
两阶段提交(Two Phase Commit, 2PC), 具有强一致性, 是CP系统的一种典型实现.常见的标准是XA, JTA等.
第一阶段是表决阶段,所有参与者都将本事务能否成功的信息反馈发给协调者;第二阶段是执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地在所有分支上提交或者回滚
缺点:
两阶段提交中的第二阶段, 协调者需要等待所有参与者发出yes请求, 或者一个参与者发出no请求后, 才能执行提交或者中断操作. 这会造成长时间同时锁住多个资源, 造成性能瓶颈, 如果参与者有一个耗时长的操作, 性能损耗会更明显.
实现复杂, 不利于系统的扩展, 不推荐.
介绍:
“LCN并不生产事务,LCN只是本地事务的协调者”
LCN分布式事务框架的核心功能是对本地事务的协调控制,框架本身并不创建事务,只是对本地事务做协调控制。因此该框架与其他第三方的框架兼容性强,支持所有的关系型数据库事务,支持多数据源,支持与第三方数据库框架一块使用(例如 sharding-jdbc),在使用框架的时候只需要添加分布式事务的注解即可,对业务的侵入性低。LCN框架主要是为微服务框架提供分布式事务的支持,在微服务框架上做了进一步的事务机制优化,在一些负载场景上LCN事务机制要比本地事务机制的性能更好,4.0以后框架开方了插件机制可以让更多的第三方框架支持进来。
特点:
支持各种基于spring的db框架
兼容SpringCloud、Dubbo、motan
使用简单,低依赖,代码完全开源
基于切面的强一致性事务框架
高可用,模块可以依赖RPC模块做集群化,TxManager也可以做集群化
支持本地事务和分布式事务共存
支持事务补偿机制,增加事务补偿决策提醒
添加插件拓展机制
下载地址:
https://github.com/codingapi/txlcn-demo
https://www.txlcn.org/zh-cn/docs/demo/env.html官网学习地址
(2)把下载好的txlcn-demo-master项目导入idea
(3)启动txManager
导入数据库 tx-manager
导入数据库 txlcn-demo
查看本地redis 是否有密码 把redis密码在配置文件注释
启动redis服务
在导入的idea里面启动 txlcn-demo-tm
登录
http://localhost:7970/admin/index.html
密码:codingapi
(4)idea安装 lombok插件
(5)启动
启动eureka注册中心
启动的时候注意 配置mysql的数据库的密码
txlcn-demo-spring-service-a
txlcn-demo-spring-service-b
txlcn-demo-spring-service-c
(6)测试
输入地址访问:
http://localhost:12011/txlcn?value=test
正常会在数据库插入3条数据
手动在 txlcn-demo-spring-service-a 里面的DemoServiceImpl设置异常 进行测试
异常就会回滚数据