面试日志elk之ES数据查询与数据同步

1.ES持久层技术​编辑

1.1 ES应用场景​编辑

1全文搜索

Elasticsearch可以用于实现全文搜索功能,例如搜索引擎、文档管理系统、电子商务搜索等。它支持复杂的查询语句、中文分词、近似搜索等功能,可以快速地搜索并返回匹配的结果。​编辑

2日志分析

Elasticsearch可以用于实现实时日志分析,例如监控系统、异常日志分析等。它可以快速地索引和搜索大量的日志数据,并支持聚合、可视化等功能,可以帮助用户快速定位和解决问题。 ELK

3业务分析

Elasticsearch可以用于实现业务分析,例如企业数据分析、市场调研等。它可以对海量数据进行搜索、聚合和分析,支持多种数据格式和数据源,例如数据库、日志、网页等,可以帮助用户了解业务情况、市场趋势等。

4搜索推荐

Elasticsearch可以用于实现搜索推荐功能,例如电商搜索推荐、新闻推荐等。它可以根据用户的搜索历史、行为等数据,进行个性化推荐,并支持实时更新和调整推荐结果。

5地理信息系统

Elasticsearch可以用于实现地理信息系统,例如地图搜索、位置分析等。它支持地理坐标索引和查询,可以快速地搜索和聚合地理数据,并支持地图可视化等功能。 GEO

1.2 Elasticsearch持久层技术盘点

  1. Elasticsearch官方提供的Java客户端 : Elasticsearch官方提供了Java客户端(High-Level REST Client和Low-Level REST Client),可以通过Java代码与ES进行交互。这些客户端提供了各种API和方法,用于执行索引、搜索、更新、删除等操作,并且支持与ES集群的连接和通信。
  2. Spring Data Elasticsearch : Spring Data Elasticsearch是SpringData框架提供的一个模块,用于简化与Elasticsearch的集成和操作。对于比较简单的查询操作,Spring Data Elasticsearch可以比较简便地实现查询功能,但是对于比较复杂的查询,Spring Data Elasticsearch使用起来依然比较繁琐,而且它的版本更新速度跟不上 Elasticsearch官方版本的更新速度,所以企业应用较少。
  3. Jest: Jest是一个开源的Java HTTP客户端库,专门用于与Elasticsearch进行交互。它提供了一组易于使用的API和方法,可以执行索引、搜索、更新、删除等操作。Jest具有良好的可扩展性和灵活性,并且支持与ES集群的连接和通信。
  4. Transport Client (已弃用): Transport Client是Elasticsearch早期版本中提供的Java客户端,自Elasticsearch 7.0版本起,Transport Client已被官方弃用
  5. Elegent Data Elasticsearch :Elegent Data Elasticsearch是Elegent Data的子框架。Elegent Data是传智教育研究院开发的一款针对NoSQL的持久层框架。Elegent Data Elasticsearch 改变了大家头疼的Elasticsearch持久化操作的难题。因为它可以让用户按照myBatisPlus的风格来操作Elasticsearch,轻松上手。

使用Elegent Data Elasticsearch框架,可以让你的程序更优雅。我们选择Elegent Data Elasticsearch框架。

1.3 Elegent Data

1.3.1 Elegent Data 简介

Elegent Data是一个优雅的NoSQL数据持久层框架。

(1)使用这个组件可以让你更轻松、更优雅地在项目中操作 Elasticsearch 等NoSQL数据库,风格类似于MyBatisPlus,让你更专注业务代码的开发。

(2)支持用户自行扩展。

开源项目地址 :gitee.com/chuanzhiliu...

我们看一下Elegent Data框架的系统架构图:

编辑

1.3.2 Elegent Data Elasticsearch快速入门

(1)在pom文件中添加依赖

xml 复制代码
<dependency>
    <groupId>cn.elegent.data</groupId>
    <artifactId>elegent-data-elasticsearch7</artifactId>
    <version>1.0.0</version>
</dependency>

(2)application.yml添加配置

less 复制代码
spring:
  elasticsearch:
    rest:
      uris: http://127.0.0.1:9201

