1. 微服务环境搭建
1. 1 模板准备
1.1.1 技术选型(alibaba)
SpringCloud Alibaba
Sentinel,GateWay,Sleuth,ZipKin,Nacos Config,Seata
1.1.2 模块设计
springcloud-alibaba 父工程
- temp-common 公共模块
- temp-order 订单微服务
- temp-item 商品微服务
- temp-gateway 服务网关微服务
1.1.3 部署列表
应用服务名称 | IP | 端口 | 说明 |
---|---|---|---|
temp-gateway | localhost | 7000 | |
temp-order | localhost | 8081 | |
temp-item | localhost | 8181、8182 | 测试openfeign |
安装服务端中间件列表
中间件 | IP | 端口 | 说明 |
---|---|---|---|
nacos discovery(1.4.1) | localhost | 8848 | 服务发现 |
nacos config(1.4.1) | localhost | 8848 | 服务配置 |
sentinel dashbord | localhost | 8080 | 服务容错(服务降级、服务限流、服务熔断) |
zipkin server+sleuth | localhost | 9411 | 服务链路追踪 |
feign | 负载均衡的HTTP客户端 | ||
seata | 分布式事务 | ||
mysql | localhost | 3306 | 存储 |
1.1.4 微服务调用
简单需求:保存订单前,需调用商品微服务查询商品信息,以便校验库存和价格。
调用方:temp-order
提供方:temp-item
1.2 环境安装
1.2.1 安装nacos
下载zip格式的安装包,然后解压当前版本nacos-server-1.4.1.zip
解压目录:./run_env
1.2.1.1 启动nacos
Windows
#切换目录
cd ./run_env/nacos/bin
#命令启动
nacos/bin> ./startup.cmd -m standalone
注意:如果端口被占用,可以去nacos\conf\application.properties修改8848到其他未使用端口
1.2.1.2 访问nacos
打开浏览器输入http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos
1.2.2 安装Sentinel控制台
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。
1.2.2.1 下载jar包,解压到文件夹
1.2.2.2 启动控制台
# 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目) java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 - Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
1.2.2.3 访问控制台
默认用户名密码是 sentinel/sentinel
提示: 控制台的使用原理
Sentinel的控制台其实就是一个SpringBoot编写的程序。我们需要将微服务程序注册到控制台
上(即在微服务中指定控制台的地址, 并且还要开启一个跟控制台传递数据的端口, 控制台也可以通
过此端口调用微服务中的监控程序获取微服务的各种信息。)
1.2.2.4 添加有关控制台的配置
修改temp-order的application.yml
spring:
cloud:
sentinel:
transport:
port: 9999 # 和控制台交流的端口
dashboard: localhost:8080 # 指定控制台服务的地址
1.2.3 安装ZipKin服务端
1.2.3.1 下载ZipKin的jar包
访问上面的网址,即可得到一个zipkin-server-2.12.9-exec.jar
1.2.3.2 通过命令行,启动ZipKin Server
java -jar zipkin-server-2.12.9-exec.jar
1.2.3.3 通过浏览器访问 http://localhost:9411 访问
1.2.4 安装Docker Mysql数据库
docker-compose.yaml
version: '3'
services:
mysql_server:
container_name: mysql_temp
image: mysql:8.0.11
environment:
MYSQL_DATABASE: temp_db
MYSQL_USER: admin
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: rootpassword
expose:
- 3306
ports:
- 3306:3306
volumes:
# 启动脚本
- ./docker-compose/mysql/initdb:/docker-entrypoint-initdb.d/
# DB持久化
- ddd_mysql_db:/var/lib/mysql
volumes:
ddd_mysql_db:
driver: local
创建同级目录\docker-compose\mysql\initdb;并创建temp_db.sql
# CREATE DATABASE temp_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
USE temp_db;
SET CHARACTER_SET_CLIENT = utf8;
SET CHARACTER_SET_CONNECTION = utf8;
CREATE TABLE IF NOT EXISTS temp_item (
id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
name varchar(30) NOT NULL COMMENT '商品名',
price decimal(9,2) NOT NULL COMMENT '价格',
stock_num int NOT NULL COMMENT '库存',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='商品';
INSERT INTO temp_item VALUE(NULL,'iphone6',4000,50);
INSERT INTO temp_item VALUE(NULL,'iphone6s',4500,50);
INSERT INTO temp_item VALUE(NULL,'iphone7',5000,50);
INSERT INTO temp_item VALUE(NULL,'iphone7plus',5500,50);
安装并执行docker mysql
docker-compose up -d
1.3 创建父工程
创建一个maven工程,然后在pom.xml文件中添加以下内容
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>temp-common</module>
<module>temp-item</module>
</modules>
<!-- 指定父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<groupId>com.temp</groupId>
<artifactId>springcloud-alibaba</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 选择SpringCloud和Alibaba版本的时候,一定要参考官网的建议,否则会有问题 -->
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.5.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--spring cloud 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--spring cloud alibaba依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--nacos discovery是每个微服务都需要使用的依赖,所以提取到父类-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--fegin组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--链路追踪 Sleuth+ZipKin-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- 限流熔断降级Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--nacos config-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
</project>
版本对应:
Spring Cloud Alibaba Version | Sentinel Version | Nacos Version | RocketMQ Version | Dubbo Version | Seata Version | Spring Cloud Version | Spring Boot Version |
---|---|---|---|---|---|---|---|
2.2.5.RELEASE | 1.8.0 | 1.4.1 | 4.4.0 | 2.7.8 | 1.3.0 | Hoxton.SR8 | 2.3.2.RELEASE |
1.4 创建common模块
创建temp-common模块
1.4.1 在pom.xml中添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-alibaba</artifactId>
<groupId>com.temp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>temp-common</artifactId>
<dependencies>
<!-- 添加持久层框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
<properties>
<mysql.version>5.1.6</mysql.version>
<fastjson.version>1.2.56</fastjson.version>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
</project>
1.4.2 创建实体类
Item.java
package com.temp.po;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity(name = "temp_item")
@Data
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;//主键
private String name;//商品名称
private Double price;//商品价格
private Integer stockNum;//库存
}
Order.java
package com.temp.po;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity(name = "temp_order")
@Data
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long oid;//订单id
private Integer uid;//用户id
private String uname;//用户名
private Integer itemid;//商品id
private String name;//商品名称
private Double price;//商品单价
private Integer number;//购买数量
}
1.5 创建商品微服务
创建一个名为temp-item模块
1.5.1 添加springboot依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-alibaba</artifactId>
<groupId>com.temp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>temp-item</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.temp</groupId>
<artifactId>temp-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
</project>
1.5.2 创建工程的主类
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ItemApplication {
public static void main(String[] args) {
SpringApplication.run(ItemApplication.class, args);
}
}
1.5.3 创建配置文件application.yml
server:
port: 8181
spring:
application:
name: service-item
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp?useUnicode=true&characterEncoding=utf-8
username: root
password: root
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
1.5.4 创建ItemDao接口
package com.temp.dao;
import com.temp.po.Item;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* JPA接口
*/
public interface ItemDao extends JpaRepository<Item, Integer> {
}
1.5.5 创建ItemService接口和实现类
ItemService.java
package com.temp.service;
import com.temp.po.Item;
public interface ItemService {
Item queryItemById(Integer id);
}
ItemServiceImpl.java
package com.temp.service;
import com.temp.dao.ItemDao;
import com.temp.po.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemDao dao;
@Override
public Item queryItemById(Integer id) {
return dao.findById(id).get();
}
}
1.5.6 创建Controller
package com.temp.controller;
import com.temp.po.Item;
import com.temp.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("/item/{id}")
public Item query(@PathVariable Integer id) {
return itemService.queryItemById(id);
}
}
1.5.7 启动微服务并访问API
1.6 创建订单微服务
1.6.1 添加springboot依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-alibaba</artifactId>
<groupId>com.temp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>temp-order</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.temp</groupId>
<artifactId>temp-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
</project>
1.6.2 创建工程的主类
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
1.6.3 创建配置文件application.yml
server:
port: 8081
spring:
application:
name: service-order
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp_db?useUnicode=true&characterEncoding=utf-8
username: root
password: rootpassword
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
1.6.4 创建OrderDao接口
package com.temp.dao;
import com.temp.po.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderDao extends JpaRepository<Order,Long> {
}
1.6.5 创建OrderService接口和实现类
OrderService.java
package com.temp.service;
import com.temp.po.Order;
public interface OrderService {
public void save(Order order);
}
OrderServiceImpl.java
package com.temp.service;
import com.temp.dao.OrderDao;
import com.temp.po.Order;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private OrderDao orderDao;
@Override
public void save(Order order) {
orderDao.save(order);
}
}
1.6.6 在原有主类基础上,追加RestTemplate
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
/**
* 新追加的RestTemplate
* @return RestTemplate
*/
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
1.6.7 创建Controller
package com.temp.controller;
import com.temp.po.Item;
import com.temp.po.Order;
import com.temp.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@GetMapping("/order/item/{id}")
public Order saveOrder(@PathVariable("id") Integer id){
Item item = restTemplate.getForObject(
"http://localhost:8181/item/"+id,Item.class);
Order order = new Order();
order.setUid(1);
order.setUname("订单包裹");
order.setItemid(item.getId());
order.setName(item.getName());
order.setPrice(item.getPrice());
order.setNumber(1);
orderService.save(order);
return order;
}
}
1.6.8 启动工程,通过浏览器访问服务进行测试
2. 服务治理(Nacos Discovery)
2.1 nacos注册服务
2.1.1 将商品微服务注册到nacos
进一步修改temp-item模块的代码,并注册到nacos服务上
2.1.1.1 在主类上添加@EnableDiscoveryClient
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ItemApplication {
2.1.1.2 在application.yml中添加nacos地址
spring:
application:
name: service-item
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp_db?useUnicode=true&characterEncoding=utf-8
username: root
password: rootpassword
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
#服务治理--nacos注册服务
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
2.1.1.3 到nacos控制台查看是否注册成功
在订单微服务注册完,统一查看
2.1.2 将订单微服务注册到nacos
2.1.2.1 在主类上添加@EnableDiscoveryClient和Fegin的注解
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients //开启Feigin
public class OrderApplication {
2.1.2.2 在application.yml中添加nacos服务地址
server:
port: 8081
spring:
application:
name: service-order
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp_db?useUnicode=true&characterEncoding=utf-8
username: root
password: rootpassword
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
#服务治理--nacos注册服务
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
2.1.2.3 创建一个service,并使用Feigin实现微服务调用
ItemService.java
package com.temp.service;
import com.temp.po.Item;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("service-item")//声明调用的提供者名
public interface ItemService {
Item queryItemById(@PathVariable("id") Integer id);
}
2.1.2.4 修改controller代码,并启动验证
@Autowired
private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@Autowired
private ItemService itemService;
@GetMapping("/order/item/{id}")
public Order saveOrder(@PathVariable("id") Integer id){
// Item item = restTemplate.getForObject(
// "http://localhost:8181/item/"+id,Item.class);
// 基于OpenFeign的远程调用,默认集成Robbin实现负载均衡
Item item = itemService.queryItemById(id);
Order order = new Order();
order.setUid(1);
order.setUname("订单包裹");
order.setItemid(item.getId());
order.setName(item.getName());
order.setPrice(item.getPrice());
order.setNumber(1);
orderService.save(order);
return order;
}
2.1.2.5 重启order微服务,查看效果
3. 服务容错Sentinel
3.1 微服务集成Sentinel
微服务集成Sentinel非常简单,只需要加入Sentinel的依赖即可
package com.temp;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SentinelController {
@RequestMapping("/sentinel/test")
public String test(){
return "OK";
}
@RequestMapping("/sentinel/test2")
public String test2(){
return "OK-test2";
}
}
3.2 Feign整合Sentinel
3.2.1 在配置文件中开启Feign对Sentinel的支持
#服务治理--nacos注册服务
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
#开启Feign对Sentinel的支持
feign:
sentinel:
enabled: true
3.2.2 为容错的接口指定容错类
import com.temp.po.Item;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//@FeignClient("service-item")=>@FeignClient(value = "service-item")
@FeignClient(value = "service-item")//声明调用的提供者名=>value用于指定调用nacos下哪个微服务
public interface ItemService {
@GetMapping(value="/item/{id}")//指定请求的URI部分
Item queryItemById(@PathVariable("id") Integer id);
}
3.2.3 修改Controller
@RestController
@Slf4j
public class OrderController {
// @Autowired
// private RestTemplate restTemplate;
@Autowired
private OrderService orderService;
@Autowired
private ItemService itemService;
@GetMapping("/order/item/{id}")
public Order saveOrder(@PathVariable("id") Integer id){
// Item item = restTemplate.getForObject(
// "http://localhost:8181/item/"+id,Item.class);
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// 基于OpenFeign的远程调用,默认集成Robbin实现负载均衡
Item item = itemService.queryItemById(id);
Order order = new Order();
order.setUid(1);
order.setUname("订单包裹");
order.setItemid(item.getId());
order.setName(item.getName());
order.setPrice(item.getPrice());
order.setNumber(1);
// 暂时注释,防止频繁创建订单
// orderService.save(order);
return order;
}
}
3.2.4 停止所有temp-item服务,重启temp-order服务,访问请求,观察容错效果
4. 服务网关Gateway
4.1 快速入门
4.1.1 创建一个temp-gateway的模块,导入相关依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud-alibaba</artifactId>
<groupId>com.temp</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>temp-gateway</artifactId>
<properties>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
<dependencies>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
</project>
4.1.2 创建主类
package com.temp;
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);
}
}
4.1.3 添加配置文件
server:
port: 7000
spring:
application:
name: temp-gateway
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yml
shared-dataids: temp-common-config.yml
refreshable-dataids: temp-common-config.yml
gateway:
discovery:
locator:
enabled: true # 允许网关检测nacos中的微服务
routes:
- id: temp_route
uri: lb://service-order # lb 是通过名称从 nacos 获取微服务并遵循负载平衡策略。
predicates:
- Path=/order-serv/**
filters:
- StripPrefix=1
4.1.4 启动项目,并通过网关去访问微服务
先查看nacos
其次通过网关7000去访问service-order和service-item服务
4.2 整合Nacos
目前在配置文件中写死了转发路径的地址,写死地址会带来很多问题,接下来我们从注册中心获取此地址。
4.2.1 加入nacos依赖
<!-- nacos client-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
4.2.2 在主类上添加注解
package com.temp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args){
SpringApplication.run(GatewayApplication.class,args);
}
}
4.2.3 修改配置文件
server:
port: 7000
spring:
application:
name: temp-gateway
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
# file-extension: properties
# shared-dataids: temp-gateway.properties
# refreshable-dataids: temp-gateway.properties
gateway:
discovery:
locator:
enabled: true # 允许网关检测nacos中的微服务
routes:
- id: item_route
uri: lb://service-item # lb 是通过名称从 nacos 获取微服务并遵循负载平衡策略。
predicates:
- Path=/item-serv/**
filters:
- StripPrefix=1
4.2.4 测试
4.3 网关限流
4.3.1 导入依赖
<!--Gateway current limit-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
4.3.2 编写配置类
基于Sentinel的Gateway限流是通过其提供的Filter来完成的,使用时只需注入对应的SentinelGatewayFilter实例以及SentinelGatewayBlockExceptionHandler实例即可。
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer){
this.viewResolvers =
viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
/**
* Initialize a current-limiting filter
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter sentinelGatewayFilter(){
return new SentinelGatewayFilter();
}
/**
* Configure initial current limiting parameters
*/
@PostConstruct
public void initGatewayRules(){
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(
new GatewayFlowRule("item_route")// Resource name, corresponding to route id
.setCount(1) // Current limit threshold
.setIntervalSec(1) // Statistical time window, the unit is second, the default is 1 second
);
GatewayRuleManager.loadRules(rules);
}
/**
* Configure current limiting exception handler
* @return SentinelGatewayBlockExceptionHandler
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
return new SentinelGatewayBlockExceptionHandler(
viewResolvers,
serverCodecConfigurer
);
}
/**
* Custom current limit exception page
*/
@PostConstruct
public void initBlockHandlers(){
BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
Map map = new HashMap<>();
map.put("code",0);
map.put("message","The interface is current limited");
return ServerResponse
.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(map));
}
};
GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
}
4.3.3 测试
一秒内多次访问http://localhost:7000/item-serv/item/1 ,看限流是否起作用。
正常
频繁请求
可以看到限流起作用了。
5. 服务链路追踪Sleuth+ZipKin
5.1 Sleuth入门
加入依赖就行了,见父工程
5.2 Zipkin客户端集成
Zipkin客户端和Sleuth的集成非常简单,只需在微服务中添加其依赖和配置即可。
5.2.1 在每个微服务上添加依赖
加入依赖即可,见父工程
5.2.2 添加配置
spring:
application:
name: temp-gateway
zipkin:
base-url: http://127.0.0.1:9411/ #zipkin server of request address
discovery-client-enabled: false # Let nacos treat it as a URL, not as a service name
sleuth:
sampler:
probability: 1.0 #Sampled percentage
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
5.2.3 访问微服务
以gateway为例
5.2.4 访问zipkin的UI界面,观察效果
6. 服务配置Nacos Config
6.1 Nacos Config入门
6.1.1 搭建nacos环境
使用现有的nacos环境即可
6.1.2 引入nacos的依赖
加入依赖即可,见父工程
6.1.3 添加nacos config的配置
注意:不能使用原来的application.yml作为配置文件,而是新建一个bootstrap.yml作为配置文件
配置文件优先级(由高到低)
bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml
temp-item/src/resources/bootstrap.yml
spring:
application:
name: service-item
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 # nacos center address
file-extension: yaml # Configuration file format
6.1.4 在nacos中添加配置
直接把temp-item/src/resources/application.yml 的配置内容贴上,如下发布就可
这里注意:每当配置变更时,最好微服务重启一下
6.1.5 启动程序进行测试
service-order
service-item
service-gateway
可以访问,说明nacos config已经配置成功
6.2 Nacos Config高级
6.2.1 不同微服务共享配置(service-item,service-order)
不同微服务之间实现配置共享的原理类似于文件引入,就是定义一个公共配置,然后在当前配置中引入。
- 在nacos中定义一个DataID为temp-common-service.yaml的配置,用于所有微服务共享
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/temp_db?useUnicode=true&characterEncoding=utf-8
username: root
password: rootpassword
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
dashboard: 127.0.0.1:8888
zipkin:
base-url: http://127.0.0.1:9411/
discovery-client-enabled: false
sleuth:
sampler:
probability: 1.0
2 修改bootstrap.yaml
server:
port: 8181
spring:
application:
name: service-item
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848 # nacos center address
file-extension: yaml # Configuration file format
shared-dataids: temp-common-service.yaml
refreshable-dataids: temp-common-service.yaml
sentinel:
transport:
port: 8722
3 启动 微服务进行测试
7. 分布式事务Seata
7.1 安装Seata
7.1.1 下载Seata
7.1.2 修改配置文件
解压缩并进入conf目录,修改以下文件:
registry.conf
registry {
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
username = "nacos"
password = "nacos"
}
}
config {
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = "public"
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
# dataId = "seataServer.properties"
}
}
config.txt(最初时无此文件,需要在seata-server-1.4.2创建)
注意:用于存放各种配置中心的初始化脚本,执行时都会读取 config.txt
配置文件,并写入配置中心)
service.vgroup_mapping.service-item=default
service.vgroup_mapping.service-order=default
7.1.3 启动nacos初始化seata的配置
如果windows情况下,使用Git Bash Here来执行
从这里下载:github.com/seata/seata… 放到seata-server-1.4.2\conf
在git bash界面输入
sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t public -u nacos -w nacos
$ sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t public -u nacos -w nacos
set nacosAddr=127.0.0.1:8848
set group=SEATA_GROUP
Set service.vgroup_mapping.service-item=default successfully
Set service.vgroup_mapping.service-order=default successfully
=========================================================================
Complete initialization parameters, total-count:2 , failure-count:0
=========================================================================
Init nacos config finished, please start seata-server.
7.14 启动seata服务
cd bin
seata-server.bat -p 8900 -m file