springcloud微服务架构搭建过程
创始人
2025-05-28 23:40:58
0

项目地址:源代码

仅作为学习用例使用,是我开发过程中的总结、实际的一部分使用方式
开发环境:
jdk11
springboot2.7.6
springcloud2021.0.5
alibabacloud 2021.0.4.0
redis6.0
mysql8.0

一、项目搭建

1. 创建

wdz-api:存放远程服务调用相关接口
wdz-auth:认证业务
wdz-gateway:网关
wdz-modules:业务模块微服务
wdz-common:存放公用中间件、数据库等服务

pom


4.0.0pomwdz-commonwdz-gatewaywdz-apiwdz-authwdz-modulescom.wdzwdz-ruzhou1.0.0wdz-ruzhou微服务架构11UTF-8UTF-82.7.62021.0.52021.0.4.02.0.141.18.24org.springframework.cloudspring-cloud-dependencies${spring-cloud.version}pomimportorg.springframework.bootspring-boot-dependencies${spring-boot.version}pomimportcom.alibaba.cloudspring-cloud-alibaba-dependencies${spring-cloud.alibaba}pomimportorg.projectlomboklombok${lombok.version}com.alibaba.fastjson2fastjson2${fastjson2.version}devdevnacosnacos127.0.0.1:88485efed786-91f6-44c4-8e14-049df72b2a485efed786-91f6-44c4-8e14-049df72b2a48truetesttestnacosnacos127.0.0.1:8848f02ccd30-e3d5-4235-9282-d0a613bd322bf02ccd30-e3d5-4235-9282-d0a613bd322bprodprodnacosnacos127.0.0.1:8848747829ca-6d8a-4417-a46a-bd31a6f5e442747829ca-6d8a-4417-a46a-bd31a6f5e442org.springframework.bootspring-boot-maven-plugin3.0.0org.apache.maven.pluginsmaven-compiler-plugin${java.version}${java.version}${project.build.sourceEncoding}src/main/resourcesapplication*bootstrap*logback*true

nacos(2.2.0.1)

我为什么选择nacos作为注册中心?
1、独立的可视化管理后台
2、持久化,配置数据直接存储在数据库中
3、动态配置,修改配置可实时生效,不用重启
4、活跃度高,资料文件丰富
5、功能全面
6、是经过阿里巴巴考验的
戳==>官网

安装nacos

点击选择版本下载
windows建议下载zip
linux 建议下载tar.gz
下载完成解压即可

配置数据库

打开conf下的application.properties文件:
修改数据库配置,将注释打开,并配置数据源
在这里插入图片描述

创建数据库目前只支持mysql,版本要求:5.6.5+

需要IPV6支持使用:derby-schema.sql 否则使用:mysql-schema.sql 配置完成后

单机启动nacos:

Linux/Unix/Mac使用命令:sh startup.sh -m standalone
windows使用命令:./startup.cmd -m standalone
standalone:表示单机模式运行,非集群模式
官方文档
启动过程中如果出现jwt认证问题启动失败,请参考:戳详情

错误示例
在这里插入图片描述
修改文件:

nacos.core.auth.plugin.nacos.token.secret.key
使用base64 处理数据长度大于等于32即可

在这里插入图片描述
在这里插入图片描述

访问:http://localhost:8848/nacos,默认用户名密码:nacos

集群启动 官方文档

如果是在一台电脑上/服务器上模拟集群:
将nacos解压之后的文件nacos复制多份,
在这里插入图片描述

并修改对应conf文件夹下的application.properties文件端口配置
在这里插入图片描述
再将conf下的cluster.conf.example 复制一份并修改后缀为conf
在这里插入图片描述
将其他nacos地址配置在cluster.conf中
在这里插入图片描述
依次启动服务:
windows命令:./startup.cmd
linux命令: sh ./startup.sh
访问对应nacos
在这里插入图片描述
在这里插入图片描述

nacos 服务配置config与发现 discovery

创建测试注册服务网关服务,nacos作为注册中心有多种方式,本文用javaSDK的方式
在这里插入图片描述

pom文件

wdz-ruzhoucom.wdz1.0.04.0.0com.wdzwdz-gatewayjarorg.springframework.cloudspring-cloud-starter-gatewaycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-discoverycom.alibaba.cloudspring-cloud-starter-alibaba-nacos-configorg.springframework.bootspring-boot-maven-plugin
yml配置:
server:port: 8080servlet:context-path: /spring:application:name: wdz-gatewayprofiles:active: @profiles.active@
---
# 使用导入的方式读取所有需要的nacos中的配置文件
spring:config:import:- optional:nacos:application-common.yml- optional:nacos:${spring.application.name}.ymlcloud:nacos:username: @nacos.username@password: @nacos.password@server-addr: @nacos.server@# 服务发现discovery:namespace: @nacos.discovery.namespace@# 配置config:namespace: @nacos.config.namespace@

