biz confighash_mode一级散列二级散列query_configreturn hit 优化配置mempool配置join_config
在ha3 3.0 之前, indexlib 离线build,indexlib实时build索引, indexlib 索引加载, 以及在线检索相关的配置都揉在cluster 配置里面,cluster 配置比较复杂, 3.0 对这些逻辑进行了拆分:
indexlib 离线build 索引(全量增量), indexlib 实时build索引的配置独立出来放到离线的cluster 配置里面,文件名一般以app_cluster.json
indexlib 索引加载方式相关配置放到table的配置里面,文件命名一般也是cluster_name +"_cluster.json" ,与离线build配置文件通过文件夹路径进行区分;
在线检索相关配置在biz 配置中, 配置结构如下所述
biz config 结构
{
"cluster_config": {...},
"aggregate_sampler_config" : {...},
"rankprofile_config" : {...},
"summary_profile_config" : {...},
"function_config", : {...},
"searcher_cache_config" : {...},
"service_degradation_config" : {...}
}
cluster_config
cluster_config {
"hash_mode" : "",
"query_config" : "",
"join_config" : "",
"return_hit_rewrite_threshold" : "",
"return_hit_rewrite_ratio" : "",
"table_name" : "",
"pool_trunk_size: : 10,
"pool_recycle_size_limit" : 20,
}
文档的hash方式,用于决定将文档被归类到哪一个partition当中。 hash_field: 计算hash的字段, 一般使用pk 比较多, 当然也有例外,比方说inshop; hash_function: 目前支持三种hash方法,HASH、GALAXY_HASH、KINGSO_HASH。对于KINGSO_HASH,如果想修改kingSo的hash范围可以将此项配置成KINGSO_HASH#range的形式,必须配置;
例子:
"hash_mode":
{
"hash_field" : "nid",
"hash_function" : "HASH"
}
表示根据nid 字段使用HASH 方法计算hash值,进行分partition
首先介绍下HA3引擎的索引由全量(增量)和实时索引组成。 全量索引由build service(下文简称bs)构建,实时索引由searcher builder构建,两者都需要读取swift对应topic的文档进行build。索引文档的路由由bs的processor完成。它读取文档中在hash_mode配置的字段,通过hash函数计算得到一个值,其范围[0,65535],发送到swift相应的topic的分区中[0, 65535]。所以逻辑上索引共分2^16 逻辑partition, 编号是[0, 65535]。 用户可以指定最终生成的物理partition个数,引擎会自动把连续的逻辑partition映射到物理partition上。例如有2个物理partition的索引,包含的逻辑partition的区间分别是[0,32767]和[32768, 65535],同时订阅相同的swift topic分区就能获取相应的文档。在线查询时读取在线对应的hash_mode配置,进而查询指定的列。 有了上面的背景知识,我们先来说下一级散列,举个淘宝店铺内搜索的例子:hash_mode中配置hash_field为user_id(卖家id),大卖家的商品量远远大于其他小卖家所拥有的商品量,在bs processor构建的时候会将user_id计算一个hash值,热点主要表现为以下三点:1.bs processor计算hash之后,大卖家所在的builder和merger耗时会明显大于其他builder和merger,从而拖慢整体build进度;2.索引产出加载到引擎的不同列时,大卖家所在列的索引明显大于其他列,引擎需要为了热点扩大全部列的资源,造成了在线资源的浪费;3.查询也表现为大卖家所在的列查询量较多而出现查询热点。所以一级散列在这种情况下会导致build时间拉长,在线资源浪费和查询热点等问题。
二级散列是在一级散列的基础上拓展而来的功能,二级散列的作用是在一级散列的基础上,把一级散列到同一列的文档继续按照二级散列字段散列到不同的列上,比如店铺内搜索,二级散列中hash_fields配置为user_id(卖家ID)、nid(宝贝ID),一级散列是按照卖家分列,大卖家的宝贝都落在了引擎的一列上面,二级散列就是在按照卖家分列的基础上,再按照宝贝ID进行二级散列,这样大卖家的宝贝就会落在引擎的多列上。因为散列是在bs的processor中完成的,所以,1.bs的build和merge阶段的数据热点得以消除从而加快build速度;2.引擎中不同列数据不存在明显的热点,可以提升引擎整体的资源利用率;3.在查询时同样也会因查询分布到不同的列上,减少查询热点的出现。此功能在引擎3.7.2版本开始支持。 在autil中提供了二级列表函数ROUTING_HASH,其对应的新的hash_mode的配置如下:
"hash_mode" :
{
"hash_field" : "user_id",
"hash_fields" : ["user_id", "nid"],
"hash_function" : "ROUTING_HASH",
"hash_params" : {
"hash_func": "HASH",
"routing_ratio":"0.25",
"hot_ranges":"512-1536;8000-10000",
"hot_ranges_ratio":"0.25;0.5",
"hot_values":"t1;t2",
"hot_values_ratio":"0.3;0.4"
}
}
参数说明:
hash_field与hash_fields: 原先的hash_field仍支持,当hash_fields没有配置时,hash_filed的内容会动填入到hash_fields中。当hash_fields配置时,hash_field不生效,hash_field仍需要配置。
hash_function 仍支持原先的三种:HASH、GALAXY_HASH、KINGSO_HASH,新增了ROUTING_HASH作为二级散列。
hash_params是hash函数的配置参数,是个map<string, string>类型,在创建hash函数时会传入。例如使用HASH、GALAXY_HASH、KINGSO_HASH可以不用配置,ROUTING_HASH如果不配置,默认实现等同于HASH。
ROUTING_HASH的hash_params支持的配置项:
hash_func: 指定routing hash内部使用的hash函数,默认是HASH, 可以使用NUMBER_HASH方便测试
routing_ratio: 二级散列的覆盖率, 上述配置中内部二级散列值的计算是公式:
(HASH(user_id) %65536 + floor(HAHS(nid)%65536 * routing_ratio) )%65536
hot_ranges与hot_ranges_ratio:分别是热点散列值及对应的覆盖率,可以针对特定热点的散列中指定不同的覆盖率。主要应用场景是已知热点物理列,对应的0-65535间的散列值已知。
hot_values与hot_values_ratio:分别是热点卖家及对应的覆盖率,可以针对不同的大卖家设置不同的覆盖率。主要的应用场景是知道热点卖家的原始值。
注意hash mode中hash函数或hash_params的改动都会导致索引数据分布的改变,升级方案如下:
针对所有列都需要查询的场景,需要重建全量索引+更新qrs配置才能生效。
针对单列或有二级散列的场景,需要通过重建机群+重建全量索引,原因是qrs的hash配置可能与索引使用的hash配置不一致,导致在升级的过程中查询的列不正确。
检索(query)相关配置, 主要是设置默认检索的索引名, 查询多个词之间的默认关系以及是否开启multi_term 优化。
default_index
默认进行查询的索引名称,如果在query中未指明查询的索引名称时,将在该索引中查找; 比方说query=nid:1 指定了在nid索引下查找, query='mp3'未指定索引名称,会使用默认的index。
default_operator
查询多个单词时,多个单词之间缺省的关系。例如这里配置为“AND”即表示求多个单词查询结果的交集。像 "query=a b" 将被作为 "query=a AND b"进行查询。如果查询的时候单个语被分词器拆分成多个词,这多个词之间也是按照该配置项指定的关系进行查询;
multi_term_optimize
multi_term_optimize: 是否启用multiterm query 优化, 比方说a|b a&b之类的query,默认query 解析等价于a OR b, a AND b, 都是binary query,有两层,qrs 处理query 开销较大,尤其是|或者&的term 较多的情况,比方说主搜海选个性化召回query,开启这个优化选项之后会变成一个多term的单层query,通过op 标识是OR 还是AND逻辑。
例子: "query_config" : {
"default_index" : "phrase",
"default_operator" : "AND",
"multi_term_optimize" : true
},
表示默认查询的索引是phrase, 多关键默认关系是AND, 并且query解析开启multi_term优化。
优化searcher 序列化到qrs doc数的一组配置,默认情况qrs 查询searcher, searcher 需要返回start+hit个数个文档(searcher 排序出top(start+hit)), 当start+hit 比较大的时候searcher 序列化以及qrs 上反序列话成本比较大,事实上在多列场景每列数据分布较均匀, 适当减少searcher上返回的条数对最终整体效果基本没影响(保证所有searcher 返回的条数大于start+hit再乘以合适的系数), 在爬虫或者rank service架构下start+hit 往往比较大, 这个时候开启比较合适。
return_hit_rewrite_threshold : start + hit 大于这个阈值时, 开启这个优化;
return_hit_rewrite_ratio: 为了尽量不有损效果,searcher上实际排序出来的条数以及序列化之后的条数,(start+hit)/partition之后的值会按照业务场景乘以一个大于1的系数 限制条件:return_hit_rewrite_ratio 合理取值范围是(1,partition_count); 对于类似inshop 路由到单列的查询, 会自动不做这个优化处理;
优化后search上序列化的条数为(start+hit)/partition_count*return_hit_rewrite_ratio. 当列数越多的是以后优化效果越明显;
pool_trunk_size
用来控制pool分配的trunk大小,以M为单位,默认为10M。
pool_recycle_size_limit
触发pool回收的大小,以M为单位,默认为20M。
辅表相关配置,典型应用场景:宝贝数据除了存储宝贝本身信息外,还要存储会员维度(member)信息,如果不通过辅表的方案, 就要把所需要的会员信息冗余到宝贝上,同一会员的宝贝会都存储相同的信息(这个需要离线处理好),会浪费一些存储, 还有个问题就是会员信息更新的时候所有的宝贝都需要更新;另外一个方案则是通过辅表来实现, 宝贝和会员表分开索引, 在线的是时候通过会员表的pk(宝贝里面存储了member_id的正排,跟数据库机制类似), 查询得到对应的会员信息(当然具体实现上也有一些优化的手段,后面配置会说明), 这种方案的好处比较明显, 会员表没有冗余存储,更新也不成问题, 但是也有限制, 会员表信息不能作为检索条件, 只能用于过滤排序或者展示, 实际使用上可以做一些折中,将会员表中需要检索的字段冗余到宝贝表上, 其余的存储在辅表上。
join_infos 描述了当前cluster关联的辅表的信息
join_field 用于与辅表关联的字段。主表中的join_field有如下几个限制: a. join_field必须与辅表的关联字段完全一致 b. join_field目前不能是多值类型 c. join_field仅支持整数类型以及string类型 d. 辅表中的primary key索引字段必须是join_field
join_cluster 关联辅表的cluster name
strong_join 是否是强关联。当某次查询需要取该辅表的attribute时,若某篇doc关联失败( 即通过join attribute查辅表pk index失败),如果开启了强关联,则会丢弃该doc; 否则,默认会保留该doc,即使关联失败。
use_join_cache 是否开启join docid cache功能。join docid cache是主表docid到辅表docid的映射(可认为是一个特殊的attribute),对用户是透明的,用于辅表性能优化(开启了这个功能不需要再做辅表的pk 检索,直接在cache 中拿到辅表的docid)。从2.8版本开始每个join_cluster分别配置。
check_cluster_config 是否开启检查配置路径的功能,如果设为true,开启功能,会根据cluster_name去读取相应路径下的配置文件,如果关闭功能,则跳过读取配置文件,自动填充table_name为cluster_name。默认值为true。
配置例子:
"join_config" : {
"join_infos" : [
{
"join_field" : "company_id",
"join_cluster" : "company",
"strong_join" : true,
"use_join_cache" : true,
"check_cluster_config": true
}
]
},
aggregate_sampler_config
aggregate_sampler_config配置统计时的相关参数,支持2种统计模式:普通统计和批量统计, 通过aggBatchMode标识,这部分为可选配置,默认为普通统计模式。
普通统计是指每seek出一个结果就统计一次,它的参数含义如下:
"aggregate_sampler_config" :
{
"aggThreshold" : 0,
"sampleStep" : 1
}
aggThreshold 统计的阈值,当已经统计的个数小于这个数字时,抽样所有的。否则按照每sampleStep个数,抽取一次;
sampleStep 抽样统计时,每次抽样统计的跨度;
当aggBatchMode 为true时表示批量统计, 指seek出所有结果后再一次性统计,例子如下:
"aggregate_sampler_config" : {
"aggBatchMode" : true,
"aggThreshold" : 1000,
"batchSampleMaxCount" : 1000
}
批量统计开关
aggThreshold,批量统计的阈值,totalhits小于等于aggThreshold时,统计所有的结果。
totalhits大于aggThreshold时,批量统计的最大抽样个数,此时的步长公式是 (totalhits + batchSampleMaxCount - 1) / batchSampleMaxCount。
densemap功能开关
"aggregate_sampler_config" : {
"enableDenseMode" : false
}
enableDenseMode,值为"true"和"false",与性能有关的选项,根据业务特点选择开启或关闭。如果业务场景待统计的groupkey比较丰富,可以打开,性能会有提升。默认为"false"。
注:开启该选项前,务必要进行压测!
table_name
表名, 用于search上获取schema等;
rankprofile_config
主要负责定义算分的插件,这部分为可选配置,主要配置插件so 名称以及用到score 插件名称
modules.module_name 插件的模块名称
modules.module_path 插件动态链接库的名称
modeles.parameters 用户自定义参数,传递给插件的so使用
rankprofiles.rank_profile_name rank_profile名称,可以在查询语句中指定使用哪个.
rankprofiles.score_name so中score的名称
rankprofiles.total_rank_size 这个表示该scorer算分时接受的最大文档数量(单partition上要除以partition_count)
例子:
"rankprofile_config" : {
"modules" : [
{
"module_name" : "fake_scorer",
"module_path" : "libfakescorer.so",
"parameters" : {
"key" : "value"
}
}
],
"rankprofiles" : [
{
"rank_profile_name": "DefaultProfile",
"scorers" : [
{
"scorer_name" : "FakeScorer",
"module_name" : "fake_scorer",
"parameters" : {
"key" : "value"
},
"rank_size" : "300"
}
],
"field_boost" : {
"phrase.title" : 1000,
"phrase.body" : 100
}
}
]
}
summary_profile_config
required_attribute_fields summary返回结果中,不在summary_schema中的attribute字段;主要应用于辅表,即主表查询结果里返回辅表字段。
modules.module_name 插件的模块名称。
modules.module_path 插件动态链接库的名称。
modules.parameters 用户自定义参数,传递给插件的so使用。
summary_profiles.summary_profile_name summary_profile的名称,可以在查询语句中指定使用哪个。
summary_profiles.extractors summary extractor处理链的配置,extract summary时,按顺序过一遍所有的extractor。
summary_profiles.parameters 用户自定义参数,传递给summary_profile使用。
summary_profiles.field_configs 需要建立摘要的field的定义。
summary_profiles.max_summary_length highlight_prefix 可以指定关键字高亮显示,摘要的长度限制等。
配置例子:
"summary_profile_config" : {
"required_attribute_fields" : ["aux_field1", "aux_field2", "attr_field"],1
"modules" : [
{
"module_name" : "ha3_summary_eg",
"module_path" : "libha3_summary_eg.so",
"parameters" : {
"key" : "value"
}
}
],
"summary_profiles" : [
{
"summary_profile_name": "DefaultProfile",
"extractors" :[
{
"extractor_name" : "SmartSummaryExtractor",
"module_name" : "ha3_summary_eg",
"parameters" : {
"key": "value"
}
},
{
"extractor_name" : "DefaultSumamryExtractor",
"module_name" : "",
"parameters" : {}
}
],
"field_configs" : {
"TITLE" : {
"max_snippet" : 1,
"max_summary_length" : 40,
"highlight_prefix": "<font color=red>",
"highlight_suffix": "</font>",
"snippet_delimiter": "..."
},
"BODY" : {
"max_snippet" : 2,
"max_summary_length" : 100,
"highlight_prefix": "<font color=red>",
"highlight_suffix": "</font>",
"snippet_delimiter": "..."
}
}
}
]
}
function_config
配置集群用到的function_expression插件信息,这部分为可选配置。具体参数含义如下:
"function_config" :
{
"modules" : [
{
"module_name" : "func_module_name",
"module_path" : "libfunction_expression_plugin.so",
"parameters" :
{
"config_path" : "pluginsConf/one_function.json"
}
}
]
}
searcher_cache_config
searcher cache是用于cache第一阶段查询的结果
"searcher_cache_config" :
{
"max_size" : 1024, /* M byte */
"max_item_num" : 200000,
"inc_doc_limit" : 1000,
"inc_deletion_percent" : 1,
"latency_limit" : 1, /* ms */
"min_allowed_cache_doc_num" : 0,
"max_allowed_cache_doc_num" : 50000
}
max_size max_size用于指定Searcher Cache的最大内存使用空间,单位为 M 字节,默认值为 1024 M bytes。
max_item_num max_item_num用于指定Searcher Cache的初始化时item的个数。cache的底层是一个hash table,max_item_num用于初始化hash_table,而cache中实际的item个数是运行时根据实际的item大小和cache总的内存限制决定的,因此这个配置值只是一个帮助cache初始化的值,一般情况下可以忽略这个配置项,默认值是200000。
inc_doc_limit 在有增量的情况下,如果某个query命中了Searcher Cache,那么需要将cache中结果和在增量部分(相对于该query上一次进cache时增量的doc)中查询的结果进行合并后返回给用户,当从增量部分查到的结果数大于 inc_doc_limit 时,则将该query在cache中的结果主动失效,下次查询该query时重新填充cache。默认值是1000。
inc_deletion_percent 增量的删除会导致原本在cache中的部分结果可能已经失效(被删除或更新),当失效的doc占cache中缓存的结果总数的百分比超过 inc_deletion_percent% 时,同样需要将这个cache结果主动失效,而且当前这次查询会被当成是一次cache miss,从而重新查询当前query并填充cache。默认值是1。
latency_limit Searcher Cache只会缓存 (rank_latency + rerank_latency) > latency_limit 的query的查询结果,因为被cache住的query的latency越大,cache对性能提升的效果越明显。单位时ms,默认值是1ms。
min_allowed_cache_doc_num和max_allowed_cache_doc_num 分别用于设置允许进入cache的结果数的最小值、最大值,以便应对极端场景下走cache的开销,默认值是0和std::numeric_limits<uint32_t>::max()
service_degradation_config
service_degradation_config是控制服务降级的配置,用于在服务异常或者流量暴增的情况下维护系统的稳定运作,示例如下:
"service_degradation_config" :
{
" condition" : {
"worker_queue_size_degrade_threshold" : 100,
"worker_queue_size_recover_threshold" : 10,
"duration" : 1000
},
"request" : {
"rank_size" : 5000,
"rerank_size" : 200
}
}
配置服务降级主要分为两部分,服务降级的检测标准以及判断为服务降级后的降级措施:
检测标准:检测服务需要降级的主要依据是当前worker的工作队列长度,当长度持续duration ms大于worker_queue_size_degrade_threshold时,服务进入降级状态,在降级状态下持续duration ms小于worker_queue_size_recover_threshold时,恢复为不降级状态。特别的,在降级状态下,如果队列长度小于worker_queue_size_recover_threshold,则该query不降级,这样在降级状态下队列长度会在worker_queue_size_recover_threshold上下波动。
降级措施:目前只支持改写请求的rank_size以及rerank_size,即粗排和精排的条数,通过减小计算规模来降低请求的消耗时间,在rank_service架构下只有rank_size 生效。
multi_call_config
ha3 3.2.0之前的版本参考如下流控配置,从3.2.0开始流控逻辑做了较大重构,字段由"anomaly_process_config"改为"multi_call_config",例如:
"multi_call_config" : {
"probe_percent" : 0.3,
"latency_upper_limit_percent" : 0.4,
"begin_degrade_latency" : 100,
"full_degrade_latency" : 150,
"et_trigger_percent" : 0.8,
"et_wait_time_factor" : 5,
"et_min_wait_time" : 30,
"retry_trigger_percent" : 0.6,
"retry_wait_time_factor" : 3
}
具体配置选项参考gig文档。老版本配置说明如下: 服务稳定性可以在每个cluster里单独配置,具体的配置项如下:
"anomaly_process_config" :
{
"flowControlEnabled" : true,
"earlyTerminationEnabled" : true,
"retryQueryEnabled" : true,
"flowControl" : {
"sample_interval" : 100,
"min_sample_count" : 10,
"heavy_load_arpc_error_ratio" : 0.5,
"light_load_arpc_error_ratio" : 0,
"max_flow_redirect" : 1,
"queue_size_threshold" : 5,
"flow_control_categories" : [1,2,3,4,5,6,7,8,9,10,11]
},
"detection" : {
"early_termination_trigger_result_percent" : 0.8,
"early_termination_wait_time_factor" : 3,
"retry_query_trigger_result_percent" : 0.8,
"retry_query_wait_time_factor" : 1
}
}
searcher流量控制功能开关
查询提前结束功能开关
重查功能开关
流量控制的相关配置,目前其也包含searcher健康状态监控的相关参数
健康状态的更新间隔,单位ms
最少需要sample查询个数。这个参数主要判断ARPC错误的比例,如果一个健康状态更新间隔现,查询数量不够,则继续累积。
当ARPC查询错误个数大于这个比例时,searcher的健康状态需要降级。
当ARPC查询错误个数小于这个比例时,searcher的健康状态需要升级。
最多找备份searcher的个数。当一列中的一个searcher处理不健康时,需要把分配给这个searcher的部分流量导到其它同列searcher中。这个参数决定当找多个同列searcher的结点仍没有找到健康结点时,则丢失流量
queue_size是每次查询从searcher机器上带回来searcher的队列长度。根据这个队列长度,QRS或PROXY会更新searcher的健康状态。这个值主要用于配置searcher健康状态更改需要满足条件。具体的算法如下:searcher的健康状态共为11级,每一级健康状态的更新条件是不一样的。例如示例中queue_size_threshold为5,其健康状态更新的队列长度对应的数组为q=[5,10,15,20,25,30,35,40,45,50,55], searcher健康度降级:queue_size >= q[10-H_c+1], searcher健康度升级:queue_size < q[10-H_c],其中H_c是searcher当前处于健康值0<= H_c <= 10
健康状态更新的队列长度对应数组的高级控制配置项,<10>是一个简单线性展开的配置方法。当配置这个数组时,将覆盖<10>
配置触发查询提前结束检测应满足的结果个数比例,例如查10列的内容,如果8列结果已经返回,则开始触发查询提前结果检测。
查询提前结束应等待的时间。假设查询提前结束检测被触发时使用的时间为T,如果再等待3t的时间,结果还不完整,则这时会提前结束查询处理并返回结果。如果在等待的期间结果已经完整,则结果正常返回。t为第一个正常返回结果所需的时间。
配置触发查询重查检测应满足的结果个数比例,例如查10列的内容,如果8列结果已经返回,则开始触发重查检测。
配置查询重查应等待的时间。假设查询重查检测被触发时使用的时间为T,如果再等待t的时间,结果还不完整,则这时会向同列另一个searcher发送查询请求。如果在等待的期间结果已经完整,则结果正常返回。t为第一个正常返回结果所需的时间。
cava_config
ha3 高级语言脚本相关配置, ha3 支持用户通过cava脚本写插件,下面是相关配置
"cava_config" : {
"enable" : true, (1)
"ha3_cava_conf" : "../binary/usr/local/etc/cava/config/cava_config.json", (2)
"lib_path" : "cava/lib",(3)
"source_path" : "cava/src",(4)
"code_cache_path" : "cava/cache",(5)
"pool_trunk_size" : 10, //MB (6)
"pool_recycle_size_limit" : 20, //MB (7)
"alloc_size_limit" : 40, //MB (8)
"init_size_limit" : 1024, //MB (9)
"module_cache_size" : 100000 (10)
}
(1)是否启用cava功能
(2)cava语言配置
(3)平台方提供的公共库,upc时编译生效
(4)业务方提供的自定义插件,可以复用平台方提供的公共库,upc时编译生效
(5)提前编译进code cache的插件代码,不会被cache淘汰,并且不能被别人引用
(6)cava内存池trunk_size,默认值10MB,无需用户修改
(7)cava内存池recycle_size,默认值20MB,无需用户修改
(8)cava query级别能分配的最大内存
(9)cava 整体最多可以使用多大内存,不包括上述query级别的内存
(10)最多缓存query里面传递source code的个数,超过则开始LRU淘汰
关于cava 的详细介绍后续会有单独章节来介绍
turing_options_config
turing_options_config可以覆盖图化相关的配置例如
"turing_options_config":{ "graph_config_path": “ssss”, // 图的路径 "dependency_table":[“a”,"b"] //依赖表等 }