springcloud_alibaba总结

Nacos

Spring Boot微服务向Nacos注册

  • pom
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • Properties
1
2
3
4
5
6
7
8
9
spring.application.name=microservice
server.port=8080
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
spring.cloud.nacos.discovery.server-addr=192.168.0.230:8848
spring.cloud.nacos.discovery.namespace=public
# 开启永久实例 不常用 默认为临时实例
#spring.cloud.nacos.discovery.ephemeral=false
#spring.clo ud.inetutils.preferred-networks=192.168.0
  • 添加注解
1
2
3
4
@EnableDiscoveryClient
@Configuration
public class NacosDiscoveryConfiguration {
}

临时实例和永久实例的区别

  • 临时实例只是临时存在于注册中心中,会在服务下线或不可用时被注册中心剔除,临时实例主动向注册中心发送心跳包
  • 永久实例在服务下线或不可用时也不会被注册中心剔除,注册中心会在永久服务初始化时根据客户端选择的协议类型(Http、TCP 以及 MySQL )注册探活的定时任务,注册中心主动向永久实例探活

Docker单机部署

1
2
3
4
5
6
7
8
9
10
 docker run -d --name nacos --restart=always \
-e MODE=standalone \
# 新版本需手动定义NACOS_AUTH_TOKEN、NACOS_AUTH_IDENTITY_KEY、NACOS_AUTH_IDENTITY_VALUE来确保服务安全
-e NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789 \
-e NACOS_AUTH_IDENTITY_KEY=ikey \
-e NACOS_AUTH_IDENTITY_VALUE=idvalue \
# 8848主端口、9848gRPC请求服务端端口用于客户端向服务端发起连接和请求、9849服务端gRPC请求服务端端口
# 默认为主端口+1000和+1001
-p 8848:8848 -p 9848:9848 -p 9849:9849 -d \
nacos/nacos-server:v2.2.1-slim

Docker集群部署

  1. 创建网桥
1
2
# 创建名为bdg-nacos-cluster的网桥,在同一网桥下不同容器可以通过容器名称进行通信
docker network create -d bridge bdg-nacos-cluster
  1. 创建MySQL容器,并初始化数据库nacos_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mkdir -p /etc/nacos-mysql/initdb
cd /etc/nacos-mysql/initdb

rm -f mysql-schema.sql
# nacos官方mysql数据表
wget http://manongbiji.oss-cn-beijing.aliyuncs.com/ittailkshow/sca2023/download/mysql-schema.sql

docker volume rm -f nacos-mysql-data
# 创建名为 nacos-mysql-data 的数据卷
docker volume create nacos-mysql-data

docker rm -f mysql8
docker run --name mysql8 --hostname=mysql8 -d \
-p=8306:3306 --network=bdg-nacos-cluster --restart=always \
-e MYSQL_ROOT_PASSWORD=root \
# 将nacos-mysql-data数据卷挂载到容器中的 /var/lib/mysql 目录,用于存储 MySQL 数据库文件,以实现持久化存储
-v nacos-mysql-data:/var/lib/mysql \
# 初始化数据库
-v /etc/nacos-mysql/initdb:/docker-entrypoint-initdb.d \
mysql:8
  1. 创建Nacos节点
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
# 此处可根据节点名称更换,如nacos2、nacos3
export CNAME=nacos1
# 此处可根据主节点端口更换,如8848、8850、8852,不可连续,因为会自动生成+1000和+1001的端口
export MAINPORT=8848
docker rm -f ${CNAME}
docker volume rm -f ${CNAME}-logs
# 创建日志数据卷,将Nacos Server日志持久化到主机
docker volume create ${CNAME}-logs

docker run -d --name ${CNAME} \
--network=bdg-nacos-cluster --restart=always \
--hostname=${CNAME} \
-e PREFER_HOST_MODE=hostname \
# 这里就看你到底需要几个节点了
-e NACOS_SERVERS="nacos1:8848 nacos2:8848 nacos3:8848" \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_SERVICE_HOST=mysql8 \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=root \
-e MYSQL_SERVICE_DB_PARAM="characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true" \
# 集群中NACOS_AUTH_IDENTITY_KEY、NACOS_AUTH_IDENTITY_VALUE、NACOS_AUTH_TOKEN要全部保持一致
-e NACOS_AUTH_IDENTITY_KEY=2222 \
-e NACOS_AUTH_IDENTITY_VALUE=2xxx \
-e NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789 \
-v ${CNAME}-logs:/home/nacos/logs \
-p ${MAINPORT}:8848 -p $((${MAINPORT}+1000)):9848 -p $((${MAINPORT}+1001)):9849 -d \
nacos/nacos-server:v2.2.1-slim

SpringCloud LoadBalancer

SpringBoot微服务集成LoadBalancer

  • pom

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
  • 添加注解

1
2
3
4
5
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
  • 负载请求
1
2
3
4
5
6
7
8
@Resource
private RestTemplate restTemplate;

@GetMapping("/remote-call")
public String remoteCall(){
String result = restTemplate.getForObject("http://provider-service/hello", String.class);
return "remote:" + result;
}

负载方式

默认为RoundRobinLoadBalancer轮询请求,如需更改负载方式如下操作

1
2
3
4
5
6
7
8
9
// 注意此处不要添加@configuration
public class CustomLoadBalancerConfiguration {
// 切换为RandomLoadBalancer随机负载
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment env,LoadBalancerClientFactory l) {
String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(l.getLazyProvider(name,ServiceInstanceListSupplier.class),name);
}
}
1
2
3
4
// 在启动端添加@LoadBalancerClients注解
@LoadBalancerClients({@LoadBalancerClient(value = "provider-service", configuration = CustomLoadBalancerConfiguration.class)})
public class ConsumerServiceApplication {
}

