Elasticsearch趟坑记——后台数据篇

本文详述了一个项目中将HBase数据源切换到Elasticsearch的过程,包括使用hivetoES工具和Spark写入ES的挑战与解决方案。在数据写入阶段,讨论了_id的设置、字段命名规范以及性能优化,如通过HTTP请求和滚动扫描提升写入速率。在索引设置部分,提到了分片、副本、字段类型和其它参数对性能的影响。此外,还介绍了如何利用ES的别名机制保证在线服务的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:
项目隶属于用户画像服务,为了更好的支持前端查询服务,决定将原有的HBase数据源切换成Elasticsearch(以下简称ES),从k-v型数据库切到nosql。本以为是个比较简单的任务,做起来才发现有各种问题,简单记录下。

本文将从数据写入,索引设置两方面简述遇到的一些问题。
基本集群情况如下:三台ES,32G内存,其中16G内存分给ES,单台500G SSD。

数据写入
hive to ES
有专门的工具包,elasticsearch-hadoop-6.3.2.jar,需要注意的是后边的版本号需要和ES的版本一致。将hive表建成外部表,向外部表中写入数据即可。基本语句:

STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler'
TBLPROPERTIES(
'es.nodes' = '192.168.0.1',
'es.port'='9200',
'es.resource' = 'user_profile/user_profile',//表示ES的index/type
'es.mapping.id' = 'user_id',//指定_id的取值
'es.mapping.names' = 'name:NAME'//hive字段与ES字段的对应
)

有两个问题需要注意:

'es.mapping.id’手动设置,同一index/type的_id具有唯一性,可以进行数据去重,保证数据恢复时的幂等性等。但_id设计到ES的底层存储,需要足够离散,尽量不要用有规律的数字(类比HBase的Rowkey设计),以保证ES的性能,推荐用MD5之后的值作为_id,或用ES自己生成UUID。
hive表名与字段名称不敏感,而ES是敏感的,如果不指定es.mapping.names,导入的ES index的字段将会全部都为小写。这里推荐字段的命名采用下划线的方式以减少可能遇到的问题。
spark写入ES
简单的同步可以用外部表,但如果有一些复杂的逻辑计算,先将结果写入hive再导入ES肯定不是一个好方案,还有需求时从ES查询全量数据后将数据经过计算结果写回ES。对于上述任务,只能自己写代码了。ES提供了spark的访问的工具包。
libraryDependencies += “org.elasticsearch” % “elasticsearch-hadoop” % “6.3.2”
ES的节点配置写入到sparkconf中:


  val conf = new SparkConf().setAppName("UserProfile")
  conf.set("es.nodes", "192.168.0.01")
  conf.set("es.port", "9200")
  conf.set("es.index.auto.create", "true")
  conf.set("es.nodes.wan.only", "true")

读取写入如下:


  val result_rdd = sc.esRDD("user_profile/user_profile","{\"query\": {\"bool\": {\"must\": [{\"match\": {\"name\": \"test\"}}]}}}")

  EsSpark.saveToEs(result_rdd, "user_profile_new/user_profile_new")

上述代码为rdd与ES的交互,dataframe类似,不在赘述。

这几行代码也带来了本项目前期遇到的一个较大问题:性能,最初观察大概每10s左右有1K数据写入ES,这个效率是完全无法满足线上服务的要求的。经过排查发现是sc.esRDD这个读取的瓶颈,如果spark的并行读设置的足够大,则很容易将ES的cpu打满,如果不大则性能无法满足要求。应该esRDD这个底层实现机制导致,目前没去了解源码,有时间可以仔细排查下具体原因。

最终本项目的解决方案为用http请求替换sc.esRDD这个读入数据的方法,并通过游标的方式,获取全量的结果数据,最终代码如下:


  val url = "http://192.168.0.1:9200/user_profile/_search?_source=user_id&&scroll=1m"
  val response: HttpResponse[String] = Http(url).method("PUT").postData(x._2).header("Content-Type", "application/json;charset=utf-8").timeout(connTimeoutMs = 1000, readTimeoutMs = 600000).asString
  val parser = new JsonParser()
  val jsonstr = parser.parse(response.body).asInstanceOf[JsonObject]
  val json_array = jsonstr.getAsJsonObject("hits").get("hits").getAsJsonArray()
  val scroll_id = jsonstr.getAsJsonPrimitive("_scroll_id")//通过_scroll_id循环获取全量数据

