更新中,关注不断更…
如果觉得需要补充哪些内容,可以在评论区留言或者私信我哦
文章目录
- 🌟引入
- 🎶Feign
- 😺Ribbon
- 🐎Naocs
- 🍨Gateway
- 🍬Docker
- 🚢RabbitMQ
- sentinel
- seata
🌟引入
这里讲的是基于springboot和springboot alibaba的微服务,Spring Boot和Spring Boot Alibaba都是基于Spring框架的开源框架,用于简化应用程序的开发和部署。
这篇文章里会介绍微服务的整体概念,目前国内常用的组件,以及国内使用非常广泛的Snowy框架。
首先说一下微服务的概念,相信很多小伙伴已经对单体架构和SOA架构有所了解,当然如果没有了解过也不用着急,这里大致讲一下:
单体架构:将系统所有功能,包括前端界面、后端服务全部在同一个工程上开发,最终将所有模块、所有功能打包在一起放在一个进程上运行。
SOA架构:粗颗粒度的、松耦合的、面向服务的架构,在架构中使用一个标准 的通信协议,通过网络提供应用程序的业务功能服务,且所有服务都是完全独立部署和维护的,并且可以组合使用。
SpringCloud是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud
SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验。
所以刚入手SpringCloud的家人们可以简单理解成一个SpringCloud项目是把一个整体的SpringBoot项目拆成很多小的SpringBoot项目并且集成上优秀组件。
本文中会介绍feign,ribbon,nacos,gateway,rabbitMQ,redis,Sentinel,Seata,以及docker部署工具。
下面这个是一个典型的微服务架构,整个项目拆分成四个模块。
这里说一下微服务架构的几个原则:
- 不同微服务,不要重复开发相同业务
- 微服务数据相互独立,不要访问其他服务的数据库
- 微服务可以将自己的业务暴露为接口,供其他的微服务调用
看到上面的图,有些小伙伴就会想到一个问题,不同的微服务会部署到不同的服务器上,这样就会涉及到一个远程调用的问题,那么这里就开始介绍SpringCloud的第一个组件——feign。
🎶Feign
Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign
其作用就是帮助我们优雅的实现http请求的发送,解决远程调用的问题。
远程调用简称RPC(Remote Procedure Call),简单来说就是调用方和被调用方不在同一个机器上,可以对比着“本地过程调用”理解这一概念。
这里我们先看一下官方文档:
这段话总结一下就是Feign是以添加注释的形式使用的。
Feign的具体使用方法如下:
- 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 添加注解
在启动类上加上 @EnableFeignClients 注解
@EnableFeignClients
@SpringBootApplication
public class OrderApplication{
public static void main(String[] args){
SpringApplication.run(OrderApplication.class,args);
}
}
- 编写Feign客户端
import org.springframework.cloud.openfeign.Feignclient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.Pathvariable;
//指定绑定服务为userservice
@FeignClient("userservice")
public interface UserClient{
@GetMappring("/user/{id}")
User findById(@PathVariable("id") Long id);
}
这个客户端主要是基于SpringMVC的注解来声明远程调用的信息
- 测试
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId){
//1.查询订单(假设这里已经定义好了order实体类)
Order order = orderMapper.findById(orderId);
//2.利用Feign发起http请求,查询用户
User user = userClient.findById(order.getUserId());
//3.封装user到order
order.SetUser(user);
//4.返回
return order;
}
要是有用过RestTemplate的小伙伴就会发现Feign要整洁很多,可读性也更高。
Feign还可以支持很多的自定义配置,如下表所示:
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign.Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign.Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。
基于配置文件修改feign的日志级别可以针对单个服务:
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
也可以针对所有服务:
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
NONE:不输出日志信息。
BASIC:仅输出请求方法、URL、响应状态码和执行时间四个基本信息。
HEADERS:输出BASIC级别的信息,并且输出请求和响应的头信息。
FULL:输出完整的请求和响应的详细信息,包括请求和响应的正文。
基于Java代码来修改日志级别:先声明一个类,然后声明一个Logger.Level的对象:
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
如果是局部生效,则把它放到对应的@FeignClient这个注解中:
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)
我们在使用中还会遇到Feign性能优化的问题,这里主要使用的就是用连接池替换Feign默认的URLConnection。
使用连接池可以有效地提高Feign的性能和可靠性。连接池可以缓存已经建立的HTTP连接,避免每次发送HTTP请求都需要建立新的连接,从而提高请求的响应速度。同时,连接池还可以限制并发连接的数量,防止由于并发连接数过高而导致的服务器负载过高的问题。
完成改操作需要引入依赖并在在yaml文件中加入如下配置:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>11.5</version>
</dependency>
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
当然具体的配置都是按照项目的需求来的。
Feign的性能优化还有超时设置,重试机制,这里就不详细介绍了,感兴趣的小伙伴可以去自己了解。
😺Ribbon
接下来介绍的是Ribbon,这是SpringCloud底层使用的实现负载均衡的组件。
关于负载均衡这个概念很多小伙伴都已经在学习网络的时候了解了,这里就只放一张图去描述,Ribbon就是实现了蓝色的功能。
Ribbon使用起来很方便,首先加入依赖:
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<version>2.2.2</version>
</dependency>
第二步是在启动类加上 @LoadBalance 注解
@LoadBalanced
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
也会在创建RestTemplate并注入Spring容器时用到:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
下面说一下修改负载均衡的方法:
负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类:
修改负载均衡规则有两种方式:
- 代码方式:在Application类中,定义一个新的IRule:
@Bean
public IRule randomRule(){
return new RandomRule();
}
- 配置文件方式:在application.yml文件中,添加新的配置也可以修改规则:
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
说一下Ribbon加载的问题:
Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长,而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
ribbon:
eager-load:
enabled: true
clients: userservice
🐎Naocs
说完了Ribbon就该讲Nacos了,Nacos是一个注册中心组件,同样是注册中心组件的还有Eureka,但现在国内更推崇Alibaba的Nacos,所以这里就仅介绍Nacos。
Nacos可以在本机上安装,官网链接在这里:https://nacos.io/zh-cn/docs/quick-start.html ,安装好的效果如下:
我现在在本机上跑的是小诺开源项目,这是服务已经注册到我的Nacos上的效果。
如果是自己的新项目要使用的时候,先找到你nacos的安装目录,点开bin目录,在命令行运行这行命令:
.\startup.cmd -m standalone
保证你的nacos正常运行,这时候对你们项目进行下面的操作:
- 引入依赖
<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地址
在你需要的服务的application.yml文件中添加nacos地址:
spring:
cloud:
nacos:
server-addr: localhost:8848
- 重启
重启微服务后,登录nacos管理页面,可以看到微服务信息啦
有的小伙伴可能不知道去哪看,这个时候你可以试试在浏览器输入localhost:8848,
或者直接点运行起来的项目中的蓝色的8848
你改了端口号的话就输入自己的nacos服务用到的端口号就行
下面是一些nacos的其他配置:
- 配置集群
修改application.yml文件,添加集群配置:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ # 集群名称
重启后,我们就可以在nacos控制台看到类似下面的结果:
如果要实现同集群优先,可以将所需服务的yml文件进行如下修改:
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
我们在实际部署的时候还会遇到配置权重的问题,这个需要在nacos控制台中找到服务列表,点击详情进行编辑:
权重从1到0,权重越小被访问几率越小,如果权重修改为0,则该实例永远不会被访问。
Nacos中还有一个命名空间的可选配置,不同namespace之间相互隔离,不同namespace的服务互相不可见。
如果要修改命名空间,则加上自己的命名空间的ID:
spring:
cloud:
nacos:
server-addr: localhost:8848
discovery:
cluster-name: HZ
namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID
如果要新建命名空间则直接点击即可,ID为了防止重复,用自动生成的比较好
🍨Gateway
Gateway(网关)是微服务架构中的守门神,为所有微服务提供统一的入口。它充当了客户端请求与服务端应用之间的门户,将请求通过定义的路由和断言进行转发,路由表示需要转发请求的地址,断言则代表请求这些地址时所需满足的条件。只有同时符合路由和断言,Gateway才会转发请求。
网关有三个大的功能:
-
权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截。
-
路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发到某个微服务,这个过程叫做路由。当然路由的目标服务有多个时,还需要做负载均衡。
-
限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。
网关常用的有gateway和zuul,zuul是阻塞式的,性能远远不如gateway,我们这里就只对gateway进行介绍。
阻塞式(Blocking)通常用来描述一种同步的操作方式。当一个线程或进程执行一个阻塞式的操作时,它会一直等待,直到操作完成并且返回结果。在此期间,线程或进程会被挂起,无法执行其他任务。
下面说一下怎么在项目中使用gateway
- 引入依赖
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
- 编写启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
- 编写基础配置和路由规则
创建application.yml文件,内容包括服务基本信息、nacos地址、路由:
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
gateway:
routes: # 网关路由配置
- id: user-service # 路由id,自定义,只要唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
将符合Path
规则的一切请求,都代理到 uri
参数指定的地址。
这里将 /user/**
开头的请求,代理到lb://userservice
,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。
上面yml中的路由配置包括两个很重要的配置——断言和过滤器,这里只列出种类,需要使用的话可以去深入了解
断言工厂:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
过滤器工厂:
名称 | 说明 |
---|---|
AddRequestHeader | 给当前请求添加一个请求头 |
RemoveRequestHeader | 移除请求中的一个请求头 |
AddResponseHeader | 给响应结果中添加一个响应头 |
RemoveResponseHeader | 从响应结果中移除有一个响应头 |
RequestRateLimiter | 限制请求的流量 |
这里举一个小栗子🌰:
如果需要给所有进入userservice的请求添加一个请求头:Truth=give an example
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=give an example # 添加请求头
这个时候因为当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。
如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=give an example
有的时候可能会遇到跨域问题,解决方法如下:
在yml文件进行按照下面进行修改:
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
只允许8090端口发5种请求访问10010端口。
🍬Docker
Docker是一款流行的开源容器化平台,可以帮助开发人员和系统管理员更轻松地打包、发布和运行应用程序。Docker的主要目标是提供一种轻量级的、可移植的容器化解决方案,使应用程序可以在任何环境中运行,而不需要担心底层操作系统或基础设施的变化。
Docker基于容器技术,允许用户将应用程序及其所有依赖项打包成一个独立的容器,从而简化了应用程序的部署和管理。Docker容器可以在任何支持Docker的操作系统上运行,包括Linux、Windows和macOS等。
简单来说,Docker解决了操作系统环境差异,依赖版本差异的问题。
要是看到这里还不懂的可以去网站看一下这篇:https://www.runoob.com/docker/docker-tutorial.html?source=1
说一下怎么使用docker,在使用之前,要准备的是一个CentOS7的云服务器或者虚拟机,还没有的小伙伴建议先暂停一下,准备好环境再来学习。
- 安装docker
如果是之前有下过的话这里有删除命令:
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine \
docker-ce
下载docker需要yum工具,这里先安装:
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2 --skip-broken
更新本地镜像:
# 设置docker镜像源
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
然后输入命令:
yum install -y docker-ce
docker-ce为社区免费版本。稍等片刻,docker即可安装成功。
商业版docker-ee有需要的小伙伴可以安装
- 启动docker
这里网上有说要直接关防火墙的,但我不太建议,需要哪个端口的时候开放指定端口即可
通过命令启动docker:
systemctl start docker # 启动docker服务
systemctl stop docker # 停止docker服务
systemctl restart docker # 重启docker服务
然后输入命令,可以查看docker版本:
docker -v
这里写一个使用docker创建nginx容器的栗子:
我们这里会用到,用下面的命令把8080端口上的进程杀掉
下一步是安装镜像
docker pull nginx
需要安装什么镜像可以自己去dockerhub上去找
当然,如果你觉得服务器的网速太慢,你也可以选择用本机传输的方式,这里就不详细讲了
下面这个就是创建的命令:
docker run --name myn -d -p 8080:80 nginx
解释一下每个参数是什么意思:
- “–name” => 容器名称
容器名称一定一定不要随便起一个,不然到时候你自己都不知道这个容器是做什么的
- “-d” => 以后台模式进行运行
- “-p” => 指定映射端口,我这里是让新建的docker容器上的80端口映射到服务器上的8080端口
- 最后是这个容器上需要什么服务,因为这里演示我们创建的是nginx,所以直接写nginx就好
创建完成之后,你在浏览器输入 你服务器的ip + :端口号 就可以进行访问
加点拓展知识,如果你点开这个想看到的不是这个页面该怎么办呢
这个就需要找到存nginx的html页面的文件夹
cd /usr/share/nginx/html
这里可以看到index.html这个文件,将这个文件用本机编译器打开
选择系统关联,然后打开进行编辑就可以了
docker还有一些高级应用我会专门写一篇文章,写完了链接会放到这里,现在先带过了
🚢RabbitMQ
RabbitMQ是一款开源的消息代理软件,实现了高级消息队列协议(AMQP)标准。它提供了一个消息系统,允许应用程序通过发送和接收消息来相互通信。RabbitMQ充当中间人,从生产者接收消息并将其发送给消费者。
下面的内容等更新…
sentinel
下面的内容等更新…
seata
下面的内容等更新…