微服务笔记

image-20230817163441180

微服务概念

微服务

微服务简单理解就是将功能模块的多个功能,拆分为多个小功能服务,具体拆分多细的颗粒度,取决于需求项目需要,在服务之间可以通过RPC或其它方式来相互交互。

分布式

分布式简单理解就是将服务分散部署在不同的服务器上,服务与服务之间的调用也是通过RPC或其它方式来交互

关系

微服务大部分通过分布式环境来部署的但是分布式部署的应用不一定是微服务架构的,比如集群部署,它是把相同应用复制到不同服务器上,但是逻辑功能上还是单体应用

微服务本质是一个分布式架构方案

  1. 拆分为更小的模块
  2. 对外暴露接口,实现服务治理,远程调用(注册中心:Eureka)
  3. 团队独立,数据库独立,部署独立
  4. 有很高容错,并有服务降级避免出现联结问题

image-20231015095135309

SpringCloud整合的技术栈

image-20231015095120174

springCloud版本兼容性

image-20231015095629330

不同服务之间相互调用

1.需要在配置类注入bean

image-20230418172041456

2.调用其方法,发送http请求调用其他微服务最后封装结果

image-20230418172212344

Eureka注册中心

image-20231015102840993

image-20231015103822630

搭建eurekaServer

image-20230418193046113

服务注册

image-20230418193241325

IDEA服务集群启动测试

image-20231015104211881

3.拉取服务

image-20230418193355054

Ribbon

Ribbon负载均衡原理

  1. 拦截请求获取服务id
  2. 拉取eureka注册中心返回服务地址列表
  3. 在IRule对地址列表选择策略,进行服务地址选择
  4. 调用服务实现负载均衡

image-20231015105827091

负载均衡策略配置

zoneavoidanceRlue为默认负载均衡策略,默认是轮询规则

image-20231016163731194

饥饿加载

ribbon总是在第一次获取请求才加载服务,耗时很长,启用项目启动时加载服务,提升网站速率

image-20231016165441076

Nacos

安装与启动

nacos安装地址

image-20231016173041656

启动Nacos:

1
.\startup.cmd -m standalone #单机模式

Nacos注册

image-20231016224338728

配置Nacos注册地址:

1
2
3
4
5
6
7
8
cloud: 
nacos:
server-addr: loaclhost:8848
discovery:
cluster-name: HZ #配置集群组
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 同时地域分组随机负载均衡规则

服务分级(分组)模型:

在同一个局域网的多个实例调用服务较快,配置集群组有助于调用服务时优先选择本地集群,如果都挂了,访问其他集群

image-20231016230946407

Nacos设置服务权重

此方法用于控制服务访问频率,一般设置在0~1

image-20231016232932597

NameSpace环境隔离

作用于隔离环境,不同环境下的服务无法访问,同一台机器可以用此来设置多个隔离空间用于开发环境,上线环境。

image-20231017092849760

1
2
3
4
cloud: 
nacos:
discovery:
namespace: c82bd449-3c13-487c-8468-da716efdedee #命名空间id

临时实例和非临时实例

默认为临时实例,服务发现拉取与eureka相同,Nacos引入非临时实例,主动询问服务提供者服务状态,如果服务出问题将会快速反映给消费者,主动通知push改变服务地址,但是损耗服务器性能。

image-20231017144943251

非临时实例配置:

image-20231017144933371

Nacos集群搭建

image-20231017181334847

修改集群配置(在cluster.conf文件中加入):

1
2
3
127.0.0.1:8845
127.0.0.1:8846
127.0.0.1:8847

nignx反向代理:

image-20231017182043340

更改服务提供者的Nacos地址:

image-20231017182223033

Nacos统一配置管理

项目启动读取配置流程:

image-20231017150818743

这里需要引入bootstrap.yml文件,提前将Nacos地址读取出来,才能进行下一步“读取Nacos配置文件”!它的优先级优于application.yml

image-20231017150704847

配置热更新

  1. 通过@RefreshScope更新

image-20231017165209097

1
2
3
4
5
@RefreshScope
public class UserController {
@Value("${pattern.dateformat}")
private String dateformat;
}
  1. 通过@ConfigurationProperties注入,自动刷新
1
2
3
4
5
6
7
8
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;
private String envSharedValue;
private String name;
}
1
2
3
4
5
6
7
@Autowired
private PatternProperties properties;

@GetMapping("now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
}

多环境配置共享

环境包括:dev(开发环境),test(测试环境),pro(开发环境)

1
2
3
spring:
profiles:
active: dev # 环境

image-20231017171459993

Feign

Feign用于简化远程调用,仅仅需要编写一个接口,就能实现Autowired,相当于本地调用一样。

