HBase/Hive+Lily Indexer+solr踩坑总结

HBase/Hive+Lily Indexer+solr踩坑总结

  • 1号坑----大数据量的HBASE表往solr中刷历史索引需要关闭Lily,并根据rowkey分批运行MapReduce

踩坑情景:

我们有一张4亿条、300+字段的HBASE表需要针对30个字段在SOLR中建立二级索引,
在刷历史数的时候没有分批,直接运行了批量建索引的MR程序,导致SOLR直接被冲垮,无法提供服务。

原因:

由于需要处理的数据太多,并且当时还有几个实时往HBASE进数且往solr实时索引的表正在运行,
软提交设置的是15秒,这就会导致Lily不停地往solr commit数据,而MR批量导入的数据又过多,
SOLR就直接崩溃了,现在的配置为软提交1分钟,硬提交5分钟

解决办法:

我们的HBASE表是加盐的,有100个预分区,00-99,因此在运行批量建历史索引的MR程序是直接按分区来就行了,按预分区加上--hbase-start-row和--hbase-end-row 就行了。
	--reducers设置为0意味着没有reduce,只有Map,Map直接读取HBASE表数据处理好之后直接输出到SOLR建上索引。
	--go-live则是说solr会将离线索引的数据merge到running的collection中。
	当然也可以指定reducers,指定之后便会将数据处理成solr索引的格式的文件,然后将该文件直接merge到solr中,至于哪种方式好我也不好说,我比较倾向于reducer为0吧。
	详细信息可以看链接[Cloudera的解释还是很清楚的](https://www.cloudera.com/documentation/enterprise/latest/topics/search_hbase_batch_indexer.html#concept_z1c_cg3_ms)

脚本如下:

`echo "##########00 -- 10 start############"
echo `date`
hadoop --config /etc/hadoop/conf \
jar /opt/cloudera/parcels/CDH/lib/hbase-solr/tools/hbase-indexer-mr-job.jar \
--conf /etc/hbase/conf/hbase-site.xml \
--hbase-indexer-file $HOME/hbase-indexer/*****/morphline-hbase-mapper.xml \
--morphline-file morphlines.conf \
--zk-host *******:2181/solr \
--hbase-start-row 00 \
--hbase-end-row 10 \
--collection collectionName\
--reducers 0 \
--go-live
echo "###########00 -- 10 end#############"

wait
echo "##########10 -- 20 start############"
echo `date`
hadoop --config /etc/hadoop/conf \
jar /opt/cloudera/parcels/CDH/lib/hbase-solr/tools/hbase-indexer-mr-job.jar \
--conf /etc/hbase/conf/hbase-site.xml \
--hbase-indexer-file $HOME/hbase-indexer/*****/morphline-hbase-mapper.xml \
--morphline-file morphlines.conf \
--zk-host *******:2181/solr \
--hbase-start-row 10 \
--hbase-end-row 20 \
--collection collectionName\
--reducers 0 \
--go-live
echo "###########10 -- 20 end#############"
wait`

分区如下(仅截了一部分):
HBase/Hive+Lily Indexer+solr踩坑总结_第1张图片

- 2号坑----Morphlines对于Int类型的处理问题

踩坑情景:

  首先需要明确一点HBASE中都是Binary,没有类型之分。
  我们有一些Int类型的字段有时候会没数,若一上来就没数是没问题的,hbase中不会有这条记录。
  但悲催的是从有数变成没数,这时这个字段便会成为空。
  此时Lily根据morphlines的映射关系做处理时这条记录就进不去solr了,原因就是空无法转成int类型。

解决办法:

1、morphlines中有个findReplace,可以根据一些条件做判断转换,不过我没用,链接奉上:
[有兴趣的可以看看](http://kitesdk.org/docs/1.1.0/morphlines/morphlines-reference-guide.html#findReplace)
2、我们这边int用的比较少,也没几个字段,就牺牲性能了,改成了String类型。

- 3号坑----对于时间类型的处理问题

踩坑情景:

时间类型复杂多样,数据链路较长,数据源有MySQL、ORACLE、SQLServer、SAP等,时间格式也是各种各样,
前面ETL工作做的不够精细,没有处理成统一的格式。刚开始将HIVE的数据往HBASE中bulkload时也没注意这方面,
直接导致了后面从HBASE往SOLR中导的时候很多记录处理失败没建上索引。

解决办法:

在HIVE中做统一的时间格式,实时数据也要与HIVE中的时间格式保持一致。这个很重要,要不然以后用起来太麻烦了。
要提前规划好。在Morphlines配置convertTimestamp的时候多想一些自己系统可能出现的情况,我们这边用了四种:
即inputFormats中的四种:带时分秒的,只有年月日的,为空的,带毫秒的。这四种目前基本满足我们的需求了。
{
    convertTimestamp {
      field : "hsicrm_registrationtime"
      inputFormats : ["yyyy-MM-dd HH:mm:ss","yyyy-MM-dd","","yyyy-MM-dd HH:mm:ss.SSS"]
      inputTimezone : Asia/Shanghai
      outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
      outputTimezone : UTC
    }
  }

- 4号坑----将hive parquet表的数据批量导入到SOLR建立索引

Morphlines文件配置展示:

SOLR_LOCATOR : {
	# Name of solr collection
	collection : hive_test

	# ZooKeeper ensemble
	zkHost : "*****:2181/solr"
	}
	morphlines : [
	{
	id : shunguang_order_v1
	importCommands : ["org.kitesdk.**", "com.ngdata.**"]

	commands : [
	{
	readAvroParquetFile {
	# Optionally, use this Avro schema in JSON format inline for projection:
	# projectionSchemaString : """"""

	# Optionally, use this Avro schema file in JSON format for projection:
	# projectionSchemaFile : /path/to/syslog.avsc
	}
	}

	{
	extractAvroPaths {
	flatten : false
	paths : {    ##解释一下:"id:/row_id",左边的id是指solr中索引的主键,
	右边的row_id是指我选择hive表中row_id字段来作为solr索引的主键。下面的字段名则需要与schema.xml中
	对应起来,与hive的字段名一样就行了,不容易出错。
	id : /row_id
	siteid : /siteid
	istest : /istest
	paytime : /paytime
	isbackend : /isbackend
	}
	}
	}
	
	{
	convertTimestamp {  ##针对时间字段做一下转换。
		field : paytime
		inputFormats : ["yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd","","yyyy-MM-dd HH:mm:ss.SSS"]
		inputTimezone : Asia/Shanghai
		outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
		outputTimezone : UTC
		}
	}
	}


	{
		sanitizeUnknownSolrFields {
			# Location from which to fetch Solr schema
			solrLocator : ${SOLR_LOCATOR}
		}
	}

	# log the record at DEBUG level to SLF4J
	 { logInfo { format : "output record: {}", args : ["@{}"] } }
	{loadSolr {solrLocator : ${SOLR_LOCATOR}}}
	]
	}
	]

- 大坑来了----读取HDFS文件往SOLR批量建索引的两个工具

1、/opt/cloudera/parcels/CDH/jars/search-mr-*-job.jar,这个jar包是跑MapReduce批量建索引。
需要注意的是它只能用于初始化建历史索引,并不会对原有的索引数据做更新。比如你将pt=20190709分区共1万条
不重复的数用这个工具往solr建上了索引,然后你又运行了一遍脚本建了一遍,那solr里就成了2万条,
每一条都有俩索引记录,只是solr中的version版本号不同。
2、/opt/cloudera/parcels/CDH/lib/solr/contrib/crunch/search-crunch-1.0.0-cdh5.15.0.jar,
这个jar包是跑spark 1.6任务批量建索引。可以对原有索引数据做更新。假如你有一些增量表是按天更新的,那么用这个做增量脚本是个合适的选择。
3、/opt/cloudera/parcels/CDH/lib/solr/contrib/crunch/search-crunch-1.0.0-cdh5.15.0.jar,
哈哈,你没看错,跟第二个一样,只不过这个工具有两种运行方式,也可以用MapReduce的方式跑。具体怎么选择看你的环境。

1、/opt/cloudera/parcels/CDH/jars/search-mr-*-job.jar调用脚本

kinit -kt /home/***/***.keytab ****
hadoop --config /etc/hadoop/conf \
jar /opt/cloudera/parcels/CDH/jars/search-mr-*-job.jar org.apache.solr.hadoop.MapReduceIndexerTool \
-Dmapreduce.job.queuename=root.high \
--conf /etc/hadoop/conf.cloudera.hdfs/hdfs-site.xml \
--morphline-file morphlines.conf \
--morphline-id shunguang_order_v1 \
--solr-home-dir $HOME/hive-indexer/shunguang_order_v1 \
--output-dir hdfs://nameservice1/tmp/shunguang_order_v1 \
--zk-host ****:2181/solr \
--collection shunguang_order_v1 \
--go-live \
hdfs://nameservice1/hive/***/****/pt=1001/000001_0 hdfs://nameservice1/hive/***/****/pt=1001/000002_0 
##可以一次性处理多个hdfs文件,只不过需要将每个文件都罗列上,用空格分隔。
##如果你的集群开了kerberos,那么最好像我一样先kinit一下有对应权限的principal。

2、/opt/cloudera/parcels/CDH/lib/solr/contrib/crunch/search-crunch-1.0.0-cdh5.15.0.jar调用脚本

这个脚本是直接拿的Cloudera document中,直接就能用。
直接甩链接

kinit -kt ~/****.keytab ***
export HADOOP_CLASSPATH="/opt/cloudera/parcels/CDH/lib/search/lib/search-crunch/*"
export myMorphline=/home/dsj_solr/hive-indexer/shunguang_order_v1/morphlines_2.conf
export myResourcesDir=/opt/cloudera/parcels/CDH/share/doc/search-*/search-crunch
export myDriverJarDir=/opt/cloudera/parcels/CDH/lib/solr/contrib/crunch
export myDependencyJarDir=/opt/cloudera/parcels/CDH/lib/search/lib/search-crunch
export myDriverJar=$(find $myDriverJarDir -maxdepth 1 -name 'search-crunch-*.jar' ! -name '*-job.jar' ! -name '*-sources.jar')
export myDependencyJarFiles=$(find $myDependencyJarDir -name '*.jar' | sort | tr '\n' ',' | head -c -1)
export myDependencyJarPaths=$(find $myDependencyJarDir -name '*.jar' | sort | tr '\n' ':' | head -c -1)
#export myDependencyJarFiles=$(find $myDependencyJarDir -name '*.jar' | grep -v poi| sort | tr '\n' ',' | head -c -1)
#export myJVMOptions="-DmaxConnectionsPerHost=10000 -DmaxConnections=10000 -Djava.io.tmpdir=/tmp/dir/ -verbose:class -Djute.maxbuffer=102400000"
export myJVMOptions="-DmaxConnectionsPerHost=10000 -DmaxConnections=10000 -Djava.io.tmpdir=/tmp/dir/ -verbose:class -Djute.maxbuffer=102400000 -Dlog4j.configuration=./log4j_debug.conf"

echo "DriverJar":$myDriverJar
#echo "myDependencyJarFiles":$myDependencyJarFiles

spark-submit \
  --master yarn \
  --deploy-mode cluster \
  --jars $myDependencyJarFiles \
  --executor-memory 4G \
  --driver-memory 4G \
  --conf spark.executor.extraJavaOptions="$myJVMOptions" \
  --conf spark.executor.extraClassPath=/opt/cloudera/parcels/CDH/lib/search/lib/lucene-analyzers-common.jar \
  --conf spark.driver.extraJavaOptions="$myJVMOptions" \
  --conf spark.driver.extraClassPath=/opt/cloudera/parcels/CDH/lib/search/lib/lucene-analyzers-common.jar \
  --driver-java-options "$myJVMOptions" \
  --class org.apache.solr.crunch.CrunchIndexerTool \
  --files $myMorphline,log4j_debug.conf,/opt/cloudera/parcels/CDH/lib/search/lib/lucene-analyzers-common.jar \
  $myDriverJar \
  -D hadoop.tmp.dir=/tmp \
  -D morphlineVariable.ZK_HOST=***:2181/solr \
  --morphline-file morphlines_2.conf \
  --morphline-id shunguang_order_v1 \
  --pipeline-type spark \
  --chatty \
  --log4j log4j_debug.conf \
hdfs://nameservice1/hive/***/***/pt=1001/000013_0

#####MapReduce调用方法
hadoop \
  --config /etc/hadoop/conf.cloudera.yarn/ \
  jar $myDriverJar org.apache.solr.crunch.CrunchIndexerTool \
  --libjars $myDependencyJarFiles \
  -D mapreduce.map.memory.mb=12000 \
  -D mapreduce.reduce.memory.mb=12000 \
  -D morphlineVariable.ZK_HOST=***:2181/solr \
  -D mapreduce.input.fileinputformat.split.maxsize=64000000 \
  -D mapreduce.job.queuename=root.***\
  --files $myMorphline \
  --morphline-file morphlines_2.conf \
  --pipeline-type mapreduce \
  --chatty \
  --log4j $myResourcesDir/log4j.properties \
hdfs://nameservice1/hive/***/****/pt=1001/000013_0

你可能感兴趣的:(HBase/Hive+Lily Indexer+solr踩坑总结)