qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

Elasticsearch Java虚拟机配置详解

ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。支持通过HTTP使用JSON进行数据索引。
  我们建立一个网站或应用程序,并要添加搜索功能,令我们受打击的是:搜索工作是很难的。我们希望我们的搜索解决方案要快,我们希望 有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP的索引数据,我们希望我们的搜索服务器始终可用,我们希望能够一台开 始并扩展到数百,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。Elasticsearch旨在解决所有这些问题和更多的。
  安装
  以windows操作系统和ES0.19.7版本为例:
  ①下载elasticsearch-0.19.7.zip
  ②直接解压至某目录,设置该目录为ES_HOME环境变量
  ③安装JDK,并设置JAVA_HOME环境变量
  ④在windows下,运行 %ES_HOME%\bin\elasticsearch.bat即可运行
  分布式搜索elasticsearch单机与服务器环境搭建
  先到http://www.elasticsearch.org/download/下 载最新版的elasticsearch运行包,本文写时最新的是0.19.1,作者是个很勤快的人,es的更新很频繁,bug修复得很快。下载完解开有三 个包:bin是运行的脚本,config是设置文件,lib是放依赖的包。如果你要装插件的话就要多新建一个plugins的文件夹,把插件放到这个文件 夹中。
  1.单机环境:
  单机版的elasticsearch运行很简单,linux下直接 bin/elasticsearch就运行了,windows运行bin/elasticsearch.bat。如果是在局域网中运行elasticsearch集群也是很简单的,只要cluster.name设置一致,并且机器在同一网段下,启动的es会自动发现对方,组成集群。
  2.服务器环境:
  如果是在服务器上就可以使用elasticsearch-servicewrapper这个es插件,它支持通过参数,指定是在后台或前台运行es,并且支持启动,停止,重启es服务(默认es脚本只能通过ctrl+c关闭es)。使用方法是到https://github.com/elasticsearch/elasticsearch-servicewrapper下载service文件夹,放到es的bin目录下。下面是命令集合:
bin/service/elasticsearch +
console 在前台运行es
start 在后台运行es
stop 停止es
install 使es作为服务在服务器启动时自动启动
remove 取消启动时自动启动
  在service目录下有个elasticsearch.conf配置文件,主要是设置一些java运行环境参数,其中比较重要的是下面的
  参数:
#es的home路径,不用用默认值就可以
set.default.ES_HOME=<Path to ElasticSearch Home>
#分配给es的最小内存
set.default.ES_MIN_MEM=256
#分配给es的最大内存
set.default.ES_MAX_MEM=1024
# 启动等待超时时间(以秒为单位)
wrapper.startup.timeout=300
# 关闭等待超时时间(以秒为单位)
wrapper.shutdown.timeout=300
# ping超时时间(以秒为单位)
wrapper.ping.timeout=300
  安装插件
  以head插件为例:
  联网时,直接运行%ES_HOME%\bin\plugin -install mobz/elasticsearch-head
  不联网时,下载elasticsearch-head的zipball的master包,把内容解压到%ES_HOME%\plugin\head\_site目录下,[该插件为site类型插件]
  安装完成,重启服务,在浏览器打开 http://localhost:9200/_plugin/head/ 即可
  ES概念
  cluster
  代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说 的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通 信和与整个es集群通信是等价的。
  shards
  代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
  replicas
  代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当个某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
  recovery
  代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。


 river
  代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服 务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia 的。
  gateway
  代表es索引的持久化存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到硬盘。当这个es集群关闭再 重新启动时就会从gateway中读取索引数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和 amazon的s3云存储服务。
  discovery.zen
  代表es的自动发现节点机制,es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
  Transport
  代表es内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。
  分布式搜索elasticsearch中文分词集成
  elasticsearch官方只提供smartcn这个中文分词插件,效果不是很好,好在国内有medcl大神(国内最早研究es的人之一)写的两个中文分词插件,一个是ik的,一个是mmseg的,下面分别介绍下两者的用法,其实都差不多的,先安装插件,命令行:
  安装ik插件:
  plugin -install medcl/elasticsearch-analysis-ik/1.1.0
  下载ik相关配置词典文件到config目录
  cd config
  wget http://github.com/downloads/medcl/elasticsearch-analysis-ik/ik.zip --no-check-certificate
  unzip ik.zip
  rm ik.zip
  安装mmseg插件:
  bin/plugin -install medcl/elasticsearch-analysis-mmseg/1.1.0
  下载相关配置词典文件到config目录
  cd config
  wget http://github.com/downloads/medcl/elasticsearch-analysis-mmseg/mmseg.zip --no-check-certificate
  unzip mmseg.zip
  rm mmseg.zip
  分词配置
  ik分词配置,在elasticsearch.yml文件中加上
  index:
  analysis:
  analyzer:
  ik:
  alias: [ik_analyzer]
  type: org.elasticsearch.index.analysis.IkAnalyzerProvider
  或
  index.analysis.analyzer.ik.type : “ik”
  这两句的意义相同
  mmseg分词配置,也是在在elasticsearch.yml文件中
  index:
  analysis:
  analyzer:
  mmseg:
  alias: [news_analyzer, mmseg_analyzer]
  type: org.elasticsearch.index.analysis.MMsegAnalyzerProvider
  或
  index.analysis.analyzer.default.type : "mmseg"
  mmseg分词还有些更加个性化的参数设置如下
