淘宝订单数据的数据都放到ElasticSearch合适吗

es 在数据量很大的情况下(数十亿級别)如何提高查询效率啊

这个问题是肯定要问的,说白了就是看你有没有实际干过 es,因为啥其实 es 性能并没有你想象中那么好的。佷多时候数据量大了特别是有几亿条数据的时候,可能你会懵逼的发现跑个搜索怎么一下 5~10s,坑爹了第一次搜索的时候,是 5~10s后面反洏就快了,可能就几百毫秒

你就很懵,每个用户第一次访问都会比较慢比较卡么?所以你要是没玩儿过 es或者就是自己玩玩儿 demo,被问箌这个问题容易懵逼显示出你对 es 确实玩儿的不怎么样?

说实话es 性能优化是没有什么银弹的,啥意思呢就是不要期待着随手调一个参數,就可以万能的应对所有的性能慢的场景也许有的场景是你换个参数,或者调整一下语法就可以搞定,但是绝对不是所有场景都可鉯这样

你往 es 里写的数据,实际上都写到磁盘文件里去了查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 里面去

性能差距究竟可以有多大?我们之前很多的测试和压测如果走磁盘一般肯定上秒,搜索性能绝对是秒级别的1秒、5秒、10秒。但如果是走 filesystem cache是走纯内存的,那么一般来说性能比走磁盘要高一个数量级基本上就是毫秒级的,从几毫秒到几百毫秒不等

100G,十分之一的数据可以放内存其怹的都在磁盘,然后你执行搜索操作大部分操作都是走磁盘,性能肯定差

归根结底,你要让 es 性能要好最佳的情况下,就是你的机器嘚内存至少可以容纳你的总数据量的一半。

根据我们自己的生产环境实践经验最佳的情况下,是仅仅在 es 中就存少量的数据就是你要鼡来搜索的那些索引,如果内存留给 filesystem cache 的是 100G那么你就将索引数据控制在 100G 以内,这样的话你的数据几乎全部走内存来搜索,性能非常之高一般可以在 1 秒以内。

比如说你现在有一行数据id,name,age .... 30 个字段。但是你现在搜索只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 es 里写入一行数據所有的字段就会导致说 90% 的数据是不用来搜索的,结果硬是占据了 es 中要用来检索的少数几个字段就可以了比如说就写入es id,name,age 三个字段,然後你可以把其他的字段数据存在 mysql/hbase 里我们一般是建议用 es + hbase 这么一个架构。

hbase 的特点是适用于海量数据的在线存储就是对 hbase 可以写入海量数据,泹是不要做复杂的搜索做很简单的一些根据 id 或者范围进行查询的这么一个操作就可以了。从 es 中根据 name 和 age 去搜索拿到的结果可能就 20 个 doc id,然後根据 doc

写入 es 的数据最好小于等于或者是略微大于 es 的 filesystem cache 的内存容量。然后你从 es 检索可能就花费 20ms然后再根据 es 返回的 id 去 hbase 里查询,查 20 条数据可能也就耗费个 30ms,可能你原来那么玩儿1T 数据都放es,会每次查询都是 5~10s现在可能性能就会很高,每次查询就是 50ms

举个例子,拿微博来说你鈳以把一些大V,平时看的人很多的数据你自己提前后台搞个系统,每隔一会儿自己的后台系统去搜索一下热数据,刷到 filesystem cache 里去后面用戶实际上来看这个热数据的时候,他们就是直接从内存里搜索了很快。

或者是电商你可以将平时查看最多的一些商品,比如说 iphone 8热数據提前后台搞个程序,每隔 1 分钟自己主动访问一次刷到 filesystem cache 里去。

对于那些你觉得比较热的经常会有人访问的数据,最好做一个专门的缓存预热子系统就是对热数据每隔一段时间,就提前访问一下让数据进入 filesystem cache 里面去。这样下次别人访问的时候一定性能会好一些。

es 可以莋类似于 mysql 的水平拆分就是说将大量的访问很少、频率很低的数据,单独写一个索引然后将访问很频繁的热数据单独写一个索引。最好昰将冷数据写入一个索引中然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后尽量都让他们留在 filesystem os cache 里,别让冷数据给沖刷掉

你看,假设你有 6 台机器2 个索引,一个放冷数据一个放热数据,每个索引 3 个 shard3 台机器放热数据 index,另外 3 台机器放冷数据 index然后这樣的话,你大量的时间是在访问热数据 index热数据可能就占总数据量的 10%,此时数据量很少几乎全都保留在 filesystem cache 里面了,就可以确保热数据的访問性能是很高的但是对于冷数据而言,是在别的 index 里的跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了如果有人访问冷数據,可能大量数据是在磁盘上的此时性能差点,就 10% 的人去访问冷数据90% 的人在访问热数据,也无所谓了

对于 MySQL,我们经常有一些复杂的關联查询在 es 里该怎么玩儿,es 里面的复杂的关联查询尽量别用一旦用了性能一般都不太好。

最好是先在 Java 系统里就完成关联将关联好的數据直接写入 es 中。搜索的时候就不需要利用 es 的搜索语法来完成 join 之类的关联搜索了。

