当前位置:首页 >> 行情

选型+设计实践,一次引入Elasticsearch的系统架构空战

来源:行情   2023年04月05日 12:15

我们运维相较于MongoDB更是熟悉Elasticsearch。 我们紧接著有一些统计数字报注记类的期望,Elastic Stack的各种电脑程式能不太好实现我们的期望。 我们以外著手处理方式的一幕以非实时、纯读过为配的业务范围,Elasticsearch左右实时查看早就能实现我们。 二、Elasticsearch举例

腾讯百科 :

Elasticsearch是一个基于Lucene的查看增值器。它透过了一个分布式多普通用户能力的全文谷歌,基于RESTful web上端口。Elasticsearch由Java口语联合开发的,是一种流行的企业级谷歌。Elasticsearch运用于互联中都,能够达致实时查看,稳定,合理,较快,配备同多种类型。官方浏览器在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他口语中都都是可用的。

对于实现所想的业务范围期望和期望支持海量原始数据的查看,我考虑了Elasticsearch,真是是理由配要这两项:

那么我其所确信Elasticsearch相当大的缺点只有吃CPU,具体情况理由可以看下文CPU初始化一小。

三、Elasticsearch为什么快?

我其所对于Elasticsearch快的理由配要总结三点:

CPU初始化 多种数据库:倒排数据库和doc values。 战斗群重置

1、CPU初始化

Elasticsearch是基于Lucene, 而Lucene被所设计为可以利用转换系统最上层机制来堆栈CPU原始数据结构设计,换句话真是Elasticsearch是具体情况来真是转换系统最上层的Filesystem Cache,检索时,转换系统但会将驱动器文件从前的原始数据终上端堆栈到 Filesystem Cache 从前面去,因此承诺Elasticsearch可靠性更多很高,那么就能够增值器的透过的更多CPU给Filesystem Cache 覆盖存留储设备的原始数据。

上一段仍要一句话什么意思呢?假如:Elasticsearch 路由器有 3 台增值器各64GCPU,3台总CPU就是 64 * 3 = 192G。每台电脑程式给 Elasticsearch jvm heap 是 32G,那么每增值器想得到 Filesystem Cache 的就是 32G(50%),而战斗群从前的 Filesystem Cache 的就是 32 * 3 = 96G CPU。此时,在 3 台Elasticsearch增值器共五迁出了 1T 的驱动器容量,那么每台电脑程式的原始资料量兆 341G,意味着每台增值器只有大概10分之1原始数据是堆栈在CPU的,其余都得走到闪存。

真是到这从前大家并不一定但会有一个直觉得认识,因此我从《大M-网站系统所设计核心:核心原理与情形分析》第36页抠了一张注记格从前:

从上示意图竖直项看借助于,CPU初始化可靠性是机壳驱动器的200倍,是SSD驱动器兆30倍,假如读过一次Elasticsearch走到CPU一幕下耗时20毫秒,那么走到机壳闪存就得4秒,走到SSD驱动器确实兆0.6秒。讲到这从前我相信大家对是否是走到CPU的可靠性差异有一个直觉的认识。

对于Elasticsearch有很多种数据库类M-,但是我确信核心配要是倒排数据库和doc values。

2、倒排数据库

Lucene将初始化数据库的所有信息许多组织为倒排数据库(inverted index)的结构设计形式。倒排数据库是一种将词干同态到XML的原始数据结构设计,可以确信倒排数据库是面向词干的而不是面向XML的。

假设在测试环境的Elasticsearch存留放在了有以下三个XML:

Elasticsearch Server(XML1) Masterring Elasticsearch(XML2) Apache Solr 4 Cookbook(XML3)

以上XML数据库建好后,简明标示借助于如下:

如上注记格所示,每个词项看做到术语项所借助于现过的XML前方,这种数据库结构设计强制较快、有效的查看借助于原始数据。

3、doc values

对于分组、催化、排序等某些系统来真是,倒排数据库的作法并不是最佳考虑,这类系统转换的是XML而不是词项,这个时候就得把倒排数据库逆转出去已成正排数据库,这么做到但会有两个缺点:

构建短时间较宽。 CPU迁出大,确实避免OutOfMemory,且影响废物回收。

Lucene 4.0之后完整版加进了doc values和额外的原始数据结构设计来二阶决上头得弊上端,以外有五种类M-的doc values:NUMERIC、BINARY、SORTED、SORTED_SET、SORTED_NUMERIC,针对每种类M-Lucene都有特定的存留储方法。