使用技巧:Feign单独做个模块用来写controller接口,并打包添加到各服务依赖里面,就可以减小代码冗余!

Feign的使用

  1. 引入依赖
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 添加**@EnableFeignClients注解在SpringbootApplication**类上
  2. 编写FeignClient接口
1
2
3
4
5
6
@FeignClient(value = "userservice")
public interface UserClient {

@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
  1. 直接@Autowied,非常优雅
1
2
@Autowired
private UserClient userClient;

Feign的日志配置

image-20231018223151149

方式二:

1
2
3
4
5
6
public class DefaultFeignConfiguration {
@Bean
public Logger.Level logLevel(){
return Logger.Level.BASIC;
}
}
1
2
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@FeignClient(value = "userservice",configuration = DefaultFeignConfiguration.class)

性能优化:增加连接池

Feign底层使用URLConnection,没有配备连接池,效率很低,这里采用HttpClient来代替

image-20231018224439895

image-20231018224212617

Feign常用实现方式

image-20231019111234348

方式一:

xxxxxxxxxx docker-compose upsh

方式二:

image-20231019111500583

image-20231019112756854

GateWay

image-20231019130142980

搭建网关服务

  1. 新建一个模块,引入依赖

image-20231020225941385

  1. 注册为Nacos中的服务,配置路由信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
application:
name: gateway
cloud:
nacos:
server-addr: nacos:8848 # nacos地址
gateway:
routes:
- id: user-service # 路由标示,必须唯一
uri: lb://userservice # 路由的目标地址
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**

配置路由参数(predicates)

路由参数

image-20231020225826745

路由过滤器

路由过滤配置

  • 配置在路由下的过滤器只对当前路由请求生效
  • 配置在defaultFilters中所有路由有效
1
2
3
4
5
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=Truth,Itcast is freaking awesome!

image-20231020231125059

全局过滤器(GlobalFilter)

业务逻辑完全由自己来定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//示例用过滤器链做一个简单的登录校验
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3.判断参数值是否等于 admin
if ("admin".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,拦截
// 5.1.设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.拦截请求
return exchange.getResponse().setComplete();
}

@Override
public int getOrder() {
//order定义的是过滤链执行的顺序
return -1;
}
}

过滤器执行顺序

image-20231020234754745

跨域问题处理

跨域问题是浏览器拦截Ajax请求,需要配置才能实现前后端分离

image-20231020235620962

Docker部署微服务

Docker的安装

Docker在Centos7安装教程

1
2
3
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

配置镜像加速器:

1
2
3
4
5
6
7
8
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://rf7o1yzs.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

DockerHub网址

Docker命令查看

Docker容器包含操作linux内核的文件和镜像文件,打开容器其实就相当于一个阉割版的并且只安装了这个一个镜像的linux系统

1
2
3
4
5
docker -help
docker save --help
docker run --name mn -p 80:80 -d nginx
docker logs mn
docker exec -it mn bash #进入容器修改

image-20231021112419062

操作数据卷(volume)

将容器与数据分离,解耦合,方便操作容器内数据,保障数据安全

挂载volume修改文件内容更加方便

image-20231021125809902

挂载数据卷:

  1. volume挂载目录

image-20231021132203962

  1. 自定义文件夹,文件挂载目录
1
2
3
4
5
6
7
docker run \
--name mysql \
-p 3306:3306 \
-v /mount/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
-v /mount/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-d mysql:5.7.5 \

Dockerfile自定义镜像

Dockerfile文档

image-20231021143314540

1
2
3
4
5
6
7
8
9
10
11
12
# 指定基础镜像 FROM centos:7
FROM java:8-alpine

# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin

COPY ./docker-demo.jar /tmp/app.jar
# 暴露端口
EXPOSE 8090
# 指定入口,java项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar

DockerCompose集群部署

微服务项目结构:

image-20231021191119306

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: "3.2"

services:
nacos:
image: nacos/nacos-server
environment:
MODE: standalone
ports:
- "8848:8848"
mysql:
image: mysql:5.7.5
environment:
MYSQL_ROOT_PASSWORD: 123
volumes:
- "$PWD/mysql/data:/var/lib/mysql"
- "$PWD/mysql/conf:/etc/mysql/conf.d/"
userservice:
build: ./user-service
orderservice:
build: ./order-service
gateway:
build: ./gateway
ports:

docker-compose指令:

1
2
3
4
docker-compose up -d
docker-compose stop gateway userservice orderservice mysql nacos
docker-compose restart gateway userservice orderservice mysql
docker-compose logs -f userservice

Docker私有镜像仓库搭建