循环内部代码:


  val parser = new JsonParser()
  val scroll_url = "http://192.168.0.1:9200/_search/scroll"
  val scroll_response: HttpResponse[String] = Http(scroll_url).method("PUT").postData("{ \"scroll\": \"1m\",\"scroll_id\":" + scroll_id + " }").header("Content-Type", "application/json;charset=utf-8").timeout(connTimeoutMs = 1000, readTimeoutMs = 600000).asString
  val scrol_jsonstr = parser.parse(scroll_response.body).asInstanceOf[JsonObject]
  val scroll_json_array = scrol_jsonstr.getAsJsonObject("hits").get("hits").getAsJsonArray()

最终测试结果,每分钟大约10W数据写入,初步满足要求。

索引设置
写入性能
上文简单说了下spark写入ES的性能问题,其实hive外部表导入时也会遇到性能瓶颈,简单介绍下我对索引做了哪些设置:
a、分片与副本:分片数最好为机器的整倍数。为了提高写入速度,可以先将副本数关闭,写入完成后再打开。这样写入时只会写入一个节点,可以大幅提高写入性能。打开副本数时,ES只会消耗网络与IO资源,不会占用cpu。副本数可以提高一定的搜索性能,理性设置。

curl -H "Content-Type: application/json" -XPUT ${str} -d'
{
    "settings" : {
        "index" : {
            "number_of_shards" : 3,//分片数
            "number_of_replicas" : 0.//副本数
        }
    }
}'

b、索引字段类型:hive外部表写入ES时,如果不指定索引字段的类型,hive中int会自动转成long,double会转成float,最好按需要先建索引,然后再建外部表。关于字段是否需要被索引也需要提前设置,默认是全加索引,这也非常影响写入性能与存储空间。
c、还有一些索引的参数配置,也会一定程度上影响写入速度。

"refresh_interval": "300s"//刷新间隔,默认1s,如果不要求写入数据实时被检索出来,加大之。
"translog.flush_threshold_size": "4096mb" //刷新的文件大小阈值
"index.translog.flush_threshold_ops:":1000000//日志多少条进行flush
"indices.store.throttle.max_bytes_per_sec" : "100mb"//加大merge速度

……
总的来说,分片与副本最影响性能,其次是字段是否需要索引。由于ES的研发思路就是开箱即用,默认配置以满足绝大多数场景,如果不是对ES有一定了解,尽量减少对参数的修改,有时会获得更好的性能。

在线服务
由于需要对外提供在线服务,如何保证数据更新时的服务也是一个问题。本项目采用了ES自带的别名机制,对外提供的永远是一个确定的名称。每天的数据写入为带时间戳的版本,当数据验证完成时,将新的表的别名设成提供服务的表名。

curl -H "Content-Type: application/json" -XPOST ${str} -d'
{
    "actions": [
        { "remove": { "index": "user_profile_'${1}'", "alias": "user_profile" }},
        { "add":    { "index": "user_profile_'${2}'", "alias": "user_profile" }}
    ]
}'//更改别名

ES默认提供了原子性的操作,保证了同时成功与失败。
本文简述了后台数据写入ES时遇到的一些问题与解决方案,后续为业务方提供基础的RPC服务也遇到了较多问题,有时间继续总结。
PS:不得不佩服ES的更新速度,在本项目进行的过程中ES就升级到了6.4.1,让我这种只喜欢用最新版本的,很难受。