doc values是列式存留储设备的正排数据库,通过docID可以较快初始化到该doc的特定URL的值,列式存留储设备存留储设备对于催化计算有相当很高的可靠性。

4、战斗群重置

Elasticsearch可以直觉、较快利用多路由器增值器形已成战斗群,为了将分摊增值器的继续执行压力。

此外原始数据可以来进行重置存留储设备,查看时模版到完全相同增值器上的配重置来进行查看。

这从前可以直觉讲述下Elasticsearch检索原理,Elasticsearch的检索分两个下一阶段:集中都于下一阶段与改组下一阶段。

假定一个Elasticsearch路由器都可以不能接受浏览器的催促。不能接受到催促后,就是集中都于下一阶段,并行发送子检索给其他路由器;

然后是改组下一阶段,则从极多重置中都获取送回结果,然后对他们来进行改组、排序、取较宽等不足之处转换。最终将结果送回给浏览器。

机制如下示意图:

分页浅层圈套

基于以上检索的原理,引入一个分页浅层的弊上端。

现能够查页较宽为10、第100页的原始数据,其实上是但会把每个 Shard 上存留储设备的前 1000(10*100) 条原始数据都查到一个协同路由器上。如果有 5 个 Shard,那么就有 5000 条原始数据,接着协同路由器对这 5000 条原始数据来进行一些改组、处理方式,再借助到最终第 100 页的 10 条原始数据。也就是其实上查的原始数据总量为pageSize*pageIndex*shard,每页更深则检索的越慢。因此ElasticSearch也但会有承诺,每次检索借助于来的原始数据据统计数字不但会送回有约10000条。

那么从业务范围上必要跟产品沟通能避免分页跳转,运用于向下初始化。而Elasticsearch运用于的特别系统所设计是search_after、scroll_id。

四、ElasticSearch与资料库基本本质对比

在Elasticsearch 7.0完整版之后(<7.0),有type的本质,而Elasticsearch和彼此间M-资料库的彼此间是,index = database、type = table,但是在Elasticsearch 7.0完整版后(>=7.0)弱所谓了type默确信_doc,而官方但会在8.0之后但会从根本上移走type。

五、增值器选M-

在官方XML()从前促请Elasticsearch JVM Heap最大为32G,同时不有约增值器CPU的一半,也就是真是CPU分别为128G和64G的增值器,JVM Heap最大才会够设置32G;而32G增值器,则促请JVM Heap最大16G,剩余的CPU将但会给到Filesystem Cache充分运用于。如果不能够对词干正则注记达式做到催化计算(例如,不能够 fielddata )可以慎重考虑增大JVM Heap。JVM Heap越小,但会造已成了Elasticsearch的GC频率更是很高,但Lucene就可以的运用于更是多的CPU,这样可靠性就但会更是很高。

对于我们Corporation的期望追加业务范围还但会有获取普通用户的访不知就有来统计数字PV(page view)、UV(user view),有一定的催化计算,经难免方便的慎重考虑与讨论,平衡已制造成本与期望后考虑了腾讯幽的两台配置为CPU 16核、CPU64G,SSD幽闪存的增值器,并给与Elasticsearch 配置JVM Heap = 32G。

六、期望一幕考虑

Elasticsearch在本Corporation系统的可运用于一幕相当多,但是作为第一次加进因慎重考虑,给与联合开发与运维一定的短时间熟悉与检视。

经过商讨,考虑了两个业务范围一幕,普通用户书本小真是的就有明细与小真是查看,考虑这两个业务范围一幕理由如下:

1、所写一幕

我们模拟器的普通用户黏性相当很高,书本小真是是一个很高频率的子程序,因此普通用户书本小真是的就有明细可在短短时间内造已成海量原始数据的一幕。(现一个年末已达致了70G的原始资料量,共五1亿1千万条)

2、读过一幕

书本就有无需透过给期望追加的电话卡业务范围运用于,可从书本副标题数、书本小时等来进行查看计算。 小真是查看既有二阶决问题是通过彼此间M-资料库like检索,已是不具备潜在的可靠性弊上端与自然资源消耗的业务范围一幕。

对于上述两个业务范围,普通用户书本小真是的就有明细与电话卡业务范围不属于追加业务范围,对于在投身于已制造成本相较较少,也不用难免的能够可选原先业务范围的压力。

