背景:需要在一堆日志中统计所有存在的源IP,日志时按天存放的,代码结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def get_all_store_hosts():
'''
返回es中存储中所有ip
在索引doc时未设置refresh
'''

return _all_

def get_distinct_hosts_from_logs(day):
'''
从日志中查询所有的ip并去重
'''

return _hosts_

def store_hosts(hosts)
'''
将新的ip存储到es中
'''


def stat(day):
_all_ = get_all_store_hosts()
_hosts_ = get_distinct_hosts_from_logs:
_hosts_ = [_host for _host in _hosts_ if _host not in _all_]
if len(_hosts_):
store_hosts(_hosts_)

if __name__ == '__main__':
for day in xrange(1, 30):
stat(day)

各位看官觉得有问题吗?好吧,貌似没有问题,但是呢执行完成后,你会惊奇的发现es中你的统计的数据里面存储大量重复的ip

问题原因:
在文档索引的shard上到shard更新有一定时间间隔, 而只有到shard更新后才可search到文档, 也就是说文档索引后不一定可以查询到, 在es的官方文档中亦有描述,戳这里查看Refresh一节, 文档亦给出解决方法在索引时使用refresh=true属性, 但是需要测试对索引和查询性能的影响

在这里我的解决方法:在内存中做了一个缓存,通过缓存去重,当不缓存中不存在时则存储到es,并放入缓存中,为什么可以放在内存中,原因,就算有40w的ip, 放在内存数组中时, 内存大小占用25M左右对于一般的机器足以承受

INDEX API

示例:

1
2
3
4
5
PUT /test/user/1
{
"name": "silence",
"age": 27
}

说明:
1.索引文档使用PUT方法,需要指定index(test)、type(user)和文档编号,提交数据为json格式为文档的内容
2.在索引文档时,会自动检查index和type是否存在,若不存在则自动创建,对于type会自动调用putmapping方法为type自动创建mapping,当提交的json数据新增字段时也会自动对type自动调用putmapping方法在mapping中添加新的字段类型
可通过elasticsearch.yml中添加配置禁用自动创建index和type

1
2
action.auto_create_index: false        #禁用自动创建index
index.mapper.dynamic: false #禁用自动生成type

在某些时候允许某类型或者禁用某类型的index自动创建,则可以使用匹配模式和黑白名单形式进行配置

1
action.auto_create_index: +test*,+temp*,+tmp*       #只允许自动创建以test,temp,tmp开头的index

说明: 若action.auto_create_index设置为true或允许某些index执行, index.mapper.dynamic设置为false, 则可第一次时index自动创建一个type,后续不能再单独创建新的type

3.文档中的version属性
es为每个文档自动设置一个version属性, version从1开始, 当文档发生更新,删除操作时version都会自增1, version是范围为[1, 9.2e+18]的整数, 在获取或查询文档是version作为文档的一部分返回
version属性主要使用乐观锁机保证数据在读取后再进行更新动作时的数据一致性问题,在提交请求时通过指定version参数表示存储的版本必须符合条件时才可执行成功, 默认条件为两者一致,若不提交version表示不进行检查
使用方法:
例如编号为1的文档version为7

1
2
3
4
5
6
7
8
9
10
11
{
"_index": "test",
"_type": "user",
"_id": "1",
"_version": 7,
"found": true,
"_source": {
"name": "silence",
"age": 27
}
}

当我们使用如下请求执行更新动作可看到执行成功,并且version自增1, 返回结果中为8:
输入:

1
2
3
4
5
PUT /test/user/1?version=7
{
"name": "silence",
"age": 28
}

输出:

1
2
3
4
5
6
7
{
"_index": "test",
"_type": "user",
"_id": "1",
"_version": 8,
"created": false
}

当我们再次发出version=7的请求得到的响应为:

1
2
3
4
{
"error": "VersionConflictEngineException[[test][2] [user][1]: version conflict, current [8], provided [7]]",
"status": 409
}