<think>嗯,用户问的是“es后台启动”,我需要先弄清楚这里的“es”指的是什么。通常,“ES”可以代表多个技术相关的术语,最常见的是Elasticsearch,也可能是指Eclipse Scout或者其他东西。不过结合“后台启动”这个上下文,可能性最大的应该是Elasticsearch,因为它在服务器环境中经常需要以后台进程运行。 首先,我应该确认用户的环境,比如操作系统是Linux还是Windows。不过用户没有具体说明,可能需要给出两种系统的解决方案。但根据经验,Elasticsearch在Linux服务器上更常见,所以可能重点放在Linux上,但也要涵盖Windows的情况。 接下来,用户可能想知道如何将Elasticsearch作为后台服务启动,而不仅仅是前台运行。通常,直接运行elasticsearch命令会在前台启动,退出终端后进程就结束了,所以需要后台运行的方法。 对于Linux系统,常见的方法包括使用nohup配合&符号,或者使用systemd服务来管理。如果是使用tar.gz包安装的话,可能需要手动配置systemd服务文件。而如果是通过deb或rpm包安装的,可能已经自动配置好了systemd,可以直接使用systemctl命令。 然后,Windows系统的话,可能需要以服务的形式安装,使用--install参数,然后通过net start来启动。不过用户可能对Windows服务管理不太熟悉,需要给出具体步骤。 另外,用户可能没有明确说明是否已经安装Elasticsearch,或者是否配置了正确的环境变量。这时候可能需要提醒用户确保安装正确,并且JAVA_HOME设置正确,因为Elasticsearch依赖Java。 还有,后台启动之后,如何验证是否成功运行?可能需要告诉用户使用curl或者浏览器访问9200端口来检查状态。 可能还需要提到日志的位置,以便用户排查问题,比如在Linux下是logs目录,或者systemd的journalctl查看日志。 总结一下,回答的结构应该是先确认“es”指的是Elasticsearch,然后分Linux和Windows两种情况讲解后台启动的方法,包括使用nohup、systemd以及Windows服务的方式。然后给出验证方法和常见问题提示,比如Java环境、权限问题等。确保步骤清晰,用户能一步步操作,同时提醒需要注意的地方,比如防火墙设置或者配置文件修改。</think>关于“ES后台启动”,通常指的是Elasticsearch(分布式搜索和分析引擎)在服务器环境中以后台进程方式启动。以下是分步说明: ### 1. 确认环境 - **操作系统**:Linux/Unix系统或Windows系统 - **安装方式**:通过压缩包(tar.gz/zip)或包管理器(apt/yum)安装 --- ### 2. Linux/Unix系统后台启动方法 #### 方法一:使用 `nohup` 命令 ```bash # 进入Elasticsearch安装目录的bin文件夹 cd /path/to/elasticsearch/bin # 使用nohup后台启动(默认绑定本地地址,端口9200) nohup ./elasticsearch > /dev/null 2>&1 & ``` #### 方法二:通过Systemd服务(推荐) 1. 创建systemd服务文件: ```bash sudo nano /etc/systemd/system/elasticsearch.service ``` 2. 添加以下内容(根据实际路径修改): ```ini [Unit] Description=Elasticsearch After=network.target [Service] User=elasticsearch Group=elasticsearch ExecStart=/path/to/elasticsearch/bin/elasticsearch Restart=always LimitNOFILE=65536 [Install] WantedBy=multi-user.target ``` 3. 启动并设置开机自启: ```bash sudo systemctl daemon-reload sudo systemctl start elasticsearch sudo systemctl enable elasticsearch ``` --- ### 3. Windows系统后台启动 1. 以管理员身份打开CMD/PowerShell 2. 安装为服务: ```powershell cd C:\path\to\elasticsearch\bin .\elasticsearch-service.bat install ``` 3. 启动服务: ```powershell .\elasticsearch-service.bat start ``` --- ### 4. 验证是否启动成功 ```bash curl http://localhost:9200 # 或浏览器访问 http://服务器IP:9200 ``` 成功响应示例: ```json { "name" : "node-1", "cluster_name" : "elasticsearch", "version" : { ... } } ``` --- ### 5. 常见问题排查 - **权限问题**:Linux下需确保用户对Elasticsearch目录有读写权限。 - **Java环境**:需安装Java 8或更高版本,并设置`JAVA_HOME`环境变量。 - **端口冲突**:检查9200和9300端口是否被占用。 - **内存不足**:调整`config/jvm.options`中的堆内存参数(如`-Xms1g -Xmx1g`)。 --- 通过以上步骤,可确保Elasticsearch稳定运行于后台。建议优先使用systemd(Linux)或服务(Windows)管理,便于监控和自动重启。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值