而小真是查看业务范围不属于优所谓改造,得保障可选既有的普通用户查看习惯理论上下,追加拼法查看。同时最差以引入的作法,必要的下降代码重所写范围,如果运用于效果太差,随时可以回滚到原先的二阶决问题作法。

七、所设计拟议

1、共五性所设计

我运用于.Net 5 WebApi将Elasticsearch嵌入已成ES业务范围增值API,这样的作法配要用来隐藏系统所设计显然(时区、词干器、类M-转换已成等),引出粗粒度的输入上端口。这种作法在马丁福勒所著的《NoSQL拟将》所称把资料库视之为“领域普通用户界面资料库”,直觉来真是就是才会通过领域间接的访不知存留储设备,对于这个领域由一个一个团队负责维护联合开发,也只有这个一个团队才并不知道存留储设备的结构设计。这样通过嵌入的API增值二阶继续性了直接API增值与存留储设备,子程序方就不用难免注目存留储设备的物理性质,像Mongodb与Elasticsearch这种无方式而的存留储设备,不用不应将为判别结构设计,换而言之就是对于存留储设备已为结构设计可随意重所写引入,那么“领域普通用户界面资料库”的作法也能避免了其他一个团队无意侵入的重所写。

慎重考虑到现在业务范围期望多样度相较直觉,MQ消费品上端也一起集已成到ES业务范围增值,若不足之处MQ消费品业务范围小规模增多,再慎重考虑把MQ消费品业务范围所希望到一个(或多个的)消费品上端某种程度。

以外以连动读过、连动所写、异步所写的三种交互作法,来进行与其他增值通信。

2、书本就有明细

本期望是完全追加,因此加进相较直觉,才会够在【模拟器API】运用于【RabbitMQ】来进行二阶继续性,运用于异步作法初始化Elasticsearch,运用于路由注记除了用来二阶继续性,还不以为然用来填充很高模版所写压力的确实会。

对于不足之处追加的业务范围例如电话卡增值,则才会够通过RPC前提联接ES业务范围API,以连动初始化的作法检索原始数据。

3、小真是查看

对于该业务范围,我第一反不应有别于CQRS的观念,既有的初始化命题我不用难免的注目与了二阶,因此我才会够希望办法把彼此间M-资料库的原始数据连动到Elasticsearch,然后透过业务范围检索API附加既有模拟器API的原始Web才可。

那么原始数据连动则一般都是分先为和纳两种作法。

4、先为

先为的实时性或许是比纳要很高,只无需短时间内的先为送做到初始化的原始数据(增、续、改)才可,无论是从可靠性、自然资源利用、行政处分各层面来看都比纳更是有效。

制定该拟议,可以考虑Debezium和SQL Server开端CDC系统。

Debezium由RedHatUbuntu的,同时能够具体情况来真是kafka的,一个将多种原始Web实时变更是原始数据俘获,形已成原始时序输借助于的Ubuntu电脑程式,同类产品有Canal, DataBus, Maxwell。

CDC通所称Change Data Capture,这样一来译文出去为变更是原始数据俘获,核心为监控增值俘获资料库的所写转换(抽出,更是新,续除),将这些变更是按发生的顺序明晰就有从前。

我其所在我博客社论多次重申核心所设计的转换已成已成核心为恰好:实现期望与许多组织核心,在实现期望的理论上不应不应将为考虑直觉、合适的拟议。系统所设计选M-不应能够慎重考虑自己的一个团队是否是可以支撑。在上述无论是额外加入Debezium和kafka,还是能够针对SQL Server开端CDC都大于了我们运维所能承受的趋左右,加进最初中都间件和系统所设计是能够试错的,而试错是能够额外很高的已制造成本,在未确定的确实会下加进更是多的未确定,只但会造已成更是大的已制造成本和不可控。

5、纳

纳或许是最直觉最合适的二阶决问题作法,才会够运用于作业勤务增值,不定段短时间不间断去从资料库纳取原始数据初始化到Elasticsearch就可。

然而纳取原始数据,分全量连动与短时间内连动:

对于短时间内连动,才会够每次检索原始WebSelect * From Table_A Where RowVersion> LastUpdateVersion,则可以过滤借助于能够连动的原始数据。但是这个作法有点致命的缺点,原始Web已被续除的原始数据是未检索借助于来的,如果把Elasticsearch反之亦然去跟SQL Server原始数据做到对比又是一件相当荒谬的作法,因此才会坚持该作法。

