目录

地址:

描述:

RestTemplate远程访问:

eureka访问:

nacos注册中心

配置共享

feign远程调用

首先创建一个 module,命名为 feign-api

新增api

引入 feign 依赖:

order-service中 的 UserClient、User 都复制到 feign-api 项目中 加入依赖

在 order-service 启动类添加注解开启 Feign

测试

Gateway 网关

创建 SpringBoot 工程 gateway,引入网关依赖

编写启动类

流程图

全局过滤器

跨域问题

RabbitMQ消息中间件

镜像拉取

启动容器

publisher实现

consumer实现

SpringAMQP

pom:

配置:

在 consumer 服务中添加监听队列

在 publisher 服务中添加发送消息的测试类

WorkQueue

Fanout

Direct

topic

消息转换器

修改序列化:

ELasticsearch搜索引擎

es安装:

安装ik分词器

基本操作:

索引操作:

文档操作:

消息同步:

查询映射:

自动补全

JMeter压力测试

Sentine流量组件

springCloud中整合 Sentinel

Feign整合Sentinel

Seata分布式事务

Seata的架构

部署TC服务

Seata微服务集成


地址:

引用:

微服务技术栈 - 乐心湖's Blog | 技术小白的技术博客

GitHub:

描述:

RestTemplate远程访问:

    @Beanpublic RestTemplate restTemplate(){return new RestTemplate();}public Order queryOrderAndUserById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// TODO: 2021/8/15  2.查询用户User user = restTemplate.getForObject("http://localhost:8081/user/" + order.getUserId(), User.class);// 3. 将用户信息封装进订单order.setUser(user);// 4.返回return order;}

eureka访问:

新建eureka-service 服务

//pom 依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>//@EnableEurekaServer 开启 eureka 的注册中心功能import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);}
}// application.yml
server:port: 10086
spring:application:name: eureka-server
eureka:client:service-url: defaultZone: http://127.0.0.1:10086/eureka

将order user 注册到eureka服务

//将 user-service、order-service 都注册到 eureka
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>在启动类上添加注解:@EnableEurekaClientspring:application:#name:orderservicename: userservice
eureka:client:service-url: defaultZone: http://127.0.0.1:10086/eureka

服务拉取

//@LoadBalanced 注解,用于开启负载均衡。
//SpringCloud 底层提供了一个名为 Ribbon 的组件,来实现负载均衡功能。@Bean
@LoadBalanced
public RestTemplate restTemplate(){return new RestTemplate();
}

nacos注册中心

nacos安装

//拉取镜像
docker pull nacos/nacos-server//运行
docker run --name nacos -d -p 8848:8848 --privileged=true --restart=always -e JVM_XMS=256m -e JVM_XMX=256m -e MODE=standalone -e PREFER_HOST_MODE=hostname nacos/nacos-server//访问
http://localhost:8848/nacos/#/configurationManagement?dataId=&group=&appName=&namespace=&pageSize=&pageNo=

服务注册

//在 cloud-demo 父工程中引入 SpringCloudAlibaba 的依赖:<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>//然后在 user-service 和 order-service 中的pom文件中引入 nacos-discovery 依赖:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>//在 user-service 和 order-service 的 application.yml 中添加 nacos 地址:spring:cloud:nacos:server-addr: 127.0.0.1:8848//浏览器访问:http://localhost:8080/order/101,正常访问,同时负载均衡也正常。

配置文件

nacos 地址必须放在优先级最高的 bootstrap.yml 文件