(3)创建DTO

typescript 复制代码
@Data
public class OrderDTO {

    private Long id;//id

    private String orderNo;//订单编号

    private String innerCode;//机器编号

    private String addr;//点位地址
  
    private Long skuId;//商品id

    private String skuName;//商品名称
  
    private Integer status;//订单状态:0-创建;1-支付完成;2-出货成功;3-出货失败;

    private Integer amount;//支付金额

    private Integer bill;//分账金额

    private Integer price;//商品金额
  
}

(4)创建服务类

scala 复制代码
@Component
public class OrderEsService extends Elasticsearch7DataService<OrderDTO> {

}

(5)创建Controller类,测试分页查询、列表查询、增加、删除、修改操作。

typescript 复制代码
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderEsService orderEsService;


    @GetMapping("/page")
    public Pager<OrderDTO> findPage(){
        ElegentQueryWapper elegentQueryWapper=new ElegentQueryWapper();
        elegentQueryWapper.from("order")
                .eq("status","1")
                .eq("sku_name","统一奶茶");
        return  orderEsService.page(elegentQueryWapper,1,10);
    }

    @GetMapping("/list")
    public List<OrderDTO> findList(){
        ElegentQueryWapper elegentQueryWapper=new ElegentQueryWapper();
        elegentQueryWapper.from("order");
        return  orderEsService.list(elegentQueryWapper);
    }


    @GetMapping("/statistics")
    public List<StatisticsVo> findStatistics(){
        ElegentQueryWapper queryWapper=new ElegentQueryWapper();
        queryWapper.from("order")
                .eq("status","1")
                .count("price").groupBy("sku_id");
        return  orderEsService.statistics(queryWapper);
    }


    @GetMapping("/save")
    public void save(){
        OrderDTO orderDTO=new OrderDTO();
        orderDTO.setId(200L);
        orderDTO.setAddr("测试地址");
        orderDTO.setStatus(1);
        orderEsService.save("order",orderDTO.getId()+"",orderDTO);
    }


    @GetMapping("/update")
    public void update(){
        OrderDTO orderDTO=new OrderDTO();
        orderDTO.setId(200L);
        orderDTO.setAddr("地址测试");
        orderDTO.setStatus(2);
        orderEsService.update("order",orderDTO.getId()+"",orderDTO);
    }


    @GetMapping("/delete")
    public void delete(){
        orderEsService.delete("order","200");
    }

    @GetMapping("/findById/{id}")
    public OrderDTO findById( @PathVariable("id") String id){
        OrderDTO order = orderEsService.findById("order", id);
        return order;
    }

}

2.订单搜索

2.1 需求分析

用户在微信小程序中能够根据日期范围检索查询历史订单。

编辑

除了小程序,还有管理后台也需要订单查询功能。

编辑

2.2 实现思路

(1)在订单微服务,封装查询逻辑,通过使用ElegentData查询elasticsearch中的订单数据。

(2)在C端网关路由到订单微服务

2.3 代码实现

2.3.1 订单微服务搜索功能的实现

(1)在订单微服务的pom文件中,添加依赖

xml 复制代码
<dependency>
    <groupId>cn.elegent.data</groupId>
    <artifactId>elegent-data-elasticsearch7</artifactId>
    <version>1.0.0</version>
</dependency>

(2)在订单微服务的配置中(配置中心),添加以下配置

less 复制代码
spring:
  elasticsearch:
    rest:
      uris: http://127.0.0.1:9201

(3)创建搜索服务类 OrderEsService

scala 复制代码
@Component
public class OrderEsService extends Elasticsearch7DataService<OrderVO> {

}

(4)OrderService新增方法

javascript 复制代码
/**
 * 搜索订单
 * @param pageIndex
 * @param pageSize
 * @param orderNo
 * @param openId
 * @param startDate
 * @param endDate
 * @return
 */
Pager<OrderVO> search(Integer pageIndex, Integer pageSize, String orderNo, String openId, String startDate, String endDate);

(5)OrderServiceImpl实现此方法