而全量连动,只要每次从SQL Server原始Web全量追加到Elasticsearch,并附加原先的Elasticsearch的Index,因此该拟议得全续全增。但是这从前又引申借助于最初弊上端,如果先为续后增,那么在续除后再追加的这段真空期怎么办?假如有5分钟的真空期是不能原始数据,普通用户就未运用于查看系统。那么才会先为增不足之处,先为追加到一个Index_Temp,全量追加完后,把既有Index改名已成Index_Delete,然后再把Index_Temp改已成Index,仍要把Index_Delete续除。这么一套转换从前,有不能心从前很繁琐很费劲?Elasticsearch有一个叫原指(Aliases)的系统,原指可以一对多的看做到多个Index,也可以以粒子性的来进行原指看做到Index的待机,具体情况二阶决问题可以看下文。

八、书本就有二阶决问题显然

1、也就是真是判别

不应将为判别了个抽象类ElasticsearchEntity来进行复用,对于也就是真是判别有三个注意的显然点:

对于ElasticsearchEntity我判别两个属性_id与Timestamp,Elasticsearch是无方式而的(不用预判别结构设计),如果也就是真是本身不能_id,初始化到Elasticsearch但会终上端转化已成一个_id,为了不足之处的运用于便捷性,我无论如何自行判别了一个。 基于上述的分页浅层的弊上端,因此在不足之处涉及的业务范围必要但会以search_after+向下初始化的作法落实到我们的业务范围。取而代之我们才会够运用于DateTime类M-的URL用DateTime.Now就有后,再运用于search_after后但会终上端把DateTime类M-URL转换已成已成毫秒级的Timestamp,但是我在二阶决问题demo的时候,去仿造原始数据,在普通用户界面从前以for可逆new原始数据的时候,辨认借助于转化已成的速度但会在微秒级彼此之间,那么假设用毫秒级的Timestamp来进行search_after过滤,同一个毫秒有4、5条原始数据,那么容确实避免在运用于向下初始化时候少初始化了几条原始数据,这样就到造已成了原始数据送回不准确了。因此我引入了个[DateTime.Now.DateTimeToTimestampOfMicrosecond()]转化已成微秒级的Timestamp,为了将必要下降借助于现引初始化原始数据的确实会。 对于Elasticsearch的转换也就是真是的日前短时间类M-均以DateTimeOffset类M-通告,因为Elasticsearch存留储设备的是UTC短时间,而且但会因为Http催促的日前格式完全相同造已成了存留放在的日前短时间也但会大大偏差,为了能避免日前弊上端运用于DateTimeOffset类M-是一种保险的作法。而对于WebAPI 上端口或者MQ的Message不能接受的短时间类M-可以运用于DateTime类M-,DTO(终端某类)与DO(无论如何所谓某类)运用于Mapster或者AutoMapper十分相似的某类同态电脑程式来进行转换已成才可(注意DateTimeOffset转DateTime得判别转换已成规则 [TypeAdapterConfig.NewConfig().MapWith(dateTimeOffset => dateTimeOffset.LocalDateTime)])。

更是进一步,把Elasticsearch转换显然隐藏在WebAPI从前,以亲善、直觉的上端口引出给联合开发者运用于,增大了联合开发者对系统所设计显然认知负担。

[ElasticsearchType(RelationName = "user_view_duration")]

public class UserViewDuration : ElasticsearchEntity

{

///

/// 小真是ID

///

[Number(NumberType.Long, Name = "entity_id")]

public long EntityId { get; set; }

///

/// 小真是类M-

///

[Number(NumberType.Long, Name = "entity_type")]

public long EntityType { get; set; }

///

/// 副标题ID

///

[Number(NumberType.Long, Name = "charpter_id")]

public long CharpterId { get; set; }

///

/// 普通用户ID

///

[Number(NumberType.Long, Name = "user_id")]

public long UserId { get; set; }

///

/// 创建人短时间

///

[Date(Name = "create_datetime")]

public DateTimeOffset CreateDateTime { get; set; }

///

/// 小时

///

[Number(NumberType.Long, Name = "duration")]

public long Duration { get; set; }

///

/// IP

///

[Ip(Name = "Ip")]

public string Ip { get; set; }

}