可自己测试version>8的请求依然失败, 此时你可能会想到在高并发情况下此种效率是否会低效, 可能你会在内存中放置一个version+1的副本, 通过内存中对副本进行自增, 然后异步方式提高并发, 此时执行成功率会下降并且导致数据丢失, 在此种情况下只要满足你指定的version大于存储中的版本号即可, 为解决此种问题es提供version_type可以指定使用的比较策略:

version_type值 说明
internal 默认值, 表示指定version必须与存储中的version一致, 若成功则存储version自增1
external/external_gt 指定值必须大于存储中的version, 若成功存储version设置为提交的version
external_gte 指定值必须大于等于存储中的version, 若成功存储version设置为提交的version
force 强制更新,并将存储version设置为提交的version

4.op_type: 在提交请求时指定op_type=create, 表示若id不存在时创建, 否则失败
输入

1
2
3
4
5
PUT /test/user/1?op_type=create
{
"name": "silence",
"age": 28
}

输出:

1
2
3
4
{
"error": "DocumentAlreadyExistsException[[test][2] [user][1]: document already exists]",
"status": 409
}

op_type=create的另一种表示方法为:

1
2
3
4
5
PUT /test/user/1/_create
{

"name": "silence",
"age": 28
}

5.ID生成器: 在大多数情况下我们不需要维护也不关心文档的id是什么, 在es中可以为文档自动生成id,方式为使用post方式提交参数, 并在请求中不指定id值(若指定则使用指定的id值)
6.routing路由分配: 在创建index时通常会将index数据存放在不同的shard上,es默认通过hash(id) % shard_num决定将文档存储在哪个shard上,此刻你应该想到routing的作用,对,就是用来指定做负载是hash的输入参数:
输入:

1
2
3
4
5
POST /test/user/?routing=name
{

"name": "silence",
"age": 28
}

若在索引文档时显示指定routing,则在提交文档中必须存在指定routing对应的值,否则执行失败

7.分布式执行
索引操作会被路由到shard上,并在包含该shard的node中执行,若存在复制shard,则当所有复制节点从主shard中执行成功后,返回结果

8.一致性
为防止某些网络节点错误,默认情况下当索引成功数量>=仲裁(replicas/2+1)时,则认为操作成功,对于复制数量为1时则数据一共存两份(主shard和复制shard),此时若主shard写成功则认为执行成功
可在elasticsearch.yml中将action.write_consistency设置为one,all,quorum修改判断依据

9.刷新shard
为了在索引文档成功后立即查询到文档(当shard刷新后才可search到), 可以通过设置refresh=true在索引文档成功后立即执行存储该数据shard的刷新动作, 在设置前应该对索引和查询进行对性能测试,对于get接口获取文档是完全实时的

再次分享自己趟过的一个坑:
背景:需要在一堆日志中统计所有存在的源IP,日志时按天存放的,代码结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def get_all_store_hosts():
'''
返回es中存储中所有ip
在索引doc时未设置refresh
'''

return _all_

def get_distinct_hosts_from_logs(day):
'''
从日志中查询所有的ip并去重
'''

return _hosts_

def store_hosts(hosts)
'''
将新的ip存储到es中
'''


def stat(day):
_all_ = get_all_store_hosts()
_hosts_ = get_distinct_hosts_from_logs:
_hosts_ = [_host for _host in _hosts_ if _host not in _all_]
if len(_hosts_):
store_hosts(_hosts_)

if __name__ == '__main__':
for day in xrange(1, 30):
stat(day)

各位看着有问题吗?好吧,貌似没有问题,但是呢执行完成后,你会惊奇的发现es中你的统计的数据里面存储大量重复的ip,问题原因大家已经知道了吧

解决方法:我在内存中做了一个缓存,通过缓存去重,当在缓存中不存在时则放入缓存中并存储到es

  1. timeout
    当文档被索引时会从主shard将数据复制到复制shard, 主shard需要等待复制shard的响应后返回执行结果, 此等待时间默认为1min, 可以通过在请求中添加timeout修改此时间