typescript 复制代码
@Autowired
private OrderEsService orderEsService;

@Override
public Pager<OrderVO> search(Integer pageIndex, Integer pageSize, String orderNo, String openId, String startDate, String endDate) {
    ElegentQueryWapper elegentQueryWapper=new ElegentQueryWapper();
    elegentQueryWapper.from("order");
    if(orderNo!=null){
        elegentQueryWapper.eq("order_no",orderNo);
    }
    if(openId!=null){
        elegentQueryWapper.eq("open_id",openId);
    }
    if(startDate!=null && endDate!=null){
        elegentQueryWapper.between(  "create_time",startDate, endDate  );
    }
   return orderEsService.page(elegentQueryWapper, pageIndex, pageSize);
}

(6)OrderController调用 service的search方法

less 复制代码
/**
 * 搜索
 * @param pageIndex
 * @param pageSize
 * @param orderNo
 * @param openId
 * @param startDate
 * @param endDate
 * @return
 */
@GetMapping("/search")
public Pager<OrderVO> search(
        @RequestParam(value = "pageIndex",required = false,defaultValue = "1") Integer pageIndex,
        @RequestParam(value = "pageSize",required = false,defaultValue = "10") Integer pageSize,
        @RequestParam(value = "orderNo",required = false,defaultValue = "") String orderNo,
        @RequestParam(value = "openId",required = false,defaultValue = "") String openId,
        @RequestParam(value = "startDate",required = false,defaultValue = "") String startDate,
        @RequestParam(value = "endDate",required = false,defaultValue = "") String endDate){
    return orderService.search(pageIndex,pageSize,orderNo,openId,startDate,endDate);
}