//首先,在 user-service 服务中,引入 nacos-config 的客户端依赖
<!--nacos配置管理依赖-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>//然后,在 user-service 中添加一个 bootstrap.yml 文件,内容如下:spring:application:name: userservice # 服务名称profiles:active: dev #开发环境,这里是dev cloud:nacos:server-addr: localhost:8848 # Nacos地址config:file-extension: yaml # 文件后缀名//在nacos控制台新增配置文件 :
data-id: userservice-dev.yamllogging:level:com.xn2001: debugpattern:dateformat: MM-dd HH:mm:ss:SSS//在 user-service 中的 UserController 中添加业务逻辑,读取 pattern.dateformat 配置并使用:@Value("${logging.pattern.dateformat}")
private String dateformat;@GetMapping("now")
public String now(){//格式化时间return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}//启动服务后,访问:http://localhost:8081/user/now

配置共享

其实在服务启动时,nacos 会读取多个配置文件,例如:

  • [spring.application.name]-[spring.profiles.active].yaml,例如:userservice-dev.yaml
  • [spring.application.name].yaml,例如:userservice.yaml

这里的 [spring.application.name].yaml 不包含环境,因此可以被多个环境共享

feign远程调用

首先创建一个 module,命名为 feign-api

新增api

@FeignClient("userservice")
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}

引入 feign 依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

order-service中 的 UserClient、User 都复制到 feign-api 项目中 加入依赖

<dependency><groupId>com.xn2001.feign</groupId><artifactId>feign-api</artifactId><version>1.0</version>
</dependency>

在 order-service 启动类添加注解开启 Feign

@EnableFeignClients(basePackages = "com.xn2001.feign.clients")

测试

@Autowired
private UserClient userClient;public Order queryOrderAndUserById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// TODO: 2021/8/20 使用feign远程调用User user = userClient.findById(order.getUserId());// 3. 将用户信息封装进订单order.setUser(user);// 4.返回return order;
}

Gateway 网关

创建 SpringBoot 工程 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>//创建 application.yml 文件,内容如下: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/开头就符合要求
  1. 编写启动类

  2. 编写基础配置和路由规则
  3. 启动网关服务进行测试

http://localhost:10010/user/1

流程图

  1. 路由id:路由的唯一标示
  2. 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
  3. 路由断言(predicates):判断路由的规则
  4. 路由过滤器(filters):对请求或响应做处理

全局过滤器

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件

  • 参数中是否有 authorization
  • authorization 参数值是否为 admin
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {// 测试:http://localhost:10010/order/101?authorization=admin@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取第一个 authorization 参数String authorization = exchange.getRequest().getQueryParams().getFirst("authorization");if ("admin".equals(authorization)){// 放行return chain.filter(exchange);}// 设置拦截状态码信息exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);// 设置拦截return exchange.getResponse().setComplete();}// 设置过滤器优先级,值越低优先级越高// 也可以使用 @Order 注解@Overridepublic int getOrder() {return 0;}
}

跨域问题

spring:cloud:gateway:globalcors: # 全局的跨域处理add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题corsConfigurations:'[/**]':allowedOrigins: # 允许哪些网站的跨域请求 allowedOrigins: “*” 允许所有网站- "http://localhost:8090"allowedMethods: # 允许的跨域ajax的请求方式- "GET"- "POST"- "DELETE"- "PUT"- "OPTIONS"allowedHeaders: "*" # 允许在请求中携带的头信息allowCredentials: true # 是否允许携带cookiemaxAge: 360000 # 这次跨域检测的有效期

RabbitMQ消息中间件

镜像拉取

docker pull rabbitmq:3-management

启动容器

docker run \ -e RABBITMQ_DEFAULT_USER=admin \ -e RABBITMQ_DEFAULT_PASS=123456 \ --name mq \ --hostname mq1 \ -p 15672:15672 \ -p 5672:5672 \ -d \ rabbitmq:3-management

去掉 \

访问:

http://localhost:15672/#/queues/%2F/object.queue

publisher实现

