月度归档: 2022年12月

一个ES查询生产环境异常排查过程

异常信息:java.io.IOException: listener timeout after waiting for [60000] ms

异常堆栈:

java.io.IOException: listener timeout after waiting for [60000] ms
	at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:660)
	at org.elasticsearch.client.RestClient.performRequest(RestClient.java:219)
	at org.elasticsearch.client.RestClient.performRequest(RestClient.java:191)
	at com.suning.maoning.core.es.EsClientHolder.performRequest(EsClientHolder.java:113)
	at com.suning.maoning.core.es.EsClientHolder.performRequest(EsClientHolder.java:127)
	at com.suning.maoning.core.es.EsClient.searchAfter(EsClient.java:343)
	at com.suning.maoning.mnbi.service.impl.commissionexport.XXXXXXXXXXXService.queryData(BaseCommissionEsExcelExportService.java:76)
	at com.suning.maoning.excel.common.export.service.impl.EsScrollRunnable.async(EsScrollRunnable.java:39)
	at com.suning.maoning.excel.common.export.service.impl.EsScrollRunnable$$FastClassBySpringCGLIB$$1736c315.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at com.suning.maoning.core.cache.interceptor.RedisInterceptor.invoke(RedisInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

根据异常堆栈指示的信息,找到对应发生异常的业务类,定位到相关具体语句,是一个ES查询调用的地方,调用方法为

esClient.searchAfter

继续跟踪对应方法

Continue reading

ElasticSearch去重查询统计数量不准确的问题

首先是需求场景介绍,上个月的需求用HIVE做数据清洗写了个T+1的任务,处理每天的退款订单数据,并将数据写入ElasticSearch中提供给业务系统进行查询及导出相关功能的开发。

ElasticSearch中的数据结构为子单纬度的,这里为了描述方便一下用sub_id替代说明。同时每条sub_id记录上关联了一个主订单id,下面的描述中主订单我们用main_id代替说明。每个sub_id都会关联一个main_id,且只能关联一个main_id,但是一个main_id可以关联多个sub_id,即非常常见标准的一个主订单关联多个子订单的1对N的结构模式。

在业务场景中,根据业务需求开发订单展示的页面功能,页面上以main_id纬度为基准进行展示,所以在这里,我们做如下方式的开发

  1. 根据页面查询入参条件先对main_id去重分页查询,同时统计总数量
  2. 根据main_id去重查询的分页结果,取得当页的main_id数据,并把这些main_id连通之前本次查询的参数一起作为新的参数,用这些新的参数重新去ElasticSearch中查询当前这些main_id下对应的sub_id的数据
  3. 取得这些sub_id数据后,在内存中对这些数据按照main_id分组聚合,并通过接口返回给前端

这样我们便实现了从main_id维度的分页查询功能,具体用到的相关ElasticSearch查询DSL语句大致如下

GET /refund_order_index/refund_order_type/_search
{
  "size": 20,
  "from": 0,
  "query": {
    "bool": {
      "filter": [
        {}
      ]
    }
  },
  "collapse": {
    "field": "main_id"
  },
  "_source": {
    "includes": [
      "main_id"
    ],"excludes": []
  },
  "aggs": {
    "total_count": {
      "cardinality": {
        "field": "main_id"
      }
    }
  }
}

ElasticSearch查询返回结果如下,内容和字段等我已做脱敏处理

Continue reading

小坑+1,Mysql的UNIQUE索引中允许存在Null值

一个小坑,如题。

新建了一张表,假设如下

create table table_c
(
id int auto_increment
primary key,
req_id int null,
req_type int default 0 null,
req_version int default 0 null,
constraint table_c_req_id_req_type_uindex
unique (req_id, req_type)
)
charset = latin1;

表中有个(req_id, req_type)组成的唯一索引,插入数据一些数据后得到如下结果

从上表中插入的结果来看,可以看到有两条(req_id = 124, req_type = null)组成的行数据,可见,unique索引中可以包含null值字段

A UNIQUE index permits multiple NULL values for columns that can contain NULL.

https://dev.mysql.com/doc/refman/5.6/en/create-index.html

官方文档中提到了这么一段,确实可以包含的,且根据上面的实验结果,但凡某个字段为null了,那么唯一性约束就失效了。

相关处理办法

  1. 给unique索引相关字段添加上 not null属性 和 default
  2. 程序代码中相关对象拼装的时候校验相关字段,并赋予默认值

首先,在设置了default值之后,如果插入执行insert语句的时候没有对应字段,mysql会赋予默认的default值。其次,某些封装的JDBC操作的工具如果我们传入的字段没有值,那么工具会自动给这个字段赋值null,那么就导致如果没有设置 not null属性会被插入一个null值,仍然导致唯一索引约束失效。