2.3.2 C端网关路由配置

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
      #订单微服务
      - id: order
        uri: lb://order-service
        predicates:
        - Path=/order/**
        filters:

2.4 测试

VSCODE的测试脚本

css 复制代码
GET http://{{hostname}}:{{port}}/order/search?pageIndex=1&pageSize=10&openId=oJ9WJ5MhIS-hiwuUX0GmsHDzqTyQ&startDate=2020-01-01&endDate=2023-12-31 HTTP/1.1
Content-Type: {{contentType}}

3. 数据同步技术

我们现在已经实现了ES数据的查询功能,但是ES数据从哪里来呀?这就需要数据同步技术实现数据从Mysql到ES的搬运。

编辑

3.1 技术方案选型

3.1.1 MQ异步通知

MQ(消息队列)异步通知是一种常见的异步通信模式,用于在分布式系统中实现解耦和异步处理。它通过将消息发送到消息队列中,然后由消费者从队列中获取消息并进行处理,实现了消息的异步传递和处理。

我们可以在数据的增删改方法操作上,发送数据MQ, 消费者接受数据后进行数据的同步处理。

3.1.2 canal

阿里的Canal是一种开源的分布式数据库复制与实时数据订阅系统。它由阿里巴巴集团开发,旨在解决大规模分布式数据库的数据同步和实时数据订阅的需求。

Canal基于MySQL的主从复制原理,通过解析MySQL的binlog日志来实现数据的增量订阅和同步。它支持多种订阅方式,包括基于数据库表的增量订阅、基于全局事务的增量订阅以及基于时间点的全量订阅。Canal可以将数据库的变更数据实时地推送给订阅者,使得订阅者能够实时获取到数据库的最新数据。

3.1.3 Elegent Pipe

传智教育研究院研发的一款数据同步框架。它的实现原理与Canal是类似的,都是基于MySQL的主从复制原理,通过解析MySQL的binlog日志来实现数据的增量订阅和同步。与Canal不同的是,Elegent Pipe 是分为服务端和客户端两个部分,服务端处理监听后,通过ElegentAC将数据库变动的内容发送给客户端,所以ElegentPipe 更适合微服务架构应用程序的开发。

开源项目地址: gitee.com/chuanzhiliu...

3.2 Elegent Pipe快速入门

3.2.1 开启binlog

mysql8是默认开启binlog的 ,mysql5.7默认不开启.

我们可以通过以下命令查看binlog是否开启

sql 复制代码
SHOW VARIABLES LIKE '%log_bin%';

要开启MySQL的binlog,您可以按照以下步骤进行操作:

  1. 编辑MySQL的配置文件 my.cnfmy.ini,具体位置根据您的操作系统和MySQL版本而定。
  2. 找到并修改以下参数:
ini 复制代码
[mysqld]
log-bin=mysql-bin
server-id=1
    • log-bin:指定binlog日志文件的前缀名称,可以根据需要自定义。
    • server-id:指定MySQL实例的唯一标识,每个MySQL实例需要有不同的server-id。
  1. 保存并退出配置文件。
  2. 重启MySQL服务,以使配置生效。

开启binlog后,MySQL将开始记录所有的数据库更改操作,并将其写入binlog文件中。这些binlog文件可以用于数据恢复、数据备份、数据同步等用途。

请注意,在修改MySQL配置文件之前,请确保您对MySQL有足够的权限,并且备份了重要的数据。此外,开启binlog会增加MySQL的写入负载,因此在生产环境中,应该根据系统的性能和资源情况进行评估和调整。

3.2.2 代码实现

(1)在服务端的工程引入依赖 (由于ElegentPipe依赖ElegentAC,所以还要引入elegent-AC-mqtt )

xml 复制代码
<dependency>
    <groupId>cn.elegent.pipe</groupId>
    <artifactId>elegent-pipe-server</artifactId>
    <version>1.1.0</version>
</dependency>

<dependency>
    <groupId>cn.elegent.ac</groupId>
    <artifactId>elegent-AC-mqtt</artifactId>
    <version>1.1.0</version>
</dependency>

(2)在服务端的配置引入依赖

yaml 复制代码
elegent:
  pipe:
    host: 127.0.0.1
    port: 3306
    username: root
    passwd: HuangShu_2023
    tables:
      - demo:users
  ac:
    host: 127.0.0.1
    port: 1883
    clientId: transmitServer
    username: admin
    password: public
    keepAliveInterval: 30
    connectionTimeout: 60
server:
  port: 8888

(3)在客户端工程引入依赖

xml 复制代码
<dependency>
    <groupId>cn.elegent.pipe</groupId>
    <artifactId>elegent-pipe-client</artifactId>
    <version>1.1.0</version>
</dependency>

<dependency>
    <groupId>cn.elegent.ac</groupId>
    <artifactId>elegent-AC-mqtt</artifactId>
    <version>1.1.0</version>
</dependency>

(4)在客户端工程的配置文件添加

yaml 复制代码
elegent:
  ac:
    host: 127.0.0.1
    port: 1883
    clientId: transmitClient
    username: admin
    password: public
    keepAliveInterval: 30
    connectionTimeout: 60

(5)在客户端工程添加类用于处理数据增删改之后的操作

typescript 复制代码
@ElegentPipe(db="demo",table = "users")
public class UserTransmit implements PipeService {
    @Override
    public void insertHandler(TransmitDTO transmitDTO) {
        System.out.println("修改前数据:"+transmitDTO.getBefore());
        System.out.println("修改后数据:"+transmitDTO.getAfter());
    }

    @Override
    public void updateHandler(TransmitDTO transmitDTO) {
        System.out.println("修改前数据:"+transmitDTO.getBefore());
        System.out.println("修改后数据:"+transmitDTO.getAfter());
    }

    @Override
    public void deleteHandler(TransmitDTO transmitDTO) {
        System.out.println("修改前数据:"+transmitDTO.getBefore());
        System.out.println("修改后数据:"+transmitDTO.getAfter());
    }
}

3.2.3 常见错误

Java监听mysql的binlog 报错解决办法

报错:com.github.shyiko.mysql.binlog.network.AuthenticationException: Client does not support authentication protocol requested by server; consider upgrading MySQL client

这是你的mysql认证规则不正确导致的。

解决方案:在mysql中执行以下命令

sql 复制代码
alter user 'root'@'localhost' identified with mysql_native_password by '密码';  --修改认证规则
flush privileges; --刷新权限

4. 订单数据同步

4.1 需求分析

将订单库中的订单表数据,同步到ES中

4.2 实现思路

(1)创建数据同步的服务端模块,引入elegent-pipe-server以及Springboot依赖

(2)在服务端模块配置文件中,配置监听dkd_order库的tb_order表。

(3)在订单微服务引入elegent-pipe-client

(4)编写数据处理类,接收数据,并通过Elegent Data Elasticsearch将数据保存到 elasticsearch中。

4.3 代码实现

4.3.1 构建数据同步服务

(1)创建dkd_pipe_service模块,Pom文件引入elegent-pipe-server以及Springboot依赖

xml 复制代码
<dependency>
    <groupId>cn.elegent.pipe</groupId>
    <artifactId>elegent-pipe-server</artifactId>
    <version>1.1.0</version>
</dependency>

<dependency>
    <groupId>cn.elegent.ac</groupId>
    <artifactId>elegent-AC-mqtt</artifactId>
    <version>1.1.0</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

(2)创建配置文件 application.yml

yaml 复制代码
elegent:
  pipe:
    host: 127.0.0.1
    port: 3306
    username: root
    passwd: HuangShu_2023
    tables:
      - dkd_order:tb_order
  ac:
    host: 127.0.0.1
    port: 1883
    clientId: transmitServer
    username: admin
    password: public
    keepAliveInterval: 30
    connectionTimeout: 60
spring:
  application:
    name: pipe-service
server:
  port: 8999

(3)添加启动类

typescript 复制代码
@SpringBootApplication
public class TransmitServerApplication {

    public static void main(String[] args){
        SpringApplication.run(TransmitServerApplication.class, args);
    }
}

4.3.2 同步逻辑的实现

(1)订单微服务 添加依赖

xml 复制代码
<dependency>
    <groupId>cn.elegent.pipe</groupId>
    <artifactId>elegent-pipe-client</artifactId>
    <version>1.1.0</version>
</dependency>

(2)订单微服务 创建数据同步处理类

typescript 复制代码
/**
 * 接受订单数据同步
 */
