55人参与 • 2024-08-06 • IDE
需求:当一个服务提供者 service 部署了多个实例交给 user 远程调用时:
注册中心作用:
构成:
eureka-server:服务端,注册中心
记录服务信息,心跳监控
eureka-client:客户端,
服务提供者(注册到服务端,定期向服务端发送心跳)、服务消费者(从服务端拉取服务列表,基于负载均衡选择服务)
作用:
服务注册: service实例启动后,会将自己的信息注册到 eureka服务端
服务拉取: user 根据 实例名 获取 service 地址列表
配置文件:
我们需要将 eureka 注册到spring容器中,所以需要在配置文件中做相关配置。
server:
port: 8099
spring:
application:
name: eureka_server
eureka:
client:
# 配置eureka服务地址
service-url:
defaultzone: http://127.0.0.1:8099/eureka
项目启动:
为了让项目能启动 eureka,需要在启动类上加一个注解:@enableeurekaserver
@springbootapplication
@enableeurekaserver
public class serverapplication {
public static void main(string[] args) {
springapplication.run(serverapplication.class, args);
}
}
启动项目,访问地址:http://127.0.0.1:8099:
注册的服务名称就是配置文件中的名称的大写。
服务注册
在上一步,已经将 eureka-server (eureka服务中心)搭建完毕,现在就开始注册服务实例了。
注意:
无论是 服务提供者 还是 服务消费者,他们的身份都是 eureka-client
记得添加 spring-boot-starter-web 的依赖,不然会报错:field optionalargs in org.springframework.cloud.netflix.eureka.eurekaclientautoconfiguration$refreshableeurekaclientconfiguration required a bean of type ‘com.netflix.discovery.abstractdiscoveryclientoptionalargs’ that could not be found.
服务发现、服务注册统一都封装在eureka-client依赖。
需要在配置文件中配置 eureka-server 的地址。
spring:
application:
name: service_provider
eureka:
client:
service-url:
defaultzone: http://127.0.0.1:8099/eureka
启动多个实例
为了让项目能启动 eureka,需要在启动类上加一个注解:@enableeurekaclient。
@springbootapplication
@enableeurekaclient
public class providerapplication {
public static void main(string[] args) {
springapplication.run(providerapplication.class, args);
}
}
我们可以通过 idea 自带功能模仿启动多个服务实例。
****
复制原来的 provider 启动配置
查看 eureka注册中心
服务发现
依赖导入
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-client</artifactid>
</dependency>
配置文件:
spring:
application:
name: service_user
server:
port: 8084
eureka:
client:
service-url:
defaultzone: http://127.0.0.1:8099/eureka
服务拉取和负载均衡
服务拉取:
修改 controller 代码,将 url 路径的 ip、端口 修改为 服务名:
@restcontroller
@requestmapping("user")
public class usercontroller {
@autowired
private resttemplate resttemplate;
@getmapping("/{id}")
public book getbookbyid(@pathvariable("id") integer id) {
// string url = "http://127.0.0.1:8081/provider" + id;
string url = "http://service_provider/provider";
if (id != null) {
url = url + id;
}
book book = resttemplate.getforobject(url, book.class);
return book;
}
}
注册 resttemplate 的时候加上注解 @loadbalanced
@loadbalanced
@bean
public resttemplate resttemplate() {
return new resttemplate();
}
接口调用:
@restcontroller
@requestmapping("user")
public class usercontroller {
@autowired
private resttemplate resttemplate;
@getmapping("/{id}")
public book getbookbyid(@pathvariable("id") integer id) {
// string url = "http://127.0.0.1:8081/provider" + id;
string url = "http://provider/pro/";
if (id != null) {
url = url + id;
}
book book = resttemplate.getforobject(url, book.class);
return book;
}
}
访问接口:
访问报错:
解决方案:
多测试几下接口,可以发现,user一会儿调用的是 provider:8081 一会儿调用的是 provider:8082。这就是负载均衡算法选择的。
eureka-server 搭建:
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-server</artifactid>
</dependency>
server:
port: 8099
spring:
application:
name: server
eureka:
client:
# 配置eureka服务地址
service-url:
defaultzone: http://127.0.0.1:8099/eureka
服务注册:
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-client</artifactid>
</dependency>
server:
port: 8081
spring:
application:
name: provider
eureka:
client:
# 配置eureka服务地址
service-url:
defaultzone: http://127.0.0.1:8099/eureka
服务发现:
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-eureka-client</artifactid>
</dependency>
server:
port: 8089
spring:
application:
name: user
eureka:
client:
# 配置eureka服务地址
service-url:
defaultzone: http://127.0.0.1:8099/eureka
ribbon负载均衡流程图:
http://provider/pro/4 并非真实的地址,这个需要ribbon负载均衡去拦截,然后选择具体的服务地址。而,ribbon就是通过 loadbalancerinterceptor 的 intercept 方法来实现拦截请求并解析选择地址。
public clienthttpresponse intercept(final httprequest request, final byte[] body, final clienthttprequestexecution execution) throws ioexception {
uri originaluri = request.geturi();
string servicename = originaluri.gethost();
assert.state(servicename != null, "request uri does not contain a valid hostname: " + originaluri);
return (clienthttpresponse)this.loadbalancer.execute(servicename, this.requestfactory.createrequest(request, body, execution));
}
负载均衡流程:
ribbon的负载均衡策略是由 irule 接口来定义的。
自定义负载均衡策略:
@bean
public irule randomrule(){
return new randomrule();
}
provider: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
nfloadbalancerruleclassname: com.netflix.loadbalancer.randomrule # 负载均衡规则
注意:
方式一的作用范围是:在访问任何微服务的时候,都是使用 randomrule 负载均衡策略;
方式二的作用范围是:在访问 provider 微服务的时候才是采用 randomrule 策略,其他的还是使用默认策略。
加载策略:
ribbon默认采用懒加载,即会在第一次访问时才会去创建 loadbalanceclient ,所以会在第一次请求的时候花上较长的等待时间。
可以通过配置文件更改加载策略为饿加载策略,即初始化时就创建 loadbalanceclient ,降低第一次访问的耗时。
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: provider # 指定饥饿加载的服务名称
概念:
服务注册中心
作用:
心跳检查: 不同于 eureka 只能 service实例 主动发起心跳,nacos 对于非临时实例可以主动发起心跳检查
临时心跳检查异常的会被剔除出 服务地址列表
引入依赖、修改配置
父工程添加 springcloudalibaba 的管理依赖。
<!--spring-cloud-alibaba-->
<dependency>
<groupid>com.alibaba.cloud</groupid>
<artifactid>spring-cloud-alibaba-dependencies</artifactid>
<version>2.2.6.release</version>
<type>pom</type>
<scope>import</scope>
</dependency>
子工程中注释掉 eureka 依赖,引入 nacos 依赖。
<dependency>
<groupid>com.alibaba.cloud</groupid>
<artifactid>spring-cloud-starter-alibaba-nacos-discovery</artifactid>
</dependency>
配置文件配置nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
启动 user 和 provider :
注意: eureka 注册名会变成大写,nacos 不会,所以改成 nacos 之后,需要把访问地址改成小写。
请求测试:
服务分级存储模型
一个服务可以拥有多个实例,如:provider 的 8081 和 8082,如果这些实例分布于全国不同的机房,如:provider:8081 在成都机房、provider:8082 在重庆机房,nacos就将同一机房内的实例 划分为一个集群。
即,一个服务可以拥有多个集群,一个集群中可以拥有多个实例。
微服务相互之间访问时,访问本地的速度更快,所以应该尽可能访问相同集群的实例,只有当本集群内存不够时,才去访问其他集群。
配置服务集群:
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
discovery:
cluster-name: cd
vm options:
-dserver.port=8082 -dspring.cloud.nacos.discovery.cluster-name=cq
2. 同集群优先的负载均衡
默认的 zoneavoidancerule 负载均衡策略并不能实现据同集群优先来实现负载均衡,因此nacos中提供了一个nacosrule
的实现,可以优先从同集群中挑选实例。
修改负载均衡策略:
@bean
public irule nacosrule(){
return new nacosrule();
}
provider: # 访问的服务名
ribbon:
nfloadbalancerruleclassname: com.alibaba.cloud.nacos.ribbon.nacosrule # 负载均衡规则
3. 权重配置
服务器的性能之间存在差异,为了让性能能好的服务器承担更多的用户请求,nacos提供了权重配置来控制访问率:权重越大、访问率越高。
注意: 权重为0的服务永远不会被访问。
4. 环境隔离
nacos提供了namespace来实现环境隔离功能。
nacos默认的namespace是:public
命名空间
nacos创建命名空间流程:
spring:
cloud:
nacos:
discovery:
namespace: e11eb3bc-8eed-4cdd-93f0-7a6c01b85eb4 # 命名空间,填id
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置为永久实例
3. 配置管理
nacos不仅可以担任微服务的注册中心,还可以担任配置管理。
统一配置管理
可以使用统一配置管理来处理因为部署的微服务数量过多,配置繁杂等问题。
nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新。
注意: 只把那些需要热更新的配置文件交给nacos
data id: 配置文件id:服务名称-profile.后缀名 。
spring引入了一种新的配置文件:bootstrap.yaml文件,会在application.yml之前被读取,流程如下:
引入nacos-config依赖:
<!--nacos配置管理依赖-->
<dependency>
<groupid>com.alibaba.cloud</groupid>
<artifactid>spring-cloud-starter-alibaba-nacos-config</artifactid>
</dependency>
添加bootstrap.yml
spring:
application:
name: user # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
config:
file-extension: yaml # 文件后缀名
这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
s
p
r
i
n
g
.
a
p
p
l
i
c
a
t
i
o
n
.
n
a
m
e
−
{spring.application.name}-
spring.application.name−{spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id,来读取配置。
读取nacos配置
@value("${pattern.dateformat}")
private string dateformat;
@getmapping("now")
public string now() {
return localdatetime.now().format(datetimeformatter.ofpattern(dateformat));
}
启动报错: org.springframework.beans.factory.beancreationexception: error creating bean with name xxx
解决方案:
检查 namespace,配置文件与服务要在同一个 namespace 中
名称是否拼错
升级 nacos 版本
@value 切换为 @nacosvalue
配置热更新
配置热更新: 修改nacos中的配置后,微服务中无需重启即可让配置生效。
实现方式:
方式一: 在@value注入的变量所在类上添加注解 @refreshscope
方式二:
使用 @configurationproperties 注解代替@value注解
在 user 服务中,添加一个类,读取patterrn.dateformat属性:
@component
@data
@configurationproperties(prefix = "pattern")
public class patternproperties {
private string dateformat;
}
在usercontroller中使用这个类代替@value:
@autowired
private patternproperties patternproperties;
@getmapping("now")
public string now() {
return localdatetime.now().format(datetimeformatter.ofpattern(patternproperties.getdateformat));
}
配置共享
其实微服务启动时,会去nacos读取多个配置文件,因为nacos管理的配置文件不包含环境信息,可以被多个环境共享。
只需要取名的时候,不加上 profile 就能被共享,如下:
配置共享时的优先级:
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论