public class PublisherTest {@Testpublic void testSendMessage() throws IOException, TimeoutException {// 1.建立连接ConnectionFactory factory = new ConnectionFactory();// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码factory.setHost("192.168.211.128");factory.setPort(5672);factory.setVirtualHost("/");factory.setUsername("admin");factory.setPassword("123456");// 1.2.建立连接Connection connection = factory.newConnection();// 2.创建通道ChannelChannel channel = connection.createChannel();// 3.创建队列String queueName = "simple.queue";channel.queueDeclare(queueName, false, false, false, null);// 4.发送消息String message = "Hello RabbitMQ!";channel.basicPublish("", queueName, null, message.getBytes());System.out.println("发送消息成功:[" + message + "]");// 5.关闭通道和连接channel.close();connection.close();}
}

consumer实现

public class ConsumerTest {public static void main(String[] args) throws IOException, TimeoutException {// 1.建立连接ConnectionFactory factory = new ConnectionFactory();// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码factory.setHost("192.168.211.128");factory.setPort(5672);factory.setVirtualHost("/");factory.setUsername("admin");factory.setPassword("123456");// 1.2.建立连接Connection connection = factory.newConnection();// 2.创建通道ChannelChannel channel = connection.createChannel();// 3.创建队列String queueName = "simple.queue";channel.queueDeclare(queueName, false, false, false, null);// 4.订阅消息channel.basicConsume(queueName, true, new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties, byte[] body) {// 5.处理消息String message = new String(body);System.out.println("接收到消息:[" + message + "]");}});System.out.println("等待接收消息中");}
}

SpringAMQP

pringAMQP 是基于 RabbitMQ 封装的一套模板,并且还利用 SpringBoot 对其实现了自动装配,使用起来非常方便。

SpringAMQP 的官方地址:Spring AMQP

pom:

<!--AMQP依赖,包含RabbitMQ-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置:

spring:rabbitmq:host: 192.168.150.101 # 主机名port: 5672 # 端口virtual-host: / # 虚拟主机username: admin # 用户名password: 123456 # 密码

在 consumer 服务中添加监听队列

@Component
public class RabbitMQListener {@RabbitListener(queues = "simple.queue")public void listenSimpleQueueMessage(String msg) throws InterruptedException {System.out.println("消费者接收到消息:【" + msg + "】");}
}

在 publisher 服务中添加发送消息的测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAmqpTest {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void testSimpleQueue() {// 队列名称String queueName = "simple.queue";// 消息String message = "你好啊,乐心湖!";// 发送消息rabbitTemplate.convertAndSend(queueName, message);}
}

WorkQueue

Fanout

路由

Direct

在 Fanout 模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到 DirectExchange

@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "direct.queue1"),exchange = @Exchange(value = "xn2001.direct"),key = {"a","b"}
))
public void listenDirectQueue1(String msg){System.out.println("接收到direct.queue1的消息:【" + msg + "】" + LocalTime.now());
}@RabbitListener(bindings = @QueueBinding(value = @Queue(value = "direct.queue2"),exchange = @Exchange(value = "xn2001.direct"),key = {"a","c"}
))
public void listenDirectQueue2(String msg){System.out.println("接收到direct.queue2的消息:【" + msg + "】" + LocalTime.now());
}
/*** direct* 向交换机发送消息*/
@Test
public void testDirectExchangeToA() {// 交换机名称String exchangeName = "xn2001.direct";// 消息String message = "hello, i am direct to a!";rabbitTemplate.convertAndSend(exchangeName, "a", message);
}/*** direct* 向交换机发送消息*/
@Test
public void testDirectExchangeToB() {// 交换机名称String exchangeName = "xn2001.direct";// 消息String message = "hello, i am direct to b!";rabbitTemplate.convertAndSend(exchangeName, "b", message);
}

topic

Topic 与 Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic 类型可以让队列在绑定Routing key 的时候使用通配符!

消息转换器

Spring 会把你发送的消息序列化为字节发送给 MQ,接收消息的时候,还会把字节反序列化为 Java 对象。

修改序列化:

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.10</version>
</dependency>
@Bean
public MessageConverter jsonMessageConverter(){return new Jackson2JsonMessageConverter();
}

ELasticsearch搜索引擎

es安装:

挂载指令:

docker run -it -v /D/docker/wordcount:/home/root/a_dir/ IMAGE
冒号前后分别为本地路径和要挂载到的路径
IMAGE为镜像名称

注意

本地路径不能像通常那样写作D:/,而是要写成/D/,否则会报错Error response from daemon: invalid mode
要挂载的路径/home/root/a_dir/原先就存在

docker run -d  --name es  -e "ES_JAVA_OPTS=-Xms512m -Xmx512m"  -e "discovery.type=single-node"  -v es-data:/D/es/data  -v es-plugins:/D/es/plugins --privileged  --network es-net  -p 9200:9200  -p 9300:9300  elasticsearch:7.12.1