@ElegentPipe(db="dkd_order",table = "tb_order")
@Slf4j
public class OrderPipe implements PipeService {

    @Autowired
    private OrderEsService orderEsService;

    @Override
    public void insertHandler(TransmitDTO transmitDTO) {
        Map<String, Serializable> orderMap = transmitDTO.getAfter();
        orderEsService.save("order", (Long)orderMap.get("id")+"",orderMap );
        log.info("ES插入订单数据{}",orderMap);
    }

    @Override
    public void updateHandler(TransmitDTO transmitDTO) {
        Map<String, Serializable> orderMap = transmitDTO.getAfter();
        orderEsService.update("order",(Long)orderMap.get("id")+"",orderMap );
        log.info("ES修改订单数据{}",orderMap);
    }

    @Override
    public void deleteHandler(TransmitDTO transmitDTO) {
        Map<String, Serializable> orderMap = transmitDTO.getBefore();
        orderEsService.delete("order",(Long)orderMap.get("id")+"");
        log.info("ES删除订单数据{}",orderMap);
    }
}

相关推荐
码农BookSea1 小时前
用好PowerMock,轻松搞定那些让你头疼的单元测试
后端·单元测试
绝无仅有1 小时前
大场面试之最终一致性与分布式锁
后端·面试·架构
晨晖22 小时前
springboot的Thymeleaf语法
java·spring boot·后端
seven97_top2 小时前
SpringCloud 常见面试题(二)
后端·spring·spring cloud
b***66613 小时前
【springboot】健康检查 监控
java·spring boot·后端
databook3 小时前
让你的动画“活”过来:Manim 节奏控制指南 (Rate Functions)
后端·python·动效
n***33353 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
XUN4J4 小时前
深入浅出谈谈RPC框架
后端
Java水解4 小时前
功能全面的PostgreSQL图形化管理工具pgAdmin3实战详解
后端·postgresql