public abstract class ElasticsearchEntity

{

private Guid? _id;

public Guid Id

{

get

{

_id ??= Guid.NewGuid();

return _id.Value;

}

set => _id = value;

}

private long? _timestamp;

[Number(NumberType.Long, Name = "timestamp")]

public long Timestamp

{

get

{

_timestamp ??= DateTime.Now.DateTimeToTimestampOfMicrosecond();

return _timestamp.Value;

}

set => _timestamp = value;

}

}

2、异步初始化

对于异步初始化有两个显然点:

该原始数据从RabbtiMQ免费消费品初始化到Elasticsearch,从后面代码可以看借助于,我蓄意以年末的维空间确立Index,格式为 userviewrecord-2021-12,这么做到的最终目标是为了方便管理Index和自然资源利用,有能够的确实会下但会续除原先的Index。 第一时间免费与WebAPI继续集已成到同一个某种程度,这样做到配要是联合开发、部署都方便,如果不足之处免费多了,在把第一时间免费特别的业务范围所希望到独立的某种程度。

1)按无需转变,能避免过度所设计

① 免费消费品命题

public class UserViewDurationConsumer : BaseConsumer

{

private readonly ElasticClient _elasticClient;

public UserViewDurationConsumer(ElasticClient elasticClient)

{

_elasticClient = elasticClient;

}

public override void Excute(UserViewDurationMessage msg)

{

var document = msg.MapTo();

var result = _elasticClient.Create(document, a => a.Index(typeof(Entity.UserViewDuration).GetRelationName() + "-" + msg.CreateDateTime.ToString("yyyy-MM"))).GetApiResult();

if (result.Failed)

LoggerHelper.WriteToFile(result.Message);

}

}

///

/// 免费消费品

///

public static class ConsumerExtension

{

public static IApplicationBuilder UseSubscribe(this IApplicationBuilder appBuilder, IHostApplicationLifetime lifetime) where T : EasyNetQEntity, new() where TConsumer : BaseConsumer

{

var bus = appBuilder.ApplicationServices.GetRequiredService();

var consumer = appBuilder.ApplicationServices.GetRequiredService();

lifetime.ApplicationStarted.Register(() =>

{

bus.Subscribe(msg => consumer.Excute(msg));

});

lifetime.ApplicationStopped.Register(() => bus?.Dispose());

return appBuilder;

}

}

② 免费与注入

public class Startup

{

public Startup(IConfiguration configuration)

{

Configuration = configuration;

}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)

{

}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)

{

app.UseAllElasticApm(Configuration);

app.UseHealthChecks("/health");

app.UseDeveloperExceptionPage();

app.UseSwagger();

app.UseSwaggerUI(c =>

{

c.SwaggerEndpoint("/swagger/v1/swagger.json", "SF.ES.Api v1");

c.RoutePrefix = "";

});

app.UseRouting();

app.UseEndpoints(endpoints =>

{

endpoints.MapControllers();

});

app.UseSubscribe(lifetime);

}

}

3、检索上端口

检索上端口此处有两个显然点:

如果不确定年末份,则运用于形式化检索userviewrecord-*,当然有能够的也可以运用于原指处理方式。 因为Elasticsearch是就有UTC短时间,因此短时间检索得自行决定TimeZone。

[HttpGet]

[Route("record")]

public ApiResult> GetRecord([FromQuery] UserViewDurationRecordGetRequest request)