这里磁盘挂在了,也有文件,但是没有生效,容器内在线安装

安装ik分词器

docker exec -it es /bin/bash./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip

参考:

docker安装es、ik分词器、kabana_Andy_Health的博客-CSDN博客_docker es安装ik

基本操作:

GET /hotel/_search
{
  "query": {
    "match_all": {}
  }
}

POST /_analyze
{
  "analyzer": "ik_max_word",
  "text": "努力工作天天向上"
}

PUT /hotel
{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

GET hotel

POST /md/_doc/1
{
  "info":"study",
  "email":"123@163.com"
}

GET /hotel/_doc/61083

// 查询所有
GET /hotel/_search
{
  "query": {
    "match_all": {
    }
  }
}

//条件查询
GET /hotel/_search
{
  "query": {
    "match": {
      "name": "7天"
    }
  }
}

// term查询
GET /hotel/_search
{
  "query": {
    "term": {
      "city.keyword": {
        "value": "上海"
      }
    }
  }
}

// range查询
GET /indexName/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10, // 这里的gte代表大于等于,gt则代表大于
        "lte": 20 // lte代表小于等于,lt则代表小于
      }
    }
  }
}

// geo_bounding_box查询 范围查询
GET /indexName/_search
{
  "query": {
    "geo_bounding_box": {
      "FIELD": {
        "top_left": { // 左上点
          "lat": 31.1,
          "lon": 121.5
        },
        "bottom_right": { // 右下点
          "lat": 30.9,
          "lon": 121.7
        }
      }
    }
  }
}

// geo_distance 查询 附近查询
GET /indexName/_search
{
  "query": {
    "geo_distance": {
      "distance": "15km", // 半径
      "FIELD": "31.21,121.5" // 圆心
    }
  }
}

//距离排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance" : {
          "location": "31.034661,121.612282", //圆心
          "order" : "asc", //排序
          "unit" : "km" //单位
      }
    }
  ]
}

索引操作:

package com.md.es;import com.md.es.constants.HotelConstants;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;import java.io.IOException;/*** TODO add description* <p>* Created at 2022/11/1 11:28** @author cengzq5*/
public class EsIndexTest {private RestHighLevelClient restHighLevelClient;@BeforeEachpublic  void test() throws IOException {restHighLevelClient = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://127.0.0.1:9200")));}@AfterEachpublic  void close() throws IOException {restHighLevelClient.close();}/*** 创建索引*/@Testvoid createHotelIndex() throws IOException {//指定索引库名CreateIndexRequest hotel = new CreateIndexRequest("hotel");//写入JSON数据,这里是Mapping映射hotel.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);//创建索引库restHighLevelClient.indices().create(hotel, RequestOptions.DEFAULT);}/** 判断索引是否存在* @Description p* @Author cengzq5* @Date 2022/11/1 14:02* @return void*/@Testvoid existHotelIndex() throws IOException {GetIndexRequest hotel = new GetIndexRequest("hotel");boolean exists = restHighLevelClient.indices().exists(hotel, RequestOptions.DEFAULT);System.out.println(exists);}/*** @Description 删除索引*/@Testvoid deleteHotelIndex() throws IOException {DeleteIndexRequest hotel = new DeleteIndexRequest("hotel");restHighLevelClient.indices().delete(hotel,RequestOptions.DEFAULT);}}

文档操作:

package com.md.es;import com.alibaba.fastjson.JSON;
import com.md.es.pojo.Hotel;
import com.md.es.pojo.HotelDoc;
import com.md.es.pojo.PageResult;
import com.md.es.service.HotelService;
import com.md.es.service.HotelServiceImpl;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;/*** TODO add description* <p>* Created at 2022/11/1 14:29** @author cengzq5*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class EsDocTest {@Resourceprivate RestHighLevelClient restHighLevelClient;//    @BeforeEach
//    public  void test() throws IOException {
//        restHighLevelClient = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://127.0.0.1:9200")));
//    }
//
//    @AfterEach
//    public  void close() throws IOException {
//        restHighLevelClient.close();
//    }@Resourceprivate HotelService hotelService;private final String index = "hotel";/*** @Description 新增文档* @Author cengzq5* @Date 2022/11/1 15:11* @return void*/@Testpublic void insertDoc() throws IOException {Hotel hotel = hotelService.getById(61083L);HotelDoc hotelDoc = new HotelDoc(hotel);IndexRequest indexRequest = new IndexRequest(index).id(hotelDoc.getId().toString());indexRequest.source(JSON.toJSONString(hotelDoc), XContentType.JSON);restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);}/*** @Description 查询文档* @Author cengzq5* @Date 2022/11/1 15:14* @return void*/@Testpublic void getDocById() throws IOException {GetRequest hotel = new GetRequest(index,"61083");GetResponse document = restHighLevelClient.get(hotel, RequestOptions.DEFAULT);String sourceAsString = document.getSourceAsString();HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);System.out.println(hotelDoc);}/*** @Description 删除文档* @Author cengzq5* @Date 2022/11/1 15:15* @return void*/@Testpublic void testDeleteDocumentById() throws IOException {DeleteRequest hotel = new DeleteRequest("hotel", "61083");restHighLevelClient.delete(hotel,RequestOptions.DEFAULT);}/*** @Description 增量修改文档** 修改文档有两种方式:** 全量修改:直接覆盖原来的文档* 增量修改:修改文档中的部分字段* 在 RestClient 的 API 中,全量修改与新增的 API 完全一致,判断依据是 ID** 如果新增时,ID已经存在,则修改* 如果新增时,ID不存在,则新增** @Author cengzq5* @Date 2022/11/1 15:18* @return void*/@Testpublic void updateDoc() throws IOException {UpdateRequest request = new UpdateRequest(index,"61083");request.doc("price","333","starName","钻石");restHighLevelClient.update(request,RequestOptions.DEFAULT);}@Testpublic void testBulk() throws IOException {BulkRequest bulkRequest = new BulkRequest();List<Hotel> hotelList = hotelService.list();hotelList.forEach(item -> {HotelDoc hotelDoc = new HotelDoc(item);bulkRequest.add(new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc), XContentType.JSON));});restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);}/*** @Description 全量查询* @Author cengzq5* @Date 2022/11/1 15:58* @return void*/@Testpublic void matchAll() throws IOException {SearchRequest request = new SearchRequest(index);request.source().query(QueryBuilders.matchAllQuery());SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);PageResult pageResult = HotelServiceImpl.handleResponse(search);System.out.println(pageResult);}
}

消息同步:

package com.md.es;import com.md.es.constants.MqConstants;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import javax.annotation.Resource;/*** TODO add description* <p>* Created at 2022/11/1 16:34** @author cengzq5*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class MqTest {@Resourceprivate RabbitTemplate rabbitTemplate;@Testpublic void deleteDoc(){rabbitTemplate.convertAndSend(MqConstants.HOTEL_EXCHANGE, MqConstants.HOTEL_DELETE_KEY, 61083L);}
}

查询映射:

聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。

桶(Bucket)聚合:用来对文档做分组

度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等

管道(pipeline)聚合:其它聚合的结果为基础做聚合

自动补全

当用户在搜索框输入字符时,我们应该提示出与该字符有关的搜索项,提示完整词条的功能,就是自动补全了。

JMeter压力测试

下载后直接执行 bin 目录就是执行的脚本 jmeter.bat,其中包含启动脚本

Sentine流量组件

Sentinel是阿里巴巴开源的一款微服务流量控制组件

下载后 jar 包后,运行代码:java -jar sentinel-dashboard-1.8.1.jar

java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar

访问 http://localhost:8080 页面,就可以看到 Sentinel 的控制台了。

springCloud中整合 Sentinel

order-service 中整合 Sentinel

1)引入 Sentinel 依赖
<!--sentinel-->
<dependency><groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2)配置控制台修改 application.yml 文件,添加下面内容:server:port: 8088
spring:cloud: sentinel:transport:dashboard: localhost:8080

10个请求有一半失败

Feign整合Sentinel

feign: sentinel: enabled: true # 开启feign对sentinel的支持

显示出链路

Seata分布式事务

分布式事务,就是指不是在单个服务或单个数据库架构下,产生的事务,例如

  • 跨数据源的分布式事务
  • 跨服务的分布式事务
  • 综合情况

在数据库水平拆分、服务垂直拆分之后,一个业务操作通常要跨多个数据库、服务才能完成。例如电商行业中比较常见的下单付款案例,包括下面几个行为:

  1. 创建新订单
  2. 扣减商品库存
  3. 从用户账户余额扣除金额

在没有分布式情况下,新增订单成功,数据库新增一条数据,但是账号服务或者库存服务会失败,不会插入数据。

Seata的架构

Seata 事务管理中有三个重要的角色

  • TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
  • TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
  • RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

部署TC服务

下载 seata-server 包,下载中心

1.4.2 版本

修改 conf 目录下的 registry.conf 文件

registry {# tc服务的注册中心类,这里选择nacos,也可以是eureka、zookeeper等type = "nacos"nacos {# seata tc 服务注册到 nacos的服务名称,可以自定义application = "seata-tc-server"serverAddr = "127.0.0.1:8848"group = "DEFAULT_GROUP"namespace = ""cluster = "default"username = "nacos"password = "nacos"}
}config {# 读取tc服务端的配置文件的方式,这里是从nacos配置中心读取,这样如果tc是集群,可以共享配置type = "nacos"# 配置nacos地址等信息nacos {serverAddr = "127.0.0.1:8848"namespace = ""group = "DEFAULT_GROUP"username = "nacos"password = "nacos"dataId = "seataServer.properties"}
}

为了让 TC 服务的集群可以共享配置,我们选择了 Nacos 作为统一配置中心。因此服务端配置文件 seataServer.properties 文件需要在Nacos 中配好。在 Nacos 后台新建一个配置文件:http://localhost:8848/nacos/

# 数据存储方式,db代表数据库
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
# 这是MySQL8的驱动,MySQL5使用的是com.mysql.jdbc.Driver
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 数据库地址、用户名、密码都需要修改成你自己的数据库信息。
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
# 事务、日志等配置
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
# 客户端与服务端传输方式
transport.serialization=seata
transport.compressor=none
# 关闭metrics功能,提高性能
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

进入 bin 目录,运行其中的 seata-server.bat 即可

进入cmd启动,运行seata-server.bat

注意:默认启动端口为8091,确认是否被占用

Seata微服务集成

pom依赖

dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId><exclusions><!--版本较低,1.3.0,因此排除--><exclusion><artifactId>seata-spring-boot-starter</artifactId><groupId>io.seata</groupId></exclusion></exclusions>
</dependency>
<!--seata starter 采用1.4.2版本-->
<dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>${seata.version}</version>
</dependency>

注意,所有服务都要配置

seata:registry: # TC服务注册中心的配置,微服务根据这些信息去注册中心获取tc服务地址type: nacos # 注册中心类型 nacosnacos:server-addr: 127.0.0.1:8848 # nacos地址namespace: "" # namespace,默认为空group: DEFAULT_GROUP # 分组,默认是DEFAULT_GROUPapplication: seata-tc-server # seata服务名称username: nacospassword: nacostx-service-group: seata-demo # 事务组名称service:vgroup-mapping: # 事务组与cluster的映射关系seata-demo: default

使用模式:

seata:data-source-proxy-mode: XA

2)给发起全局事务的入口方法添加 @GlobalTransactional 注解

重启服务,发送多于库存的订单请求

发现并没有新增库存订单

spring-cloud相关推荐

  1. Spring cloud 微服务docker容器化最佳实践

    Spring cloud 是当下最炙手可热的微服务套件,我们将介绍如何整合Docker容器达到高效快捷的构建发布 采用了dockerfile-maven-plugin插件发布镜像到远程docker主机 ...

  2. Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

    自Spring Cloud Alibaba发布第一个Release以来,就备受国内开发者的高度关注.虽然Spring Cloud Alibaba还没能纳入Spring Cloud的主版本管理中,但是凭 ...

  3. Spring Cloud下微服务权限方案

    背景 从传统的单体应用转型Spring Cloud的朋友都在问我,Spring Cloud下的微服务权限怎么管?怎么设计比较合理?从大层面讲叫服务权限,往小处拆分,分别为三块:用户认证.用户权限.服务 ...

  4. 玩转Spring Cloud之配置中心(config server config client)

    玩转Spring Cloud之配置中心(config server &config client)  本文内容导航: 一.搭建配置服务中心(config server) 1.1.git方式 1 ...

  5. spring cloud微服务治理eureka、hystrix、zuul代码例子

    spring cloud微服务中台服务代码例子,包括eureka.hystrix.zuul https://github.com/birdstudiocn/spring-cloud-sample/tr ...

  6. 原 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus)(Finchley版本)

    转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springcloud/2018/08/30/sc-f8-bus/ 本文出自方志朋的博客 转载请标明出处: Spr ...

  7. 快速构建Spring Cloud工程

    spring cloud简介 spring cloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选.分布式会话等等.它运行环境 ...

  8. spring cloud微服务分布式云架构--hystrix的使用

    hystrix主要作用在服务消费者,进行应用的保护,当请求的服务请求超时时,做出相应的处理,避免客户端一直进行请求等待,避免在高并发的情况出现服务器死机(请求过多,内存不足) 接下来的通过一个案例对h ...

  9. Spring Cloud构建分布式电子商务平台:服务消费(基础)

    使用LoadBalancerClient 在Spring Cloud Commons中提供了大量的与服务治理相关的抽象接口,包括DiscoveryClient.这里我们即将介绍的LoadBalance ...

  10. (二)spring cloud微服务分布式云架构 - 整合企业架构的技术点

    spring cloud本身提供的组件就很多,但我们需要按照企业的业务模式来定制企业所需要的通用架构,那我们现在需要考虑使用哪些技术呢? 下面我针对于spring cloud微服务分布式云架构做了以下 ...

最新文章

  1. java.lang.Instrument 动态修改替换类代码
  2. 名词解释CPC、CPM、CPA.......[来源于网络]
  3. 【Visual Studio 2019】上传代码到 GitHub ( 16.9.2 版本 | 安装 GitHub 扩展插件 | 创建 Git 仓库 | 推送到远程仓库 )
  4. 要的需求 ip提取网站源码带采集 要求是PHP源码
  5. boot druid 长时间不连接 异常_Spring Boot学习:如何使用Druid数据源
  6. DRDS分布式SQL引擎—执行计划介绍
  7. java调mongodb自定义函数,自定义UDF函数,从hive保存到mongodb
  8. iOS 简单引导界面
  9. 关闭裁剪功能_SOLIDWORKS 2021 新增功能—3D CAD
  10. 怎么讲gis里的符号化_地信(GIS)方向考研~?测绘科学与技术
  11. arcobjects java开发_ArcGIS Engine SDK for Java 最小示例学习
  12. JAVA实现List集合去重
  13. 8款实用的Jquery瀑布流插件
  14. iTunes 12恢复.ipsw固件
  15. 目前最赚钱的5种计算机编程语言
  16. 发布本人整理的面试问题大全,为准备找工作的同行们尽一份力 希望大家多补充或回答
  17. 全球 500 亿条数据被 Elasticsearch 勒索者删除
  18. SQL - 连接表(多表查询)
  19. [力扣c语言实现]207. 课程表(拓扑排序)
  20. 机器人将“上岗”参与“中国天眼”运维

热门文章

  1. STM8 定时器TIM1 计时
  2. spring框架面试题有哪些?spring框架必问面试题总结
  3. wincc的画面怎么用博图打开_博图v13如何打开winccflexible sp4文件
  4. pytorch训练WGAN网络
  5. FPS(farthest_point_sample) 最远点采样并可视化(附open3d python代码)
  6. Windows server 2012 R2 部署WSUS补丁服务
  7. 盒模型BFC渲染机制
  8. quartus仿真35:D触发器和JK触发器构成的异步时序电路
  9. HTML第6章上机练习5(制作爱奇艺视频播放列表)
  10. Linux debian安装Vim和Vim使用教程