缓存方案

  • Springboot配置
1
2
3
4
5
spring.cloud.loadbalancer.cache.enabled=true
# 缓存过期时间
spring.cloud.loadbalancer.cache.ttl=120
# 负载均衡器的缓存容量
spring.cloud.loadbalancer.cache.capacity=100

生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
@Slf4j
public class CustomLoadBalancerLifecycle implements LoadBalancerLifecycle {
@Override
public void onStart(Request request) {
log.info("Starting load balancing for request: " + request);
}

@Override
public void onStartRequest(Request request, Response lbResponse) {
log.info("Selected service instance: " + lbResponse.getServer());
}
// CompletionContext 包含 LoadBalancer 响应,包括所选服务实例、针对该服务实例执行的请求的状态,(如果有)返回给下游客户端的响应,以及(如果发生异常)相应的 Throwable
@Override
public void onComplete(CompletionContext completionContext) {
// 在负载均衡之后执行的操作
log.info("Load balancing completed for request: " + completionContext.getLoadBalancerRequest() +
", with status: " + completionContext.status());
}
}

OpenFeign

  • 作用:动态组织远程发送的地址,但是实际负载均衡还是得靠LoadBalancer
  • pom
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 添加注解,在Application类上添加@EnableFeignClients
  • 声明接口
1
2
3
4
5
@FeignClient(name = "provider-service")
public interface ProviderServiceFeignClient {
@GetMapping("/list")
List<User> query(@RequestParam("page") int page, @RequestParam("rows") int rows);
}
  • 使用案例
1
2
3
4
5
6
7
8
9
10
@RestController
public class ConsumerController {
@Resource
private ProviderServiceFeignClient providerServiceFeignClient;
@GetMapping("/do1")
public List doSth1(){
List<User> userList = providerServiceFeignClient.query(1, 10);
return userList;
}
}

使用优化细节

  1. 将默认的URLConnection替换为OkHttpClient或者HttpClient 5
1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
</dependency>
1
2
spring.cloud.openfeign.httpclient.hc5.enabled=true
spring.cloud.openfeign.httpclient.hc5.socket-timeout=5
  1. OpenFeign请求/响应压缩,类似于nginx
1
2
3
4
5
6
7
# 启用请求或响应GZIP压缩 压缩后带宽减小 服务器cpu上升
spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true
# 配置支持压缩的请求的MIME类型列表
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置压缩请求的最小字节数,请求小于此值,则不会进行压缩处理
spring.cloud.openfeign.compression.request.min-request-size=2048
  1. 日志记录
1
2
3
4
5
6
7
@Configuration
public class FeignConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
1
2
3
@FeignClient(value = "provider-service",configuration = FeignConfiguration.class)
public interface ProviderServiceFeignClient {
}
  1. @FeignClient转发到URL
1
2
3
4
// 此时不会采用负载均衡
@FeignClient(name="testClient", url="http://localhost:8081")
public interface ProviderServiceFeignClient {
}

Dubbo3

服务提供者

  • pom
1
2
3
4
5
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
  • yaml
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
server:
port: 8001
spring:
application:
name: provider-service
cloud:
nacos:
server-addr: 192.168.31.231:8848
username: nacos
password: nacos
# dubbo启动是一个独立的容器 ,所以需要在nacos注册额外的dubbo容器
dubbo:
application:
name: provider-service-dubbo
registry:
# nacos:XX 为注册中心的种类,如果是zookeeper,则为zookeeper:XX
address: nacos://192.168.31.231:8848
username: nacos
password: nacos
# 当前dubbo容器对外暴露端口号,默认为20880,只有服务端需要暴露此端口
protocol:
name: dubbo
port: 20880
# 3.2.0默认序列化方式为fastjson2,巨坑
provider:
prefer-serialization: fastjson
  • 添加注解
1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableDubbo
@DubboComponentScan
public class ProviderServiceDubboApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderServiceDubboApplication.class, args);
}
}
1
2
3
4
5
6
7
8
// @DubboService注解可以将标注的服务实现类注册为Dubbo服务
// ProviderService为自定义的接口
@DubboService
public class ProviderServiceImpl implements ProviderService {
public User createUser(String uid, String username , String password , String nickname) {
return new User(uid,username,password,nickname);
}
}
1
2
3
4
5
6
7
8
9
// 注意,需要依赖的DTO对象,必须实现序列化接口Serializable
@Data
@AllArgsConstructor
public class User implements Serializable {
private String uid;
private String username;
private String password;
private String nickname;
}

服务消费者

  • pom
1
2
3
4
5
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
  • yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 8002
spring:
application:
name: consumer-service
cloud:
nacos:
server-addr: 192.168.31.231:8848
username: nacos
password: nacos
dubbo:
application:
name: consumer-service-dubbo
registry:
address: nacos://192.168.31.231:8848
username: nacos
password: nacos
# 消费端此处无需开放端口
  • 将服务提供者的接口复制过来(包名也得相同)
1
2
3
public interface ProviderService {
public User createUser(String uid, String username, String password, String nickname);
}
  • 添加注解
1
2
3
4
5
6
7
@SpringBootApplication
@EnableDubbo
public class ConsumerServiceDubboApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceDubboApplication.class, args);
}
}
1
2
3
4
5
6
7
8
9
@RestController
public class ConsumerController {
@DubboReference
private ProviderService providerService;
@GetMapping("/createUser")
public List<User> createUser(String uid, String username, String password, String nickname) {
return providerService.createUser(uid,username,password,nickname);
}
}

Spring Cloud Gateway

  • pom
1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
application:
name: gateway
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: nacos:8848
# 自动开启路由转发
gateway:
discovery:
locator:
enabled: true
server:
port: 80
赏个🍗吧
0%