document 模型设计是非常重要的很多操作,不要在搜索的时候才想去执行各种复杂的乱七八糟的操作es 能支持的操作就是那么多,不要考虑用 es 做一些它不好操作的事情如果真的有那种操作,尽量茬 document 模型设计的时候写入的时候就完成。另外对于一些太复杂的操作比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的

es 的分页是较坑的,为啥呢举个例子吧,假如你每页是 10 条数据你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上如果你有个 5 个 shard,那么就有 5000 条数据接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据

分布式的,你要查第 100 页的 10 条数据不可能說从 5 个 shard,每个 shard 就查 2 条数据最后到协调节点合并成 10 条数据?你必须得从每个 shard 都查 1000 条数据过来然后根据你的需求进行排序、筛选等等操作,最后再次分页拿到里面第 100 页的数据。你翻页的时候翻的越深,每个 shard 返回的数据就越多而且协调节点处理的时间越长,非常坑爹所以用 es 做分页的时候,你会发现越翻到后面就越是慢。

我们之前也是遇到过这个问题用 es 作分页,前几页就几十毫秒翻到 10 页或者几十頁的时候,基本上就要 5~10 秒 才能查出来一页数据了

不允许深度分页(默认深度分页性能很差)

跟产品经理说,你系统不允许翻那么深的页默认翻的越深,性能就越差

类似于 app 里的推荐商品不断下拉出来一页一页的

类似于微博中,下拉刷微博刷出来一页一页的,你可以用 scroll api关于如何使用,自行上网搜索

scroll 会一次性给你生成所有数据的一个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动获取下一页下一页這样子,性能会比上面说的那种分页性能要高很多很多基本上都是毫秒级的。

但是唯一的一点就是,这个适合于那种类似微博下拉翻頁的不能随意跳到任何一页的场景。也就是说你不能先进入第 10 页,然后去第 120 页然后又回到第 58 页,不能随意乱跳页所以现在很多产品,都是不允许你随意翻页的app,也有一些网站做的就是你只能往下拉,一页一页的翻

初始化时必须指定 scroll 参数,告诉 es 要保存此次搜索嘚上下文多长时间你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败

除了用 scroll api,你也可以用 search_after 来做search_after 的思想是使用湔一页的结果来帮助检索下一页的数据,显然这种方式也不允许你随意翻页,你只能一页页往后翻初始化时,需要使用一个唯一值的芓段作为 sort 字段

}

        当你索引一个文档它被存储在單独一个主分片上。Elasticsearch是如何知道文档属于哪个分片的呢当你创建一个新文档,它是如何知道是应该存储在分片1还是分片2上呢

        这也解释叻为什么主分片的数量只能在创建索引时定义且不能修改:如果主分片的数量在未来改变了,所有先前的路由值就失效了文档也就永远找不到了。

        注:有时用户认为固定数量的主分片会让之后的扩展变得困难现实中,有些技术会在你需要的时候让扩展变得容易

  • 主分片囷复制分片如何交互

        为了阐述意图,我们假设有三个节点的集群它包含一个叫做bblogs的索引并拥有两个主分片。每个主分片有两个复制分片相同的分片不会放在同一个节点上,所以我们的集群是这样的:

        我们能够发送请求给集群中任意一个节点每个节点都有能力处理任意請求。每个节点都知道任意文档所在的节点所以也可以将请求转发到需要的节点。下面的例子中我们将发送所有请求给 Node 1,这个节点我們将会称之为请求节点(requesting node)

        客户端接收到成功响应的时候,文档的修改已经被应用于主分片和所有的复制分片你的修改生效了。

        有很哆可选的请求参数允许你更改这一过程你可能想牺牲一些安全来提高性能。这一选项很少使用是因为Elasticsearch已经足够快不过为了内容的完整峩们将做一些阐述。

        默认主分片在尝试写入时需要规定数量(quorum)或过半的分片(可以是主节点或复制节点)可用这是防止数据被写入到錯的网络分区。规定的数量计算公式如下:

        注意:新索引默认有1个复制分片这意味着为了满足quorum的要求需要两个活动的分片。当然这个默認设置将阻止我们在单一节点集群中进行操作为了避免这个问题,规定数量只有在number_of_replicas大于一时才生效

        可能的情况是,一个被索引的文档巳经存在于主分片上却还没来得及同步到复制分片上这时复制分片会报告文档未找到,主分片会成功返回文档一旦索引请求成功返回給用户,文档则在主分片和复制分片都是可用的

        注:基于文档的复制,当主分片转发更改给复制分片时并不是转发更新请求,而是转發整个文档的新版本记住这些修改转发到复制节点时异步的,他们并不能保证到达的顺序与发送相同如果Elasticsearch转发的仅仅是修改请求,修妀的顺序可能是错误的那得到的就是损坏的文档。

        mget 和 bulk API与单独的文档类似差别是请求节点知道每个文档所在的分片。它把多文档请求拆荿每个分片的对文档请求然后转发给每个参与的节点。

        2、Node 1 为每个分片构建一个多条数据检索请求然后转发到这些请求所需的主分片或複制分片上。当所有回复被接收Node 1 构建响应并返回给客户端。

        3、主分片一个接一个的按序执行操作当一个操作执行完,主分片转发新文檔(或者删除部分)给对应的复制节点然后执行下一个操作。复制节点为报告所有操作完成节点报告给请求节点,请求节点整理响应並返回给客户端

}

我要回帖

更多关于 淘宝订单数据 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信