{

var dataList = new List();

string dateTime;

if (request.BeginDateTime.HasValue && request.EndDateTime.HasValue)

{

var month = request.EndDateTime.Value.DifferMonth(request.BeginDateTime.Value);

if(month

dateTime = request.BeginDateTime.Value.ToString("yyyy-MM");

else

dateTime = "*";

}

else

dateTime = "*";

var mustQuerys = new List, QueryContainer>>();

if (request.UserId.HasValue)

mustQuerys.Add(a => a.Term(t => t.Field(f => f.UserId).Value(request.UserId.Value)));

if (request.EntityType.HasValue)

mustQuerys.Add(a => a.Term(t => t.Field(f => f.EntityType).Value(request.EntityType)));

if (request.EntityId.HasValue)

mustQuerys.Add(a => a.Term(t => t.Field(f => f.EntityId).Value(request.EntityId.Value)));

if (request.CharpterId.HasValue)

mustQuerys.Add(a => a.Term(t => t.Field(f => f.CharpterId).Value(request.CharpterId.Value)));

if (request.BeginDateTime.HasValue)

mustQuerys.Add(a => a.DateRange(dr =>

dr.Field(f => f.CreateDateTime).GreaterThanOrEquals(request.BeginDateTime.Value).TimeZone(EsConst.TimeZone)));

if (request.EndDateTime.HasValue)

mustQuerys.Add(a =>

a.DateRange(dr => dr.Field(f => f.CreateDateTime).LessThanOrEquals(request.EndDateTime.Value).TimeZone(EsConst.TimeZone)));

var searchResult = _elasticClient.Search(a =>

a.Index(typeof(UserViewDuration).GetRelationName() + "-" + dateTime)

.Size(request.Size)

.Query(q => q.Bool(b => b.Must(mustQuerys)))

.SearchAfterTimestamp(request.Timestamp)

.Sort(s => s.Field(f => f.Timestamp, SortOrder.Descending)));

var apiResult = searchResult.GetApiResult();

if (apiResult.Success)

dataList.AddRange(apiResult.Data);

return ApiResult>.IsSuccess(dataList);

}

九、小真是查看二阶决问题显然

1、也就是真是判别

SearchKey是既有SQL Server的原始数据,现能够连动到Elasticsearch,仍是后继者抽象类。ElasticsearchEntity也就是真是判别,同时这从前有三个显然点:

public string KeyName,我判别的是Text类M-,在Elasticsearch运用于Text类M-才但会词干。 在也就是真是判别我不能给KeyName自行决定词干器,因为我但会运用于两个词干器:拼法和预设词干,而我但会在大批量初始化原始数据创建人Mapping时判别。 也就是真是从前的 public List SysTagId 与SearchKey在SQL Server是两张完全相同的物理注记,是一对多的彼此间,在代码注记示如下,但是在彼此间M-资料库是未与之相关联和彰显的,这就是咱们所真是的“阻抗失配”,但是能在以XMLM-存留储设备系统(MongoDB、Elasticsearch)从前不太好的二阶决这个弊上端,可以以一个催化的作法初始化,能避免多次检索关联。

[ElasticsearchType(RelationName = "search_key")]

public class SearchKey : ElasticsearchEntity

{

[Number(NumberType.Integer, Name = "key_id")]

public int KeyId { get; set; }

[Number(NumberType.Integer, Name = "entity_id")]

public int EntityId { get; set; }

[Number(NumberType.Integer, Name = "entity_type")]

public int EntityType { get; set; }

[Text(Name = "key_name")]

public string KeyName { get; set; }

[Number(NumberType.Integer, Name = "weight")]

public int Weight { get; set; }

[Boolean(Name = "is_subsidiary")]

public bool IsSubsidiary { get; set; }

[Date(Name = "active_date")]

public DateTimeOffset? ActiveDate { get; set; }

[Number(NumberType.Integer, Name = "sys_tag_id")]

public List SysTagId { get; set; }

}

2、原始数据连动

原始数据连动我有别于了Quartz.Net不间断作业勤务前提,因此行政处分不很高,所以每4足足连动一次才可,有42W多的原始数据,分批来进行连动,每次检索1000条原始数据同时来进行一次大批量初始化。全量连动一次的短时间大概2分钟。因此运用于RPC子程序[ES业务范围API增值]。

因为具体情况业务范围命题早就嵌入在[ES业务范围API增值],因此连动命题也相较直觉,检索借助于SQL Server原始Web、催化整理、子程序[ES业务范围API增值]的大批量初始化上端口、继续COM原指到最初Index。

[DisallowConcurrentExecution]

public class SearchKeySynchronousJob : BaseJob

{

public override void Execute()

{

var rm = SFNovelReadManager.Instance();

var maxId = 0;

var size = 1000;

string indexName = "";

while (true)

{

//能避免一次性全部检索借助于来,每1000条一次初始化。

var searchKey = sm.searchKey.GetList(size, maxId);

if (!searchKey.Any())

break;

var entityIds = searchKey.Select(a => a.EntityID).Distinct().ToList();

var sysTagRecord = rm.Novel.GetSysTagRecord(entityIds);

var items = searchKey.Select(a => new SearchKeyPostItem

{

Weight = a.Weight,

EntityType = a.EntityType,

EntityId = a.EntityID,

IsSubsidiary = a.IsSubsidiary ?? false,

KeyName = a.KeyName,

ActiveDate = a.ActiveDate,

SysTagId = sysTagRecord.Where(c => c.EntityID == a.EntityID).Select(c => c.SysTagID).ToList(),

KeyID = a.KeyID

}).ToList();

//以一个催化初始化到ES

var postResult = new SearchKeyPostRequest

{

IndexName = indexName,

Items = items

}.Excute();

if (postResult.Success)

{

indexName = (string)postResult.Data;

maxId = searchKey.Max(a => a.KeyID);

}

}

//原指从原先Index看做到最初Index,仍要续除原先Index

var renameResult = new SearchKeyRenameRequest

{

IndexName = indexName

}.Excute();

}

}

}