index:
analysis:
tokenizer:
mmseg_maxword:
type: mmseg
seg_type: "max_word"
mmseg_complex:
type: mmseg
seg_type: "complex"
mmseg_simple:
type: mmseg
seg_type: "simple"
  这样配置完后插件安装完成,启动es就会加载插件。

 定义mapping
  在添加索引的mapping时就可以这样定义分词器
{
"page":{
"properties":{
"title":{
"type":"string",
"indexAnalyzer":"ik",
"searchAnalyzer":"ik"
},
"content":{
"type":"string",
"indexAnalyzer":"ik",
"searchAnalyzer":"ik"
}
}
}
}
  indexAnalyzer为索引时使用的分词器,searchAnalyzer为搜索时使用的分词器。
  java mapping代码如下:
XContentBuilder content = XContentFactory.jsonBuilder().startObject()
.startObject("page")
.startObject("properties")
.startObject("title")
.field("type", "string")
.field("indexAnalyzer", "ik")
.field("searchAnalyzer", "ik")
.endObject()
.startObject("code")
.field("type", "string")
.field("indexAnalyzer", "ik")
.field("searchAnalyzer", "ik")
.endObject()
.endObject()
.endObject()
.endObject()
  定义完后操作索引就会以指定的分词器来进行分词。
  附:
  ik分词插件项目地址:https://github.com/medcl/elasticsearch-analysis-ik
  mmseg分词插件项目地址:https://github.com/medcl/elasticsearch-analysis-mmseg
  如果觉得配置麻烦,也可以下载个配置好的es版本,地址如下:https://github.com/medcl/elasticsearch-rtf
  elasticsearch的基本用法
  最大的特点:
  1. 数据库的 database, 就是  index
  2. 数据库的 table,  就是 tag
  3. 不要使用browser, 使用curl来进行客户端操作.  否则会出现 java heap ooxx...
  curl:  -X 后面跟 RESTful :  GET, POST ...
  -d 后面跟数据。 (d = data to send)
  1. create:
  指定 ID 来建立新记录。 (貌似PUT, POST都可以)
  $ curl -XPOST localhost:9200/films/md/2 -d '
  { "name":"hei yi ren", "tag": "good"}'
  使用自动生成的 ID 建立新纪录:
  $ curl -XPOST localhost:9200/films/md -d '
  { "name":"ma da jia si jia3", "tag": "good"}'
  2. 查询:
  2.1 查询所有的 index, type:
  $ curl localhost:9200/_search?pretty=true
  2.2 查询某个index下所有的type:
  $ curl localhost:9200/films/_search
  2.3 查询某个index 下, 某个 type下所有的记录:
  $ curl localhost:9200/films/md/_search?pretty=true
  2.4 带有参数的查询:
  $ curl localhost:9200/films/md/_search?q=tag:good
  {"took":7,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":2,"max_score":1.0,"hits":[{"_index":"film","_type":"md","_id":"2","_score":1.0, "_source" :
  { "name":"hei yi ren", "tag": "good"}},{"_index":"film","_type":"md","_id":"1","_score":0.30685282, "_source" :
  { "name":"ma da jia si jia", "tag": "good"}}]}}
  2.5 使用JSON参数的查询: (注意 query 和 term 关键字)
  $ curl localhost:9200/film/_search -d '
  {"query" : { "term": { "tag":"bad"}}}'
  3. update
  $ curl -XPUT localhost:9200/films/md/1 -d { ...(data)... }
  4. 删除。 删除所有的:
  $ curl -XDELETE localhost:9200/films
  引言:
  今天,事情终于发生了。Java6(Mustang),是2006年早些时候出来的,至今仍然应用在众多生产环境中,现在终于走到了尽头。已经没有什么理由阻止迁移到Java7(Dolphin)上了。
  这也促使我想写一篇关于在ElasticSearch上配置Java6和7的细微差异的博文。
  Elasticsearch对Java虚拟机进行了预先的配置。通常情况下,因为这些配置的选择还是很谨慎的,所以你不需要太关心,并且你能立刻使用ElasticSearch。
  但是,当你监视ElasticSearch节点内存时,你可能尝试修改一些配置。这些修改是否会改善你的处境?
  这篇博文尝试揭开Elasticsearch配置的神秘面纱,并且讨论最常见的调整。最终,会给出一些推荐的配置调整。
  Elasticsearch JVM 配置概览:
  这些是Elasticsearch 0.19.11版本的默认配置。
  JVM参数 Elasticsearch默认值 Environment变量