集群nacos负载配置:

通过nginx配置服务访问的nacos

upstream nacos-cluster{server 127.0.0.1:8247;server 127.0.0.1:8549;server 127.0.0.1:8848;
}
server{listen 801;server_name localhost;location /nacos{proxy_pass http://nacos-cluster;}
}
结果

在这里插入图片描述

在这里插入图片描述

负载均衡Ribbon
内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表选择服务器,它是Ribbon默认的负载均衡规则
AvailabilityFilteringRule忽略规则:1、链接3次失败,会标记为短路状态,将持续30秒,如果还是失败则持续短路,时间增长,2、并发数过高的服务链接,并发数达到上限则会被忽略
WeightedResponseTimeRule权重策略,每个服务器配置一个权重值,权重值越小,选择这个服务器的比重就会越小
ZoneAvooidanceRule以区域可用的服务器为基础进行服务器的选择,使用Zone对服务器进行分类,Zone相当于一个机房,一个区域,然后再对Zone内的多个服务做轮询
BestAvailableRule忽略哪些短路服务器,并选择并发数较低的服务器
RandomRule随机选择一个可用服务器
RetryRule重试机制的选择逻辑

自定义策略方式:

代码方式:作用的是所有服务
@Bean
public  IRule diyRule(){return new RandomRule();
}
yml方式:作用的是所配置的服务
servicename: # 服务名称如:userserviceribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule 

ribbon默认是懒加载,第一次访问的时候响应时间会比较长,初次加载之后响应就会变短。
开启ribbon饥饿加载有效提高第一次访问响应时间

ribbon:eager-load:enabled: true  # 开启饥饿加载clients: # 指定加载的服务名称- userservice- orderservice- systemservice- XXXservice
nacos服务分级存储模型

一级是服务:如:userservice、orderservice
二级是集群:配置了同一个discovery.cluster-name:
三级是实例:如杭州机房的某台部署了要访问的服务器
设置实例的集群属性:名称一样的在同一个集群内
spring.cloud.nacos.discovery.cluster-name:

NacosRule负载均衡策略:
1、优先选择同集群的服务
2、本地集群找不到提供者,才去其他集群找,并且会报警告
3、确定了可用实例列表后,再采用随机负载均衡挑选实例

NacosRule配置:

servicename: # 服务名称如:userserviceribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule 

环境隔离:namespace

spring:cloud:nacos:discovery:namespace: @nacos.discovery.namespace@ 
# 不同名称空间之间的服务不能互通,如user使用的prod order使用的dev,这两个服务不能互通

nacos特点

1、支持服务端主动监测提供者状态,临时实例采用心跳模式,非临时实例采用主动监测模式
2、林实施例心跳不正常会被剔除nacos的服务列表,非临时实例不会被剔除
3、服务列表变更消息推送模式,服务列表更新及时
4、nacos集群默认采用AP方式,集群中存在非临时实例时,采用CP模式
CAP:C(一致性),A(可用性),P(分区容错)原文
在这里插入图片描述

Feign 源码

feign是声明式的http客户端

使用方式

pom引入依赖
org.springframework.cloudspring-cloud-starter-openfeign

java代码
@FeignClient("applicationName")
public interface ApplicationName{@GetMapping("/get")Object queryById(Long id);
}

自定义feign配置

类型作用说明
feign.Logger.Level修改日志级别包含四种不同的级别:none、basic、headers、full
feign.codec.Decoder响应结果解析器http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder请求参数编码将请求参数编码,便于通过http请求发送
feign.Contract支持注解格式默认是SpringMvc的注解
feign.Retryer失败重试机制请求失败的重试机制,默认没有,会使用Ribbon的重试

none: 不记录日志
basic:只记录请求方法和URL以及响应状态代码和执行时间
headers:记录基本信息以及请求和响应标头
full:记录请求和响应的头部、主体和元数据

yml日志配置

feign:client:config:default: # DETAULT 是全局配置,如果换成application.name 则是指定服务有效loggerLevel: FULL
feign:client:config:userservice: # 针对userservice有效loggerLevel: FULL

代码方式:

public class FeignClientConfig{@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.BASIC;}
}
然后将该配置添加到:
全局配置方式启动类上
EnableFeignClients(defaultConfiguration=FeignClentConfig.class)
局部配置方式
@FeignClient(value="applicationname",configuration=FeignClientConfig)