3、业务范围API上端口

大批量追加上端口这从前有2个显然点:

在第一次有原始数据付钱的时候能够创建人Mapping,因为得对KeyNameURL判别词干器,其余URL都可以运用于AutoMap才可。 信和人的Index名所称是粗略到秒的 SearchKey-202112261121

///

/// 大批量追加小真是查看列注记(送回创建人的indexName)

///

///

///

[HttpPost]

public ApiResult Post(SearchKeyPostRequest request)

{

if (!request.Items.Any())

return ApiResult.IsFailed("无传布原始数据");

var date = DateTime.Now;

var relationName = typeof(SearchKey).GetRelationName();

var indexName = request.IndexName.IsNullOrWhiteSpace() ? (relationName + "-" + date.ToString("yyyyMMddHHmmss")) : request.IndexName;

if (request.IndexName.IsNullOrWhiteSpace())

{

var createResult = _elasticClient.Indices.Create(indexName,

a =>

a.Map(m => m.AutoMap().Properties(p =>

p.Custom(new TextProperty

{

Name = "key_name",

Analyzer = "standard",

Fields = new Properties(new Dictionary

{

{ new PropertyName("pinyin"),new TextProperty{ Analyzer = "pinyin"} },

{ new PropertyName("standard"),new TextProperty{ Analyzer = "standard"} }

})

}))));

if (!createResult.IsValid && request.IndexName.IsNullOrWhiteSpace())

return ApiResult.IsFailed("创建人数据库告终");

}

var document = request.Items.MapTo();

var result = _elasticClient.BulkAll(indexName, document);

return result ? ApiResult.IsSuccess(data: indexName) : ApiResult.IsFailed();

}

继续COM原指上端口这从前有4个显然点:

原指运用于searchkey,只但会有一个Index[searchkey-yyyyMMddHHmmss]但会跟searchkeyCOM. 不应将为把已COM的Index检索借助于来,方便二阶绑与续除。 原指COM在Elasticsearch虽然是粒子性的,但看看原始数据理论上的,因此得先为Add后Remove。 续除原先得Index照样迁出难免自然资源。

///

/// 继续COM原指

///

///

[HttpPut]

public ApiResult Rename(SearchKeyRanameRequest request)

{

var aliasName = typeof(SearchKey).GetRelationName();

var getAliasResult = _elasticClient.Indices.GetAlias(aliasName);

//给新index自行决定原指

var bulkAliasRequest = new BulkAliasRequest

{

Actions = new List

{

new AliasAddDescriptor().Index(request.IndexName).Alias(aliasName)

}

};

//移走原指从前原先的数据库

if (getAliasResult.IsValid)

{

var indeNameList = getAliasResult.Indices.Keys;

foreach (var indexName in indeNameList)

{

bulkAliasRequest.Actions.Add(new AliasRemoveDescriptor().Index(indexName.Name).Alias(aliasName));

}

}

var result = _elasticClient.Indices.BulkAlias(bulkAliasRequest);

//续除原先的index

if (getAliasResult.IsValid)

{

var indeNameList = getAliasResult.Indices.Keys;

foreach (var indexName in indeNameList)

{

_elasticClient.Indices.Delete(indexName);

}

}

return result != null && result.ApiCall.Success ? ApiResult.IsSuccess() : ApiResult.IsFailed();

}

检索上端口这从前跟前面显然得差不多:

但是这从前有一个得之外注意的点,可以看到这个检索上端口同时运用于了should和must,这从前得设置minimumShouldMatch才能正常人像SQL过滤。

should可以理二阶已成SQL的Or,Must可以理二阶已成SQL的And。