-Xms 256m ES_MIN_MEM
-Xmx 1g ES_MAX_MEM
-Xms and -Xmx   ES_HEAP_SIZE
-Xmn   ES_HEAP_NEWSIZE
-XX:MaxDirectMemorySize   ES_DIRECT_SIZE
-Xss 256k
-XX:UseParNewGC +
-XX:UseConcMarkSweepGC +
-XX:CMSInitiatingOccupancyFraction 75
-XX:UseCMSInitiatingOccupancyOnly +
-XX:UseCondCardMark (commented out)
  首先你注意到的是,Elasticsearch预留了256M到1GB的堆内存。
  这个设置适用于开发和演示环境。开发人员只需要简单的解压发行包,再执行./bin/elasticsearch -f就完成了Elasticsearch的安装。当然这点对于开发来说非常棒,并且在很多场景下都能工作,但是当你需要更多内存来降低Elasticsearch负载的时候就不行了,你需要比2GB RAM更多的可用内存。
  ES_MIN_MEM/ES_MAX_MEM是控制堆大小的配置。新的ES_HEAP_SIZE变量是一个更为便利的选择,因为将堆的初始大小和最大值设为相同。也推荐在分配堆内存时尽可能不要用内存的碎片。内存碎片对于性能优化来说非常不利。
  ES_HEAP_NEWSIZE是可选参数,它控制堆的子集大小,也就是新生代的大小。
  ES_DIRECT_SIZE控制本机直接内存大小,即JVM管理NIO框架中使用的数据区域大小。本机直接内存可以被映射到虚拟地址空间上,这样在64位的机器上更高效,因为可以规避文件系统缓冲。Elasticsearch对本机直接内存没有限制(可能导致OOM)。
  由于历史原因Java虚拟机有多个垃圾收集器。可以通过以下的JVM参数组合启用:
JVM parameter Garbage collector
-XX:+UseSerialGC serial collector
-XX:+UseParallelGC parallel collector
-XX:+UseParallelOldGC Parallel compacting collector
-XX:+UseConcMarkSweepGC Concurrent-Mark-Sweep (CMS) collector
-XX:+UseG1GC Garbage-First collector (G1)
  UseParNewGC和UseConcMarkSweepGC组合启用垃圾收集器的并发多线程模式。UseConcMarkSweepGC自动选择UseParNewGC模式并禁用串行收集器(Serial collector)。在Java6中这是默认行为。
  CMSInitiatingOccupancyFraction提炼了一种CMS(Concurrent-Mark-Sweep)垃圾收集设置;它将旧生代触发垃圾收集的阀值设为75.旧生代的大小是堆大小减去新生代大小。这告诉JVM当堆内容达到75%时启用垃圾收集。这是个估计的值,因为越小的堆可能需要越早启动GC。
  UseCondCardMark将在垃圾收集器的card table使用时,在marking之前进行额外的判断,避免冗余的store操作。UseCondCardMark不影响Garbage-First收集器。强烈推荐在高并发场景下配置这个参数(规避card table marking技术在高并发场景下的降低吞吐量的负面作用)。在ElasticSearch中,这个参数是被注释掉的。
  有些配置可以参考诸如Apache Cassandra项目,他们在JVM上有类似的需求。
  总而言之,ElastciSearch配置上推荐:
  1. 不采用自动的堆内存配置,将堆大小默认最大值设为1GB
  2.调整触发垃圾收集的阀值,比如将gc设为75%堆大小的时候触发,这样不会影响性能。
  3.禁用Java7默认的G1收集器,前提是你的ElasticSearch跑在Java7u4以上的版本上。
 JVM进程的内存结果
  JVM内存由几部分组成:
  Java代码本身:包括内部代码、数据、接口,调试和监控代理或者字节码指令
  非堆内存:用于加载类
  栈内存:用于为每个线程存储本地变量和操作数
  堆内存:用于存放对象引用和对象本身
  直接缓冲区:用于缓冲I/O数据
  堆内存的大小设置非常重要,因为Java的运行依赖于合理的堆大小,并且JVM需要从操作系统那获取有限的堆内存,用于支撑整个JVM生命周期。
  如果堆太小,垃圾回收就会频繁发生,发生OOM的几率会很大。
  如果堆太大,垃圾回收会延迟,但是一旦回收,就需要处理大量的存活堆数据。并且,操作系统的压力也会变大,因为JVM进程需要更大的堆,产生换页的可能性就会提高。
  注意,使用CMS垃圾收集器,Java不会把内存还给操作系统,因此配置合理的堆初始值和最大值就非常重要。
  非堆内存由Java应用自动分配。没有什么参数控制这里的大小,这是由Java应用程序代码自己决定的。
  栈内存在每个线程中分配,在Elasticsearch中,每个线程大小必须由128K增加到256K,因为Java7比Java6需要更大的栈内存 ,这是由于Java7支持新的编程语言特征来利用栈空间。比如,引入了continuations模型,编程语言的一个著名概念。Continuations模型对于
  协同程序、绿色线程(green thread)、纤程(fiber)非常有用 。当实现非阻塞I/O时,一个大的优势是,代码可以根据线程实际使用情况编写,但是运行时仍然在后台采用非阻塞I/O。Elasticsearch使用了多个线程池,因为Netty I/O框架和Guava是Elasticsearch的基础组件,因此在用Java7时,可以考虑进一步挖掘优化线程的特性。
  发挥增加栈空间大小的优势还是有挑战的,因为不同的操作系统、不同的CPU架构,甚至在不同的JVM版本之间,栈空间的消耗不是容易比较的。取决于CPU架构和操作系统,JVM的栈空间大小是内建的。他们是否在所有场景下都适合?例如Sloaris Sparc 64位的JVM Xss默认为512K,因为有更大地址指针,Sloaris X86为320K。Linux降为256K。Windows 32位Java6默认320K,Windows 64位则为1024K。
  大堆的挑战
  今天,几GB的内存是很常见的。但是在不久以前,系统管理员还在为多几G的内存需求泪流满面。
  Java垃圾收集器是随着2006年的Java6的出现而显著改进的。从那以后,可以并发执行多任务,并且减少了GC停顿几率: stop - the - world阶段。CMS算法是革命性的,多任务,并发, 不需要移动的GC。但是不幸的是,对于堆的存活数据量来说,它是不可扩展的。Prateek Khanna 和 Aaron Morton给出了CMS垃圾收集器能够处理的堆规模的数字。
  避免Stop-the-world阶段
  我们已经学习了Elasticsearch如何配置CMS垃圾收集器。但这并不能组织长时间的GC停顿,它只是降低了发生的几率。CMS是一个低停顿几率的收集器,但是仍然有一些边界情况。当堆上有MB级别的大数组,或者其他一些特殊的场景,CMS可能比预期要花费更多的时间。
  MB级别数组的创建在Lucene segment-based索引合并时是很常见的。如果你希望降低CMS的额外负载,就需要调整Lucene合并阶段的段数量,使用参数index.merge.policy.segments_per_tier
  减少换页
  大堆的风险在于内存压力上。注意,如果Java JVM在处理大堆时,这部分内存对于系统其它部分来说是不可用的。如果内存吃紧,操作系统会进行换页,并且,在紧急情况下,当所有其他方式回收内存都失败时,会强制杀掉进程。如果换页发生,整个系统的性能会下降,自然GC的性能也跟着下降。所以,不要给堆分配太多的内存。
  垃圾收集器的选择
  从Java JDK 7u4开始,Garbage-First(G1)收集器是Java7默认的垃圾收集器。它适用于多核的机器以及大内存。它一方面降低了停顿时间,另一方面增加了停顿的次数。整个堆的操作,例如全局标记,是在应用线程中并发执行的。这会防止随着堆或存活数据大小的变化,中断时间也成比例的变化。
  G1收集器目标是获取更高的吞吐量,而不是速度。在以下情况下,它能运行的很好:
  1. 存活数据占用了超过50%的Java堆
  2. 对象分配比例或者promotion会有明显的变化
  3. 不希望gc或者compaction停顿时间长(超过0.5至1s)
  注意,如果使用G1垃圾收集器,堆不再使用的内存可能会被归还给操作系统
  G1垃圾收集器的不足是CPU使用率越高,应用性能越差。因此,如果在内存足够和CPU能力一般的情况下,CMS可能更胜一筹。
  对于Elasticsearch来说,G1意味着没有长时间的stop-the-world阶段,以及更灵活的内存管理,因为buffer memory和系统I/O缓存能更充分的利用机器内存资源。代价就是小成本的最大化性能,因为G1利用了更多CPU资源。
  性能调优策略
  你读这篇博文因为你希望在性能调优上得到一些启示:
  1. 清楚了解你的性能目标。你希望最大化速度,还是最大化吞吐量?
  2. 记录任何事情(log everything),收集统计数据,阅读日志、分析事件来诊断配置
  3. 选择你调整的目标(最大化性能还是最大化吞吐量)
  4. 计划你的调整
  5. 应用你的新配置
  6. 监控新配置后的系统
  7. 如果新配置没有改善你的处境,重复上面的一系列动作,反复尝试
  Elasticsearch垃圾收集日志格式
  Elasticsearch长时间GC下warns级别的日志如下所示:
[2012-11-26 18:13:53,166][WARN ][monitor.jvm              ] [Ectokid] [gc][ParNew][1135087][11248] duration [2.6m], collections [1]/[2.7m], total [2.6m]/[6.8m], memory [2.4gb]->[2.3gb]/[3.8gb], all_pools {[Code Cache] [13.7mb]->[13.7mb]/[48mb]}{[Par Eden Space] [109.6mb]->[15.4mb]/[1gb]}{[Par Survivor Space] [136.5mb]->[0b]/[136.5mb]}{[CMS Old Gen] [2.1gb]->[2.3gb]/[2.6gb]}{[CMS Perm Gen] [35.1mb]->[34.9mb]/[82mb]}
  JvmMonitorService类中有相关的使用方式:
Logfile Explanation
gc 运行中的gc
ParNew new parallel garbage collector
duration 2.6m gc时间为2.6分钟
collections [1]/[2.7m] 在跑一个收集,共花2.7分钟
memory [2.4gb]->[2.3gb]/[3.8gb] 内存消耗, 开始是2.4gb, 现在是2.3gb, 共有3.8gb内存
Code Cache [13.7mb]->[13.7mb]/[48mb] code cache占用内存
Par Eden Space [109.6mb]->[15.4mb]/[1gb] Par Eden Space占用内存
Par Survivor Space [136.5mb]->[0b]/[136.5mb] Par Survivor Space占用内存
CMS Old Gen [2.1gb]->[2.3gb]/[2.6gb] CMS Old Gen占用内存
CMS Perm Gen [35.1mb]->[34.9mb]/[82mb] CMS Perm Gen占用内存
JvmMonitorSer
  一些建议
  1. 不要在Java 6u22之前的发布版本中跑Elasticsearch。有内存方面的bug。那些超过两三年的bug和缺陷会妨碍Elasticsearch的正常运行。与旧的OpenJDK 6相比,更推荐Sun/Oracle的版本,因为后者修复了很多bug。
  2. 放弃Java6,转到Java7。Oracle宣称Java6更新到2013年2月结束。考虑到Elasticsearch还是一个相对新的软件,应该使用更新的技术来提升性能。尽量从JVM中挤压性能。检查操作系统的版本。在最新版本的操作系统中运行,有助于你的Java运行环境达到最佳性能。
  3. 定期更新Java运行环境。平均一个季度一次。告诉sa你需要及时更新Java版本,以获取Java性能的提升。
  4. 从小到大。先在Elasticsearch单节点上进行开发。但是不要忘了Elasticsearch分布式的强大功能。单节点不能模拟生产环境的特征,至少需要3个节点进行开发测试。
  5. 在调整JVM之前先做一下性能测试。对你的系统建立性能基线。调整测试时候的节点数量。如果索引时候负载很高,你可能需要降低Elasticsearch索引时候占用的堆大小,通过index.merge.policy.segments_per_tierparameter参数调整段的合并。
  6. 调整前清楚你的性能目标,然后决定是调整速度还是吞吐量。
  7. 启用日志以便更好的进行诊断。在优化系统前进行小心的评估。
  8. 如果使用CMS垃圾收集器,你可能需要加上合理的 -XX:CMSWaitDuration 参数。
  9. 如果你的堆超过6-8GB,超过了CMS垃圾收集器设计容量,你会遇到长时间的stop-the-world阶段,你有几个方案:调整CMSInitiatingOccupancyFraction参数降低长时间GC的几率减少最大堆的大小;启用G1垃圾收集器。
  10. 学习垃圾收集调优艺术。如果你想精通的话,列出可用的JVM选项,在java命令中加入java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version,然后调优。

posted on 2014-02-14 11:39 顺其自然EVO 阅读(9545) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2014年2月>
2627282930311
2345678
9101112131415
16171819202122
2324252627281
2345678

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