GET API

示例:
输入:
GET /test/user/1
输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index": "test",
"_type": "user",
"_id": "1",
"_version": 3,
"found": true,
"_source": {
"name": "silence",
"age": 28,
"book": {
"name": "迷失的自己"
}
}
}

说明:
1.可以通过GET方法根据文档的ID读取文档内容
_index,_type,_id三元组唯一标识一个文档, 分别表示索引,类型和文档id
_version为文档的版本
found表示是否查询到结果, true表示存在, false表示不存在
_source是真正的文档内容

2.可以通过HEAD方法根据reponse header信息判断文档是否存在
输入:curl -XHEAD -i "http://localhost:9200/test/user/1"

1
2
3
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0`

输入:curl -XHEAD -i "http://localhost:9200/test/user/1
输出:

1
2
3
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=UTF-8
Content-Length: 0

可以看到若文档存在使用HEAD方法则返回状态码为200,否则状态码为404

3.GET操作默认是实时的,也就是说文档索引后可立即读取,并不像Search需要等待shard刷新,但是通过在GET请求中通过参数realtime=false或者在elasticsearch.yml配置action.get.realtime:false禁用
4.在GET数据时可以使用”_all”替代要查询的_type, 此时会返回在所有type中第一个匹配到的document
5.在GET数据时可以通过_source, _source_include & _source_exclude设置返回文档包含的属性
输入: GET /test/user/1?_source=false 不返回任何_source内容
输入: GET /test/user/1?_source=name 只返回_source中的name
输入: GET /test/user/1?_source_include=*.name&_source_exclude=name

_source常用于需要返回一两个字段的情况, 内容较多的文档属性值进行筛选时可以组合_source_include和_source_exclude
6.若只想返回_source中的内容可以使用:GET /test/user/1/_source
7.若在索引文档时指定了routing_key为了可以正确GET到文档,则需要在GET请求中添加routing指定正确的routing_key
8.默认GET文档执行在复制shard的上,但可以通过设置preference为_primary或者_local, _primary表示在主shard上执行, _local表示在一个分配且可用的shard上执行
9.GET请求中也可以添加refresh=true参数强制使获取文档相关shard刷新, 从而可以被search到
10.在GET请求发出后,会根据需要获取文档id将请求转发到一个相关的复制节点上执行并返回结果
11.可以在GET请求中指定version属性用于需要获取符合规则version的文档

DELETE API

示例:
输入
DELETE /test/user/1

说明:
1.在DELETE方法提交的参数中可以设置version属性用于删除符合规则的version文档
2.当在index文档是设置routing_key, 那么在删除文档时也需要使用routing设置正确的routing_key
3.当删除文档是若index不存在, 则es会自动创建
4.删除文档请求会被转发到主shard上, 主shard操作完成后, 各复制shard会从主shard进行同步
5.

对多个indices进行操作

es中大多resetapi支持请求多个index, 例如”test1,test2,test3”,index也可以使用通配符, 例如”test*“, 还可以使用+,-来包含或移除某个或某类index, 例如”test*,-test1”
支持设置多个的api的请求字符串可设置以下参数:

  • ignore_unavailable: 是否忽略单个index是否可用(不存在或关闭), true表示忽略, false表示不忽略, 默认为false, 例如查询已经关闭的index:

输入: GET /test1/user,account/_search?ignore_unavailable=false
输出:

1
2
3
4
{
"error": "IndexClosedException[[test1] closed]",
"status": 403
}

输入: GET /test1/user,account/_search?ignore_unavailable=false
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
},
"hits": {
"total": 0,
"max_score": 0,
"hits": []
}
}

  • allow_no_indices: 是否忽略通配符匹配不到index(不存在或关闭)的情况, true表示允许, false表示不允许,默认为true, 例如查询已经关闭的index:

输入: GET /test*/_search?allow_no_indices=false
输出:

1
2
3
4
{
"error": "IndexMissingException[[test*] missing]",
"status": 404
}

输入: GET /test*/_search?allow_no_indices=true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
},
"hits": {
"total": 0,
"max_score": 0,
"hits": []
}
}
  • expand_wildcards: 设置是否扩展通配符到closed的index中,open表示只在匹配并为open的index中查询,closed表示在匹配的所有的index中查询, 默认为closed, 例如查询已经关闭的index
    输入: GEt /test*/_search?expand_wildcards=closed
    输出:
    1
    2
    3
    4
    {
    "error": "IndexClosedException[[test1] closed]",
    "status": 403
    }

公共参数

  • format: 表示返回数据的格式, 可选值为yaml和json两种, 例如:
    输入: GET /test1/user/_search?format=yaml
    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ---
    took: 23
    timed_out: false
    _shards:
    total: 5
    successful: 5
    failed: 0
    hits:
    total: 1
    max_score: 1.0
    hits:
    - _index: "test1"
    _type: "user"
    _id: "1"
    _score: 1.0
    _source:
    name: "silence"
  • pretty: 表示在已json格式返回数据时是否以可视化的格式返回, false或未在设置表示不格式化, 否则格式化

  • human: 表示是否对返回结果进行格式化处理,比如3600(s)显示1h

  • 查询结果过滤
    主要使用filter_path参数进行设置

1.在返回结果中我们只关注took, hits.total, hits.hits._id, hits._source, 则我们可以发起如此请求:
输入:GET /test1/user/_search?filter_path=took,hits.total,hits.hits._id,hits.hits._source
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"took": 1,
"hits": {
"total": 1,
"hits": [
{
"_id": "1",
"_source": {
"name": "silence"
}
}
]
}
}

2.也可以使用统配符进行设置
输入: GET /_nodes/stats?filter_path=nodes.*.*ost*,nodes.*.os.*u
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"nodes": {
"9jfW4VeWRta-Uq7Cq7bK34": {
"host": "silence",
"os": {
"cpu": {
"sys": 1,
"user": 1,
"idle": 96,
"usage": 2,
"stolen": 0
}
}
}
}
}

3.若层级较多时可使用**进行简化
输入: GET /_nodes/stats?filter_path=nodes.**.*sys*
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"nodes": {
"9jfW4VeWRta-Uq7Cq7bK34": {
"os": {
"cpu": {
"sys": 2
}
},
"process": {
"cpu": {
"sys_in_millis": 139106
}
}
}
}
}

4.若只需要_source中的某些值,则可以将filter_path和_source参数共同使用
输入: GET /test1/account/_search?filter_path=hits.hits._source&_source=firstname,lastname,gender&size=2
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"hits": {
"hits": [
{
"_source": {
"firstname": "Rodriquez",
"gender": "F",
"lastname": "Flores"
}
},
{
"_source": {
"firstname": "Opal",
"gender": "M",
"lastname": "Meadows"
}
}
]
}
}

5.flat_settings用于设置在查询setting时,setting中的key格式, 默认为false:
输入: GET /test1/_settings?flat_settings=true
输出:

1
2
3
4
5
6
7
8
9
10
11
{
"test1": {
"settings": {
"index.creation_date": "1442230557598",
"index.uuid": "70bg061IRdKUdDNvgkUBoQ",
"index.version.created": "1060099",
"index.number_of_replicas": "1",
"index.number_of_shards": "5"
}
}
}

输入: GET /test1/_settings?flat_settings=false
输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"test1": {
"settings": {
"index": {
"creation_date": "1442230557598",
"number_of_shards": "5",
"uuid": "70bg061IRdKUdDNvgkUBoQ",
"version": {
"created": "1060099"
},
"number_of_replicas": "1"
}
}
}
}

  • 请求参数格式
    1.boolean: 在es中将”0”, 0, false, “false”, “off”识别为false,其他均按ture处理
    2.number
    3.time: 可以提交一个以毫秒时间的整数或者以日期标识结尾的字符串,例如”2d”表示2天,支持的格式有: y(year),M(month),w(week),d(day),h(hour),m(minute),s(second)
    4.距离: 可以提交一个以米为单位的证书或者以距离表示结尾的字符串,例如”2km”表示2千米,支持的格式有: mi/miles(mile英里), yd/yards(yard码), ft/feet(feet尺), in/inch(inch英寸), km/kilometers(kilometer千米), m/meters(meter米), cm/centimeters(centimeter厘米), mm/millimeters(millimeter毫米), NM/nmi/nauticalmiles(Nautical mile纳米)
    5.模糊类型:
    a.数字,时间, IP:类似于range -fuzzines<=value<=+fuzzines
    b.字符串: 计算编辑距离

  • 返回结果中key的格式为驼峰还是下划线分割, 通过case设置为camelCase则返回驼峰格式,否则为下划线分割形式

  • jsonp: 可以用jsonp回调的方式调用es api, 需要通过callback设置回调函数名称,并且需要在elasticsearch.yml中配置http.jsonp.enable: true来启用jsonp格式

url访问控制

可以通过代理方式进行es的url访问控制,但是对于multi-search,multi-get和bulk等在请求参数中设置不同的index的情况很难解决.
为防止通过请求体设置index的情况,需要在elasticsearch.yml中设置rest.action.multi.allow_explicit_index:false, 此时es不允许在request body中设置index

如在修改前:
输入:

1
2
3
4
5
POST /test1/user3/_bulk?pretty
{"index" : {"_index" : "test2", "_type" : "user1", "_id" : 1}}
{"name" : "silence1"}
{"index" : {"_index" : "test2", "_type" : "user1", "_id" : 2}}
{"name" : "silence2"}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"took": 225,
"errors": false,
"items": [
{
"index": {
"_index": "test2",
"_type": "user1",
"_id": "1",
"_version": 1,
"status": 201
}
},
{
"index": {
"_index": "test2",
"_type": "user1",
"_id": "2",
"_version": 1,
"status": 201
}
}
]
}

如在修改后(已重启):
输出:

1
2
3
4
{
"error": "IllegalArgumentException[explicit index in bulk is not allowed]",
"status": 500
}

输入:

1
2
3
4
5
POST /test1/user3/_bulk?pretty
{"index" : {"_id" : 1}}
{"name" : "silence1"}
{"index" : {"_id" : 2}}
{"name" : "silence2"}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"took": 8,
"errors": false,
"items": [
{
"index": {
"_index": "test1",
"_type": "user3",
"_id": "1",
"_version": 1,
"status": 201
}
},
{
"index": {
"_index": "test1",
"_type": "user3",
"_id": "2",
"_version": 1,
"status": 201
}
}
]
}

背景:在某年某月某日发现es运行不正常,查看日志发现如下错误

1
java.io.IOException: Too many open files

以下为操作步骤:
1.查看es节点信息结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"cluster_name" : "elasticsearch",
"nodes" : {
"eE4eHSOWTK-j6IO7JJzcXG" : {
"name" : "Hardcore",
"transport_address" : "inet[silence/192.168.1.111:9300]",
"host" : "silence",
"ip" : "192.168.1.111",
"version" : "1.6.0",
"build" : "cdd3ac4",
"http_address" : "inet[/192.168.1.111:9200]",
"process" : {
"refresh_interval_in_millis" : 1000,
"id" : 10598,
"max_file_descriptors" : 32768,
"mlockall" : false
}
}
}
}

疑问:明明在/etc/init.d/elasticsearch启动脚本中设置了MAX_OPEN_FILES=65535, 且执行ulimits -n $MAX_OPEN_FILES成功, 但是es节点信息中max_file_descriptors始终为32768

2.查看/etc/init.d/elasticsearch启动脚本内容,在启动进程时使用/etc/init.d/functions下的daemon函数启动,最终追溯到daemon使用runuser -s /bin/bash $user -c "$corelimit >/dev/null 2>&1 ; $*"方式启动进程,自然想要在-c中添加ulimit -n 65535, 结果以失败告终,启动脚本报错ulimit: open files: cannot modify limit: Operation not permitted,自己在命令行下发现普通用户在修改时报错, 而root用户就ok

3.修改/etc/security/limits.conf文件添加如下内容(es运行用户为elasticsearch)

1
2
elasticsearch        hard     nofile         65535
elasticsearch soft nofile 65535

修改内容后重启es, 启动后查询es节点信息max_file_descriptors还是为32768 … 此时已疯

4.查看谷歌,说/etc/pam.d/login文件中需要有session required pam_limits.so limits.conf文件才会起效,于是乎,我加上了,结果…尼玛咋还是32768呢
5.再次查看/etc/pam.d/login发现有这么一句话session include system-auth, 一看就是导入了文件system-auth, 于是在system-auth中发现已经存在session required pam_limits.so,然后尼玛删除步骤3添加的内容
6.此时想到反编译pam_limits.so文件看看到底干了什么事, 当然先得查询文件在哪 find / -name pam_limits.so
然后使用strings pam_limits.so 结果尼玛发现其中有这么两行:

1
2
3
4
5
/etc/security/limits.conf
.
.
.
/etc/security/limits.d/*.conf

自然想查看/etc/security/limits.d/下的*.conf结果,发现了def.conf,内容为:

1
2
*        hard     nofile         32768
* soft nofile 32768

说明: *表示对所有用户生效

结果自然要试试修改def.conf文件,结果这次ok了

分析原因:
1.why在/etc/init.d/elasticsearch中已经设置ulimit -n为啥没有生效
runuser命令格式:runuser -s [shell] [uid/gid] -c "command", 说明:使用一个替代的用户或组ID运行一个Shell, 只有会话的PAM hooks运行, 并且没有密码提示, 这个命令仅在root用户时有用
根据测试也知道ulimit -n只是修改当前会话中的打开文件描述符数量, 当打开新回话时或切换新用户则失效。并根据描述得知runuser在打开会话之后PAM hooks认证模块会执行,因此在此前的设置参数都无效

2.why在runuser时在-c中添加ulimit -n 65535报错
查找资料发现, 普通用户在设置ulimit -n时其大小不能超过预设置的值, 那预设置的值是谁呢, 自然就想到limits.conf,可以自己测试在limits.conf中添加自己的用户信息(silence is me),可以发现再次修改则正常

1
2
silence        hard     nofile         65535
silence soft nofile 65535

3.limits.conf和limits.d/*.conf的关系
此时自然想到的是文件加载顺序和配置内容有关,配置相同的内容但是值不通时,后加载的配置文件的值会生效呢, 我们做一下测试:在limits.d/def.conf配置文件中添加一下信息,因为第2步已经在limit.conf中设置其值为65535并测试成功,那么此时若我们再测试ulimit -n 50000正常而ulimit -n 65535 不正常自然可以验证我们的猜测

1
silence        hard     nofile         50000

结果自然与猜测一致
根据反编译的结果pam_limits.so会先加载limits.conf然后再加载limits.d/.conf此时有一定顺序, 但是limits.d/.conf中加载顺序如何呢? 猜测与系统排序有关,但未测试,在通常情况下好的系统管理员对不同用户应该根据userid在limits.d下建立不同的文件单独配置,方便管理
为什么在limits.d/def.conf中值设置hard值呢?可以查看配置文件的规则,hard设置为允许修改的最大值而soft设置的是新回话生成时默认设置

4.此时你应该会问这个值到底可以设置多大?
查看文件/proc/sys/fs/file-max和/proc/sys/fs/file-nr内容
输入: cat /proc/sys/fs/file-max
输出: 191832

输入: cat/proc/sys/fs/file-nr
输出: 1792 0 191832

查阅GOOGLE, file-nr文件中的三个数分别表示: 系统已经分配的文件句柄数, 没有用到的句柄数和所有可分配的最大句柄数,file-max中的值为最大所能分配的句柄数, 因此在ulimit -n是设置的值不能超过file-max记录的值
file-nr文件内容通常由在系统启动时根据系统内存计算得出,系统内存增大则file-max增大

5.如何查看其他进程当前设置的max_file_descriptors
对于linux内核为2.6.24及以后版本
输入: cat /proc/34690/limits | grep "Max open files"
输出: Max open files 32768 32768 files

6.如何查看某进程当前打开的文件句柄数:
输入: lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|grep pid
输出: cnt pid

*nux下安装

在*nux下,es官方已提供编译的deb和rpm包,但是需要保证已安装安装java虚拟环境(目前es1.6和1.7版本均可选择1.8版本java),安装步骤如下:
1.下载ES deb/rpm包,并执行安命令
deb包安装: dpkg -i elasticsearch-1.6.0.deb
rpm包安装: rpm -i elasticsearch-1.6.0.rpm

2.安装后需要将es服务更新随系统启动

  • 对于Debian/Ubuntu系统
    执行: update-rc.d elasticsearch defaults
    系统服务控制: /etc/init.d/elasticsearch start/stop/restart

  • 对于redhat/centos系统
    执行: chkconfig -add elasticsearch
    系统服务控制: service elasticsearch start/stop/restart

3.若需要修改es启动参数,可直接在/etc/init.d/elasticsearch脚本中修改然后从其服务器

windows下安装

在windows下es安装比较简单,当然也需要提前安装好java虚拟环境,以下为es安装步骤:
1.下载zip包并解压到安装目录
2.通过es_home/bin/service.bat将es注册到windows服务中(注意需要使用管理员权限运行),service.bat命令格式:service.bat install|remove|start|stop|manager [server_name]

参数 说明
install 将es安装到windows服务中
remove 将es从windows服务中移除
start 服务启动
stop 服务停止
manager 管理gui

在未设置安装服务时若未设置server_name时,则命令使用默认名称,在执行service.bat脚本时也不需要指定server_name参数,否则需要手动指定server_name才能执行

3.若需要修改es启动参数,可使用service.bat manager [server_name]打开GUI窗口,在”java”选项卡中设置启动参数后重启服务

es目录解释

1
2
3
4
5
6
7
8
9
10
11
12
elasticsearch                     -- path.home, es的安装目录
├─bin -- ${path.home}/bin, 启动脚本方式目录
├─config -- ${path.home}/config, 配置文件目录
├─data -- ${path.home}/data, 数据存放目录
│ └─elasticsearch -- ${path.home}/data/${cluster.name}
├─lib -- ${path.home}/lib, 运行程序目录
├─logs -- ${path.home}/logs, log目录
└─plugins -- ${path.home}/plugins, 插件目录
├─head
│ └─...
└─marvel
└─...

es支持将data目录配置为多个,可通过在进程启动时通过-Des.index.store.distributor设置在存储数据时选择的目录:

参数值 说明
least_used 默认值,选择剩余存储空间最大的目录
random 随机选取,选择的概率和目录剩余存储空间大小有关

该方案提供类似raid0(把连续的数据分散到不同的磁盘存储)的方式,配置也比较简单:

1
path.data: /path/to/data1,/path/to/data2

在*nix下使用deb/rpm安装包安装,通常会修改各文件夹的安装路径,默认安装路径如下:

type debian/ubuntu redhat/centos
home /usr/share/elasticsearch /usr/share/elasticsearch
bin /usr/share/elasticsearch/bin /usr/share/elasticsearch/bin
config(file) /etc/elasticsearch /etc/elasticsearch
config(env) /etc/default/elasticseach /etc/sysconfig/elasticseach
data /var/lib/elasticsearch/data /var/lib/elasticsearch
logs /var/log/elasticsearch /var/log/elasticsearch
plugins /usr/share/elasticsearch/plugins /usr/share/elasticsearch/plugins