预设确实会下minimumShouldMatch是等于0的,等于0的意思是,should不炮弹都任何的原始数据无论如何但会送回must炮弹都的原始数据,也就是你们确实希望查看(keyname.pinyin=’chengong‘ or keyname.standard=’chengong‘) and id> 0,但是es从前不能存留keyname='chengong'的原始数据,但会把id> 0 而且 keyname != 'chengong' 原始数据给检索借助于来。

因此我们得对minimumShouldMatch=1,就是should有条件需得假定炮弹都一个才能送回结果。

在should和must误用的确实会下需得注意minimumShouldMatch的设置!!!

///

/// 小真是查看列注记

///

///

///

[HttpPost]

[Route("search")]

public ApiResult> Get(SearchKeyGetRequest request)

{

var shouldQuerys = new List>();

int minimumShouldMatch = 0;

if (!request.KeyName.IsNullOrWhiteSpace())

{

shouldQuerys.Add(a => a.MatchPhrase(m => m.Field("key_name.pinyin").Query(request.KeyName)));

shouldQuerys.Add(a => a.MatchPhrase(m => m.Field("key_name.standard").Query(request.KeyName)));

minimumShouldMatch = 1;

}

var mustQuerys = new List>

{

a => a.Range(t => t.Field(f => f.Weight).GreaterThanOrEquals(0))

};

if (request.IsSubsidiary.HasValue)

mustQuerys.Add(a => a.Term(t => t.Field(f => f.IsSubsidiary).Value(request.IsSubsidiary.Value)));

if (request.SysTagIds != null && request.SysTagIds.Any())

mustQuerys.Add(a => a.Terms(t => t.Field(f => f.SysTagId).Terms(request.SysTagIds)));

if (request.EntityType.HasValue)

{

if (request.EntityType.Value == ESearchKey.EntityType.AllNovel)

{

mustQuerys.Add(a => a.Terms(t => t.Field(f => f.EntityType).Terms(ESearchKey.EntityType.Novel, ESearchKey.EntityType.ChatNovel, ESearchKey.EntityType.FanNovel)));

}

else

mustQuerys.Add(a => a.Term(t => t.Field(f => f.EntityType).Value((int)request.EntityType.Value)));

}

var sortDescriptor = new SortDescriptor();

sortDescriptor = request.Sort == ESearchKey.Sort.Weight

? sortDescriptor.Field(f => f.Weight, SortOrder.Descending)

: sortDescriptor.Field(f => f.ActiveDate, SortOrder.Descending);

var searchResult = _elasticClient.Search(a =>

a.Index(typeof(SearchKey).GetRelationName())

.From(request.Size * request.Page)

.Size(request.Size)

.Query(q => q.Bool(b => b.Should(shouldQuerys).Must(mustQuerys).MinimumShouldMatch(minimumShouldMatch)))

.Sort(s => sortDescriptor));

var apiResult = searchResult.GetApiResult>();

if (apiResult.Success)

return apiResult;

return ApiResult>.IsSuccess("OR原始数据");

}

十、APM监控

虽然在上头我做到了更多的二阶决问题马上,但是对于上制造后的其实运用于效果我还是希望有一个直觉的彰显。

在之后Corporation做到微增值的时候的APM选M-我们运用于了Skywalking,但是现在这家Corporation的运维不能接触过,但是对于Elastic Stack他相较相当熟悉,如同上文所真是核心所设计的转换已成已成核心为恰好:实现期望与许多组织核心,秉着我的系统所设计选M-原则是基于一个团队核心,我们有别于了Elastic APM + Kibana(7.4完整版),如下示意图所示:

仍要上制造的时候也是微小可用的待机到Elasticsearch,总体确实会都十分满意。

更是多内容

dbaplus小团体左右期一期直播【大规模资料库运维的所谓繁为简之术】将于5年末28日首播,vivo网络服务系统所设计一个团队将针对资料库过热衰老、战斗群扩容、敏感原始数据治理等话题来进行浅层探讨。通过上端元数据进入直播间,点击首播警告,精彩内容,不容错过!

直播元数据:

注目社会公众号【dbaplus小团体】,借助更是多原创系统所设计社论和精选电脑程式下载

武汉癫痫专家
漳州哪个妇科医院比较好
英太青缓释胶囊和扶他林缓释片哪个好
沈阳看男科去哪个医院好
肠胃不舒服怎么缓解
友情链接