目录
1 SpringCloudAlibaba介绍
2 服务注册与发现中心
2.1 注册中心的原理
2.2 服务拆分
2.3 服务间调用
2.3.1 RestTemplate调用远程服务
2.3.2 通过Nginx维护服务列表
2.3.3 通过Nacos实现注册中心
2.4 总结
3 Netflix Eureka注册和发现中心
3.1 创建父工程
3.2 搭建Eureka服务注册中心
3.3 创建子项目和接口开发
3.4 服务注册与发现
3.4.1 服务注册
3.4.2 服务发现
3.5 测试
3.6 总结
4 Ribbon的负载均衡
4.1 负载均衡原理
4.2 负载均衡策略配置
4.3 懒加载和饥饿加载
4.4 总结
5 Nacos服务管理平台
5.1 Nacos介绍和安装
5.1.1 Nacos介绍
5.1.2 Nacos安装
5.1.3 Nacos启动
5.2 Nacos快速入门
5.2.1 服务注册
5.2.2 服务发现
5.2.3 测试
5.3 总结
码字不易,喜欢就点个关注❤,持续更新技术内容。相关资料请私信。
相关内容:
第二篇:SpringCloudAlibaba入门与实践-CSDN博客
目前,Spring Cloud Alibaba 包含如下组件:
开源部分
Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
Dubbo:Apache Dubbo 是一款高性能 Java RPC 框架,用于实现服务通信。
Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
平台服务部分
Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
注册与发现中心是以"服务"为中心构建现代应用架构的基础服务设施,能够更快速、简便地构建、管理和交付微服务平台。相当于微服务架构中的通讯中心,每个微服务提供者会将服务地址、端口等注册到注册中心,服务消费者再通过注册中心查找服务地址,然后进行调用。
特点 | 说明 |
---|---|
服务的自动注册 | 微服务应用在启动时,通过注册中心客户端组件,将服务的相关信息自动注册给注册中心服务端。 |
服务的自动发现 | 服务消费者需要能实时监听到注册中心中服务信息的变更,以能在真正调用服务时不会出现错误。 |
服务的健康检查 | 当注册到注册中心的微服务实例宕机后,注册中心服务端发现实例已经宕机,并把相关信息从注册中心删除掉。 |
常见注册中心组件:Netflix Eureka、Alibaba Nacos、谷歌Consul、雅虎ZooKeeper。管理所有微服务、解决微服务之间调用关系错综复杂难以维护的问题。
注册中心分为服务端与客户端,服务端主要功能是记录服务信息和心跳监控,也就是为客户端提供配置服务和健康检查。客户端与微服务嵌套在一起,微服务相对地可以分为服务提供者和服务消费者,可以用多语言实现。提供者通过客户端将自己信息注册到注册中心,每隔几秒带上了服务名、服务ip、服务端口等信息向注册中心服务端发送心跳请求。消费者根据调用地微服务名称从注册中心拉取多个服务实例列表,基于此服务列表做负载均衡,挑选一个微服务发起远程调用。
同时注册中心也会通过http/tcp向微服务客户端主动发起健康检查。如果15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例。
微服务相互独立开发,不需要重复开发相同的业务。
微服务数据独立,不要访问其他微服务的数据库。
微服务可以将自己的业务暴露为接口供其他为微服务调用。
RestTemplate是Spring封装的HTTP接口调用模板类,可以通过restTemplate发起的http请求调用微服务接口地址(微服务的ip、端口、接口路径的请求参数),但微服务接口地址是硬编码的方式写死的。如果一个微服务创建多个实例,形成微服务集群,怎么处理多个实例的调用。还有如果微服务接口名、参数或者请求方式更改了,那么也得同步修改restTemplate的调用。所以通过调用写死的服务地调用是很麻烦的。
解决这个问题就需要负载均衡机制,如在中间加一个Nginx,为该服务分配一个二级域名,通过二级域名代理到不同的服务机器上,这样的问题是如当一个大型网站有大量的访问时,上百个服务系统都要启动很多机器,当访问量少时又要减机器,那么就涉及到大量的Nginx配置文件要修改。已经淘汰了。
通过SpringBoot在每个微服务上自动装配Nacos客户端,因为在Nacos中默认集成了Ribbon的支持,只需要在服务启动类注入的RestTemplate方法上添加Ribbon的@LoadBalanced注解,赋予restTemplate能够解析微服务的能力。这样在控制器方法中通过restTemplate调用的微服务接口地址就不用写死,只需将机器的地址改为服务名称作为服务域名,就能自动对该微服务地多个实例实现负载均衡。
如定义了一个分布式架构的远程服务接口调用,当向该服务接口地址发送请求时,在底层会被Ribbon中的LoadBalancerInterceptor拦截器拦截,然后进行服务接口地址的域名解析为注册中心服务的地址,拉取服务下所有的机器地址列表,然后在每次对该服务接口调用时在客户端通过Ribbon基于缓存的服务实例列表实现负载均衡。
通过以上分析就可以回答以下两个问题了:
每次都要到注册中心拉取信息吗?注册中心宕机了怎么办?
拉取微服务的信息对应的机器宕机了怎么办?
总结,Nacos注册中心会自动对每个微服务下启动的机器的IP和端口进行注册维护,当A服务要访问B服务的功能接口时,通过RestTemplate请求B服务下功能接口的服务域名和端口,会由Ribbon解析域名地址,然后根据Ribbon自动间断地向注册中心拉取的机器服务接口地址,当然还有Nacos主动推送注册维护的机器,最后Ribbon在客户端本地实现负载均衡。
Eureka停更后,比较新的技术都不支持了,一般都将Eureka换成了Nacos,不再推荐使用。不过我们可以通过学习Eureka来了解注册中心的功能。不过还在维护。
首先创建一个空百的Maven项目父工程springcloud-demo,因为父工程是用来统一管理依赖的,不需要写逻辑业务,所以可以把src目录删除,留下一个pom.xml文件就行。(注意自己Maven的配置,详细可以看http://t.csdn.cn/TSAgL)
在父工程pom文件引入相关依赖坐标。
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
只要子项目的pom文件中写了某依赖项,不指定具体版本,子项目会从父项目中继承该依赖,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
接下来就可以在父工程之下创建一个Maven子项目来搭建Eureka,与其他服务模块不同的是,pom文件中引入的是spring-cloud-starter-netflix-eureka-server的依赖坐标,通过SpringBoot在Eureka服务上自动装配Eureka服务端:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.1.2.RELEASE
编写启动类,添加@EnableEurekaServer注解:
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
添加application.yml文件,配置以下信息,包括项目的服务端口和服务名称以及Eureka的配置,引入Eureka服务端依赖之后就可以配置Eureka服务端的地址信息了,因为Eureka也需要将自己注册到注册中心:
server:
port: 10100 # 服务端口
spring:
application:
name: eurekaserver #服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://localhost:10100/eureka/
接着创建订单和用户子项目模块:
以订单服务项目为例,在java源文件下创建订单相关的目录,以及启动类。
首先在在pojo中创建用户类和订单类。注意属性名要与数据库表中的字段对应。我就是因为订单类中定义定义的user_id属性"i"大写了,而数据库是小写的,所以开始在mapper层返回的order对象user_id就为null了,最后在使用restTemplate远程调用,根据user_id查询用户接口的地方就报错了,所以一直摸不着头。可以看到注释掉远程调用后user_Id为null。
在mapper中定义OrderMapper,然后定义一个通过id查询订单的方法。
@Mapper
public interface OrderMapper {
@Select("select * from tb_order where id = #{id}")
Order findById(Long id);
}
然后在service中调用注入OrderMapper使用查询方法返回订单对象。然后进行业务处理,返回订单列表。远程调用可以先不看,看完服务注册和服务发现后再回来梳理。我们通过restTemplate发起的http请求远程调用userservice微服务用户查询的接口地址。最后返回完整的订单列表。
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
// 2.1.url路径
String url = "http://userservice/user/" + order.getUser_id();
// 2.2.发送http请求,实现远程调用
User user = restTemplate.getForObject(url, User.class);
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
}
最后在web中创建订单控制器OrderController,定义查询订单的接口。接收前端发送的请求和传递的订单id,调用业务层方法进行处理。
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
return orderService.queryOrderById(orderId);
}
}
用户服务的用户查询接口开发与订单查询一样,只是订单查询多了用户查询接口的远程调用(多表联查)。
和Eureka服务一样,订单服务和用户服务也需要引入Eureka的依赖,只不过订单和用户服务引入的是Eureka的客户端eureka-client。之前说过,只要父工程引入了依赖信息,子项目引入相关依赖时可以不指定坐标版本,自动从父工程中继承依赖。如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
同样的,引入依赖之后要进行配置,和Eureka服务一样需要配置项目启动端口、服务名称以及配置Eureka的注册中心地址,这样就能把该服务注册到Eureka中。
server:
port: 8081 #客户端端口
spring:
application:
name: orderservice # 配置服务名称和eureka地址,方便注册
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://localhost:10100/eureka/ # 配置服务名称和eureka地址,方便注册
最后先启动Eureka服务,然后启动订单和用户服务,在Eureka提供的页面可以看到已经将三个服务实例注册到了Eureka注册中心:
这样服务注册就完成了。
启动多个实例进行注册,右键需要需要模拟多实例部署的服务:
修改Name,为了避免端口冲突,需要修改端口设置:
最后可以看到复制出来的服务实例。
服务发现其实就服务拉取,服务拉取是基于服务名称获取服务实例列表,然后再对服务列表做负载均衡。
1.首先在在服务启动类注入的RestTemplate方法上添加Ribbon的负载均衡注解@LoadBalanced,赋予restTemplate能够解析微服务和实现复杂均衡的能力。
@Bean
// ribbon的负载均衡注解
@LoadBalanced
// 当通过restTemplate调用微服务接口地址时,在底层会被LoadBalancerInterceptor拦截器拦截,
// 拦截后通过执行RibbonLoadBalancerClient的execute方法对服务名称进行解析,在execute中调用getLoadBalancer方法得到DynamicServerListBalancer动态服务列表均衡器对象,该对象在注册中心拉取到对应的服务实例地址列表。然后再在execute中调用getServer找IRule接口基于规则挑出某个服务实例地址返回给RibbonLoadBalancerClient,execute将服务返回。将服务名称替换为地址最终成功发送请求。
public RestTemplate restTemplate() {
return new RestTemplate();
}
2.然后修改OrderService代码,修改url路径,用服务名代替ip、端口:(这部分就是OrderService中远程调用业务)
// url
String url = "http://userservice/user/" + order.getUserId();
// 利用RestTemplate发起http请求实现远程调用,查询用户。
User user = restTemplate.getForObject(url, User.class);
启动全部微服务,可以看到注册中心的服务列表,其中userservice服务启动了两个实例,分别在8080端口和8082端口:
测试请求用户服务中查询用户的接口:
测试请求订单服务中查询订单的接口:
这样基于Eureka注册中心的微服务基础搭建就完成了。
搭建EurekaServer
引入eureka-server依赖。
添加@EnableEurekaServer注解。
在application.yml中配置eureka地址。
搭建业务服务模块
创建服务项目
开发服务接口
服务注册
引入eureka-client依赖
在application.yml中配置eureka地址
服务发现
引入eureka-client依赖
在application.yml中配置eureka地址
给RestTemplate添加@LoadBalanced注解
用服务提供者的服务名称作为远程调用的域名
当然,因为Eureka集成了Ribbon,现在只是基于Spring的RestTemplate远程调用和Ribbon的域名解析,简单使用了一下Eureka的服务注册和服务发现的功能。后续还有Ribbon的负载均衡等等内容。
通过restTemplate调用微服务接口地址时,在底层会被LoadBalancerInterceptor拦截器拦截,拦截后通过执行RibbonLoadBalancerClient的execute方法对服务名称进行解析。
在execute中调用getLoadBalancer方法得到DynamicServerListBalancer动态服务列表均衡器对象,该对象在注册中心拉取到对应的服务实例地址列表。然后再在execute中调用getServer找IRule接口基于规则挑出某个服务实例地址返回给RibbonLoadBalancerClient,execute将服务返回。将服务名称替换为地址最终成功发送请求。
整个过程就是解析服务域名和实现负载均衡。
Ribbon内置策略 | 规则说明 |
---|---|
RoundRobinRule | 简单轮询服务列表来选择服务器。是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 按照规则忽略服务器 |
WeightedResponseTimeRule | 为每一个服务器赋予权重值。服务器响应时间越长,权重越小。这个规则会随机选择服务器,权重会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个个机房。而后对Zone内的多个服务器进行轮询。 |
BestAvailableRule | 忽视一些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑。 |
通过定义IRule实现可以修改负载均衡规则,两种方式:
1.代码方式:在服务启动类中定义一个新的Rule:
@Bean
public IRule randomRule(){
return new RandomRule();
}
2.配置文件方式:在服务配置文件中,添加新的配置也可以修改规则,如下是对userservice服务访问的负载均衡规则:
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
两种方式的区别:
在进行远程调用的服务的启动类中定义,面对的是所有服务访问使用的负载均衡规则。
而在服务配置文件中进行单一服务的配置,当然对应的也是单个的服务使用的负载均衡规则。
Ribbon对服务列表实现负载均衡访问时,默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会比较长。而采用饥饿加载则会在项目启动时创建,降低第一次访问的耗时。
第一次访问时,如下分别是懒加载和饥饿加载所用的时间:
第一次加载后再次访问:
通过下面配置开启饥饿加载:
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients:
-userservice # 指定userservice这个服务饥饿加载
-xxxservice
Ribbon负载均衡规则
规则接口是IRule
默认实现是ZoneAvoidanceRule,根据zone选择服务列表,然后轮询。
负载均衡自定义方式
代码方式:配置灵活,但修改时需要重新打包发布
配置方式:直观,方便,无需重新打包发布,但是无法做到全局配置。
饥饿加载
开启饥饿加载
指定饥饿加载的服务名称
首先我们先来看一下SpringCloud通用模块中的两个接口,一个是服务发现和服务注册的接口,无论是Eureka还是Nacos的注册和发现,都是基于这两个接口实现的。当我们要替换注册和发现中心时只需要引入新的依赖,配置新的服务注册地址,SpringBoot会进行自动装配,服务提供者和服务消费代码不需要修改。
官方:一个更易于创建云原生应用的动态服务发现(Nacos Discovery)、服务配置(Nacos Config)和服务管理平台。一句话nacos就是集注册中心、配置中心和服务管理平台的组件。
Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度最高。
Nacos的关键特性包括:
流量控制和服务退化降级
服务注册和发现
分布式配置
事件驱动
消息总线
分布式事务
Dubbo RPC
这里只展示Windows系统的安装过程。
搜索Nacos官方网站,进入Nacos的Github仓库,在右侧点击进入。
在下面有很多的版本标签,点击进入。
然后选择nacos服务进行下载。
如下是nacos解压后的目录结构:
进入bin目录,如果直接双击startup.cmd执行文件,nacos默认是集群启动方式。
可以通过指令修改为单机启动模式:
startup.cmd -m standalone
可以看到nacos服务已经在8848端口运行了:
从SpringCloudAlibaba官网复制spring-cloud-alibaba的依赖坐标,然后在cloud-demo父工程中添加:
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.5.RELEASE
pom
import
1.注释掉eureka客户端依赖,添加nacos的客户端依赖坐标:
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.修改微服务中的配置文件,在spring下添加nacos服务端口,注释掉eureka地址。
spring:
cloud:
nacos:
server-addr: 127.0.0.1:8848 # nacos服务地址
#eureka:
# client:
# service-url: # eureka的地址信息
# defaultZone: http://localhost:10100/eureka/ # 配置服务名称和eureka地址,方便注册
注意注释掉服务中原有的eureka依赖。
因为Nacos也集成了Ribbon,所以同样会进行域名解析然后拉取服务列表,并实现负载均衡。
首先启动Nacos服务:
打开nacos提供的页面,账号和密码默认都是nacos,提交后进入nacos控制台页面:
打开服务列表,暂时还没有服务注册到nacos:
我们之前已经配置在每个服务配置好了nacos注册中心的地址,现在启动服务,刷新nacos控制页面。可以看到nacos注册中心的服务列表,其中userservice服务启动了两个服务实例,分别在8080端口和8082端口:
访订单服务的订单查询接口,同时远程调用用户服务的查询接口,成功返回结果:
Nacos服务搭建
下载安装包
解压
在bin目录下运行指令:
startup.cmd -m standalone
Nacos服务注册和发现
在父工程引入SpringCloudAlibaba依赖
在所有子工程的服务中引入nacos-discovery客户端依赖
在所有服务中配置nacos服务地址,spring.cloud.nacos.server.addr