feign性能优化

URLConnection:默认实现,不支持连接池
Apache HttpClient:支持链接池
OKHttp:支持连接池
因为http链接时要三次握手,断开时要4次挥手,导致的性能浪费
优化的性能主要包括:
1、使用连接池代替默认的URLConnection
2、日志级别,最好用basic或none,日志也会浪费性能

连接池配置:

引入依赖


io.github.openfeignfeign-httpclient

配置yml

feign:httpclient:enabled: true # 开启feign对httpClient的支持max-connections: 200 # 最大链接数  可根据测试结果最优配置max-connections-per-route: 50 # 每个路径最大链接数 可根据测试结果最优配置

实践:
在这里插入图片描述
system项目引用
EnableFeignClients.clients 指定feignClient接口,及默认配置
在这里插入图片描述

如果发现RemoteUserService 加载不到提示,spring-cloud-starter-loadbalancer依赖缺失
在api中添加依赖:负载均衡依赖

org.springframework.cloudspring-cloud-starter-loadbalancer

测试接口
在这里插入图片描述
目标服务接口
在这里插入图片描述

测试结果:
在这里插入图片描述

SpringAMQP

springboot封装的消息队列,使用的是rabbitmq

生产端

引入依赖

org.springframework.bootspring-boot-starter-amqp

配置

spring:rabbitmq:host: 127.0.0.1 # 主机port: 5672   # 端口virtual-host: /  # 虚拟主机username: rabbitmq # 用户名password: 123456  # 密码

消费端

引入依赖

org.springframework.bootspring-boot-starter-amqp

配置

spring:rabbitmq:host: 127.0.0.1 # 主机port: 5672   # 端口virtual-host: /  # 虚拟主机username: rabbitmq # 用户名password: 123456  # 密码

监听java代码:

@Component
public class RabbitMqListener {@RabbitListener(queues = "mq-user")public void listenerQueueMsg(String msg){System.out.println(msg);}
}

如果提示异常:队列不存在,且启动失败

添加配置:

@Configuration
public class RabbitMqConfig {@Beanpublic Queue initQueue(){return new Queue("mq-user");}
}

由于rabbitmq的消费预取机制,会导致处理能力弱的消费端处理速度变慢,所以限制预取信息条数

spring:rabbitmq:listener:simple:prefetch: 1 # 每次只能获取一条消息,处理完成之后才能获取下一个

监听端信息:

@Slf4j
@Component
public class RabbitMqListener {@RabbitListener(queues = "mq-user")public void listenerQueueMsg(String msg) {log.info("[listenerQueueMsg]=========:{}",msg);}@RabbitListener(queues = "mq-user")public void listenerQueueMsg2(String msg) {log.info("[listenerQueueMsg2]=========:{}",msg);}
}

消息发布/订阅

发布订阅模式允许将同一消息发送给多个消费者,实现方式是加入exchange(交换机):
fanout:广播
direct:路由
topic:话题
交换机只处理转发,会造成消息丢失

FanoutExchange 方式

发送消息用户服务:

@GetMapping("/send")public LoginUser send(String username) {String queueName = "demo.fanout";String message = username;rabbitTemplate.convertAndSend(queueName,"", message);return new LoginUser(1L, username, "123456");}@GetMapping("/to")public LoginUser to(String username) {String queueName = "demo.fanout";String message = username;rabbitTemplate.convertAndSend(queueName,"", message);return new LoginUser(1L, username, "123456");}

接收消息 system服务:

监听代码@RabbitListener(queues = "demo.fanout2")public void listenerFanoutMsg2(String msg) {log.info("[demo.fanout2]=========:{}", msg);}
@Configuration
public class FanoutExchangeConfig {/*** 一个消息多个消费者监* fanout 广播模式* 定义交换机*/@Beanpublic FanoutExchange fanoutExchange() {return new FanoutExchange("demo.fanout");}@Beanpublic Queue fanoutQueue() {return new Queue("demo.fanout");}/*** 绑定交换机与队列关系** @param fanoutExchange* @param fanoutQueue* @return*/@Beanpublic Binding fanoutBinding(FanoutExchange fanoutExchange,Queue fanoutQueue) {return BindingBuilder.bind(fanoutQueue).to(fanoutExchange);}
}

接收消息 order服务:

监听
@Slf4j
@Component
public class RabbitMqListener {@RabbitListener(queues = "demo.fanout")public void listenerFanoutMsg(String msg) {log.info("[demo.fanout]=========:{}", msg);}
}

fanout 配置

