spring cloud: 微服务环境搭建(alibaba)

835 阅读11分钟

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-gatewaylocalhost7000
temp-orderlocalhost8081
temp-itemlocalhost8181、8182测试openfeign

安装服务端中间件列表

中间件IP端口说明
nacos discovery(1.4.1)localhost8848服务发现
nacos config(1.4.1)localhost8848服务配置
sentinel dashbordlocalhost8080服务容错(服务降级、服务限流、服务熔断)
zipkin server+sleuthlocalhost9411服务链路追踪
feign负载均衡的HTTP客户端
seata分布式事务
mysqllocalhost3306存储

1.1.4 微服务调用

简单需求:保存订单前,需调用商品微服务查询商品信息,以便校验库存和价格。

调用方:temp-order

提供方:temp-item

1.2 环境安装

1.2.1 安装nacos

nacos_landscape.png

下载地址:github.com/alibaba/nac…

下载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

image-20210527101213924.png

image-20210527101253525.png

1.2.2 安装Sentinel控制台

Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。

1.2.2.1 下载jar包,解压到文件夹

github.com/alibaba/Sen…

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 访问控制台

地址:http://localhost:8080/

默认用户名密码是 sentinel/sentinel

image-20210527101351593.png

image-20210526185057830.png

提示: 控制台的使用原理

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包

search.maven.org/remote_cont…

访问上面的网址,即可得到一个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 访问

image-20210526222051676.png

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>

版本对应:

github.com/alibaba/spr…

Spring Cloud Alibaba VersionSentinel VersionNacos VersionRocketMQ VersionDubbo VersionSeata VersionSpring Cloud VersionSpring Boot Version
2.2.5.RELEASE1.8.01.4.14.4.02.7.81.3.0Hoxton.SR82.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

image-20210527111458283.png

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 启动工程,通过浏览器访问服务进行测试

image-20210527144622969.png

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微服务,查看效果

image-20210527160925172.png

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服务,访问请求,观察容错效果

image-20210531233120578.png

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

image-20210601111927367.png

其次通过网关7000去访问service-order和service-item服务

image-20210601112122264.png

image-20210601112217184.png

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 测试

image-20210601115751114.png

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 ,看限流是否起作用。

正常 image-20210601143753630.png

频繁请求

image-20210601143842387.png

可以看到限流起作用了。

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为例

image-20210601174818498.png

5.2.4 访问zipkin的UI界面,观察效果

image-20210601175102706.png

image-20210601175157189.png

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 的配置内容贴上,如下发布就可

image-20210601183536922.png

image-20210601184626572.png

这里注意:每当配置变更时,最好微服务重启一下

6.1.5 启动程序进行测试

service-order

image-20210601185528097.png

service-item

image-20210601185619287.png

service-gateway

image-20210601185708011.png

可以访问,说明nacos config已经配置成功

6.2 Nacos Config高级

6.2.1 不同微服务共享配置(service-item,service-order)

不同微服务之间实现配置共享的原理类似于文件引入,就是定义一个公共配置,然后在当前配置中引入。

  1. 在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 启动 微服务进行测试

image-20210601202828722.png

7. 分布式事务Seata

7.1 安装Seata

7.1.1 下载Seata

github.com/seata/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