@Configuration
public class FanoutExchangeConfig {/*** 一个消息多个消费者监* fanout 广播模式* 定义交换机*/@Beanpublic FanoutExchange fanoutExchange() {return new FanoutExchange("demo.fanout");}@Beanpublic Queue fanoutQueue() {return new Queue("demo.fanout2");}/*** 绑定交换机与队列关系** @param fanoutExchange* @param fanoutQueue* @return*/@Beanpublic Binding fanoutBinding(FanoutExchange fanoutExchange,Queue fanoutQueue) {return BindingBuilder.bind(fanoutQueue).to(fanoutExchange);}
}

均可接收到消息

DirectExchange 方式

direct exchange 会将接收到的消息根据规则路由到指定的queue
每个queue都与exchange设置一个bindingkey
发布者发送消息时指定消息的RoutingKey
exchange将消息路由到BingingKey与消息RoutingKey一致的队列

order/system中的监听

// 注解方式处理监听信息
// bindings 代码实现的Binding
// @QueueBinding 绑定信息
// value = @Queue(name = "direct.queue")绑定消息队列
//  exchange = @Exchange(name = "demo.direct",type = ExchangeTypes.DIRECT)
// 绑定交换机,名称是demo.direct 类型是direct
// key 是direct模式的主要配置,可同时监听多个key
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue"),exchange = @Exchange(name = "demo.direct",type = ExchangeTypes.DIRECT),key = {"system","direct"}))public void listenerMessage(String msg) {log.info("[system.direct]=========:{}", msg);}

消息发送者:

/***@param exchange  交换机名称*@param message     消息内容*@param routingKey  direct 路由key*@return*/@GetMapping("/direct")public void direct(String exchange,String message,String routingKey) {rabbitTemplate.convertAndSend(exchange,routingKey, message);}

发送信息:
http://localhost/user/direct?exchange=demo.direct&message=发送的消息内容&routingKey=system

Topic 方式

topic方式与direct方式类似,只是key由精准匹配转换为模糊匹配

 // 监听@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue"),exchange = @Exchange(name = "topic-wdz",type = ExchangeTypes.TOPIC),key = "#.order"))public void listenerTopicMessage(String msg) {log.info("[listenerTopicMessage]=========:{}", msg);}

发送

@GetMapping("/direct")
public void direct(String exchange,String message,String routingKey) {rabbitTemplate.convertAndSend(exchange,routingKey, message);
}

优化

由于springamqp默认使用的是jdk默认的序列化(ObjectOutputStream)方式,性能问题有待提升。
更换为JSON方式序列化。

生产者/消费者引入依赖
  com.fasterxml.jackson.dataformatjackson-dataformats-binary2.13.4

初始化bean即可

@Bean
publicMessageConverter messageConverter(){return new Jackson2JsonMessageConverter();
}

相关内容

热门资讯

国资妙手回春,深交所撤回警告,... 随着深交所一纸批复的到来,曾经深陷退市危机的*ST围海终于迎来转机,自2025年12月23日起,该公...
MiniMax递表港交所:今年... 上海企业稀宇科技冲击港交所“大模型第一股”。12月21日,MiniMax(稀宇科技)首次刊发其聆讯后...
百余只货基收益率“破1”!基金... 资产荒背景下,货币基金收益率正加速下探,破“1”正成为普遍现象。最新数据显示,当前,全市场已有百余只...
麦当劳中国,又涨价了 订阅 快刀财经 ▲ 做您的私人商学院连年调价。作者 :林佳怡来源:南方新消费(ID: bestcho...
英伟达被批准入股英特尔 联手重... 中经记者 吴清 北京报道近日,美国联邦贸易委员会(FTC)正式批准英伟达对英特尔50亿美元的战略投资...
财经调查丨粉底印、油渍…你买的... (央视财经《财经调查》)不少消费者向总台《财经调查》反映,部分主打“大牌尾货”“孤品样衣”的直播间,...
财经调查丨有直播间二手童衣不洗... (央视财经《财经调查》)知情人称长春是东北地区旧衣分拣回收规模最大的集散地之一。总台《财经调查》记者...
实探茅台镇“第二传奇”无忧酒业... 茅台镇的酒企有很多,贵州茅台(600519.SH)是当之无愧的老大哥,这也使部分酒企在制定目标时,往...
双胞胎兄弟深夜求摸狗,背后的育... 最近,一个搞笑的视频在网上引发了热议:一位网友下楼遛狗,意外遇见了同栋楼的双胞胎兄弟。哥哥兴奋地成功...
中国稀土:适时推进内外部稀土资... 11月12日消息,中国稀土接受机构调研时表示,公司作为中国稀土集团的核心上市平台,将坚定不移落实高质...