SaaS 电商设计 (十) 记一次 5000kw 商品数据ES迁移 (详细的集群搭建以及线上灰度过程设计)

目录

  • 一.背景
  • 二.技术目标
  • 三.技术方案
    • 3.1 整体流程
    • 3.2 ES 切换前:完成整体新集群的搭建.
        • i:拓扑结构设计
        • ii: 如何选择整体的 **ES** 集群配置.
    • 3.3 **ES** 版本切换中
      • 3.3.1 多client版本兼容
      • 3.3.2 Router的设计
    • 3.4 ES 切换后
    • 3.5 开箱即用
      • 3.5.1 开箱使用 demo 演示
      • 3.5.2 使用过程的问题
  • 四.总结

专栏系列

-SaaS 电商设计 (一) 如何设计一套适应多规格的商品服务
-SaaS 电商设计 (二) 私有化部署-缓存中间件适配
-SaaS 电商设计 (三) 电商黄金流程(商详,购物车,提单)梳理,持续更新(建议收藏)
-SaaS 电商设计 (四) 谈一谈电商系统高并发多耦合上下游的系统压测怎么做
-SaaS 电商设计 (五) 私有化部署-实现 binlog 中间件适配(附源码)
-SaaS 电商设计 (六) 实现 id 生成器本地化生产 (附源码)
-SaaS 电商设计 (七) 利用 Spring 扩展点 ImportBeanDefinitionRegistrar 实现 toB 系统对接(附源码)

-SaaS 电商设计 (八) 直接就能用的一套电商商品池完整设计方案(建议收藏)
-SaaS 电商设计 (九) 动态化且易扩展的实现购物车底部弹层(附:一套普适的线上功能切量的发布方案)

一.背景

    目前商品模块整体的商品数据存储频繁会使用到 Elasticsearch(以下简称 ES ) . 主要场景是一些复杂的 B 端查询以及一些非即时性的二方商品服务提供.

    由于非技术原因,不得不从技术侧发起了一个 ES 迁移的技术性改造.具体的原因有以下几点:

  • 原本的 ES 存储托管于云平台.由于资源到期(半年后)后续不再支持. 屋漏偏逢连夜雨,恰逢最近由于业务突增一些技术问题不得不进行技术支持,沟通尔尔,发现时下响应效率不高.最终也没有实质性解决业务问题.
  • 现有的 ES 拓扑结构在目前的业务场景下难以更好的动态扩缩容.

基于以上的重重原故,计出无奈不得不进行 ES 内迁至内网.

以下为现有的拓扑结构.

每个节点的信息如下:

PS:如上的node信息可以通过 _nodes/ 得到.

从以上的节点拓扑以及系统查看可知,目前的 ES 4个节点均为主节点&数据节点.

目前的 Transport Client 形式的链接,如果需要水平扩容无法做到动态扩容,系统无感知,需要重新修改链接完成项目重启,对于分布式系统来说,在高峰时刻无疑是致命的.搞不好裁员广进的下一个就是我.

  • 目前的链接方式存在一个跨网的网络链接.

目前是一个内部网络需要跨网去链接云端 ES ,中间不可避免涉及网络损耗.

基于以上的这三点,不得不发起一个 ES 集群迁移.

二.技术目标

  • Objectives: 完成 ES 集群迁移

  • Key Results

    • 保证线上 租户150+ ,5000w+ 商品数据.平稳迁移.其中 重点 KA 客户数据 3000w 必须重点保证可用性;

    • 迁移过程完成拓扑结构升级.保证后续的 ES 水平扩容能够对于服务透明;

    • 迁移过程保证出现问题能够随时回切;

三.技术方案

3.1 整体流程

图中以数据同步流程为例.查询的流程类似.

3.2 ES 切换前:完成整体新集群的搭建.

i:拓扑结构设计

升级结构的必要性:

在整体的第一版过程中我们使用的是 5.4.3 版本.并采用的 TCP 节点直连的方式.用过的同学都知道.节点直连太坑了,连上了就别动.一旦集群发生节点变更.管你是水平还是集群重建都得动代码.生产环境哪里由得你乱动.就这样无法做到动态水平扩容后代码的无改动.
(使用 Http 方式链接可以或者增加协调节点后通过链接协调的节点的方式).且在整体的集群搭建中仅使用了数据节点.那么就不可避免出现现有的数据节点既承担数据存储,索引结构维护,归并排序等本不属于数据节点的角色内容.当然在数据量并不大的场景现有的拓扑结构是满足业务的.那随着业务的发展,势必是需要更新演进的.

延伸一下:节点角色

  • 协调节点:转发来自 ES client 的请求至各自的数据节点.数据节点本地查询符合条件的数据后返回给协调节点.协调节点通过本地归并排序分页等操作,返回最终符合条件的查询结果.通过以上描述可知,协调节点需要大量的 CPU ,以及内存资源去完成节点的工作.

通过下面的配置创建一个仅用于协调的节点:

node.master: false
node.data: false
node.ingest: false
  • 主节点:维护集群内的索引增加,删除,更新,以及集群的管理工作.主节点是全局唯一的,一旦出现故障将从有资格成为 Master 的节点中进行选举.所以实际过程中配置为 Master 节点的数量一般建议为奇数个(但是集群中将只有一个生效),防止分布式常见的脑裂问题出现.
node.master: true
node.data: false

如上我们通过配置了数据节点以及主节点两个配置,将一个节点的角色同时设置为了主节点以及数据节点.那么在实际过程中面对数据量较多的场景,该节点就有可能因为角色的多种承受了不该承受的压力,进而导致集群的不稳定.所以这也是本次改造的一个原因之一.

  • 数据节点:顾名思义就是单纯用以处理数据(存储,查询).所以数据节点就实际部署过程中对于内存以及 cpu 的要求都需要比较高.

如何配置一个ES数据节点:

node.master: false
node.data: true
node.ingest: false
ii: 如何选择整体的 ES 集群配置.
  • 存储的配置

  • 这里建议参考腾讯云官方的计算逻辑.虽然是腾讯云我觉得还是考虑的比较中肯.主要是以下几点:

    • 副本的数量,相应的倍数即可.如:1个副本.那么单节点来说就是主(20g)+副(20g)=40g
    • 原本宿主机的其他资源损耗5%.40+0.05*40=42g;
    • es 内部任务开销的资源损耗20%.42+42*0.2=50.4g;
    • es 本身的结构存储10%.50.4+50.4*0.1=55.8g.
      https://cloud.tencent.com/document/product/845/19551
  • 节点的选择
    建议有一定查询的量级的场景.比如说千万级大概100T-200T的级别的查询都配置上协调节点.主节点.数据节点.保证各个节点都能够各司其职.而且也利于后期的垂直(单节点内存,cpu扩展),水平(新增同配置节点).

  • 分片的选择

    • 首先主副分片的选择.一般场景下如果对于主副没有特别要求的情况是 1:1 的处理就好了. 虽然之前查阅腾讯的官方文档表明无单点故障考虑可以不用增加副本. 我想说的是都是生产环境多少还是要考虑的,除非你真的是在搞一个玩具.
    • 建议分片大小.这里其实是有一些约定俗成的逻辑.一般大小 10g-50g .避免出现大的分片,以至于故障发生时影响集群的稳定性.另外在重新 rebalance 时也难以在节点之间移动.具体参考官方的文档:
      https://www.elastic.co/guide/en/elasticsearch/reference/7.9/size-your-shards.html#shard-size-recommendation

我是怎么配置的?

主节点3个:4C16G100GB
网关节点3个:4C16G100GB
数据节点8个:8C16G500GB

3.3 ES 版本切换中

3.3.1 多client版本兼容

通过在业务代码中插入自定义 Router . Router 其实就是本次在整体ES 迁移过程中比较核心的内容.主要核心职责就是为了完成在流量进入的过程中(写入,读取)的版本 ES client 获取.下面通过图示来放大 ES Router 的核心设计内容.

首先是整体 spring 容器对于 client 的兼容处理.尝试了几个版本之后最后使用的 maven 是.
也就是如下版本才能完成 两种不同 TCP 版本 ES client 的同时链接(这一次选择了先不更改 ES client 的链接方式不然更改为 Rest sdk 工作量可能兜不住)

 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>transport</artifactId><version>5.6.10</version></dependency><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>5.6.10</version></dependency><dependency><groupId>org.elasticsearch.plugin</groupId><artifactId>transport-netty4-client</artifactId><version>5.6.10</version></dependency>
<!-- ES集群5.x --><bean name="esFiveClient" class="com.xxx.xxx.ElasticsearchTemplate" init-method="init"><property name="clusterNodes" value="${es.clusterNodes.own}"/><property name="clusterName" value="${es.clusterName.own}"/><property name="clientTransportSniff" value="false"/><property name="username" value="${es.cluster.username}" /><property name="password" value="${es.cluster.password}" /></bean><!-- 新集群 --><!-- ES集群6.x --><bean name="esSixClient" class="com.xxx.xxx.ESForSixTemplate" init-method="init"><property name="clusterNodes" value="${es6.clusterNodes.own}"/><property name="clusterName" value="${es6.clusterName.own}"/><property name="clientTransportSniff" value="false"/><property name="username" value="${es6.cluster.username}" /><property name="password" value="${es6.cluster.password}" /></bean>
<!-- 门店商品 --><!-- 门店商索引 同时注入两个版本client --><bean id="storeSkuInfoIndexBeanService" class="com.xxx.xxx.StoreSkuInfoIndexServiceImpl"><property name="index" value="${es6.storeSku}"/><property name="type" value="${es6.storeSku}"/><property name="elasticsearchTemplate" ref="esFiveClient"/><property name="esTemplate" ref="esSixClient"/></bean>
....
/**
* 通过配置内容判定是否读取新版 6.0 client 还是 5.0 client
* 
*/
private SearchRequestBuilder getSearchRequestBuilderBySwitch(Boolean isGoToJes) {Client client = isGoToJes ? esSixClient.getClient() : esFiveClient.getClient();String indexReal = isGoToJes ? indexForSix : index;String typeReal = isGoToJes ? typeForSix : type;return client.prepareSearch(indexReal).setTypes(typeReal);}
....

在完成maven的适配之后我们就可以完成 spring 容器的两个 client 注入了.其实到了这一步算是其中一个非常关键的技术点被解决了.因为只要拿到了 client 后续相当于无论我们是用什么手段去实施切量就比较好做了,尽可能是去做到稳定性和可回滚.
在这里插入图片描述
具体调用的链路以及实施切量的过程.

3.3.2 Router的设计

核心的思路是通过线上configServer配置来完成租户白名单控制,如果在白名单内我们将通过切到 es 6.0 client 来实现新集群切量.这样一来就能够做到线上的无缝切量以及即时的回退.

白名单配置

{"2": "ALL_STORE_ID","100001601": "10005201","100005405": "ALL_STORE_ID","100008006": "ALL_STORE_ID","100008007": "10023233,10023835" 
}

key:为具体租户Id.
value:ALL_STORE_ID :表达则是全部门店进行切换.
具体的门店值,则是表达指定租户指定门店完成切换.

具体灰度切量过程.

第一阶段:完成数据量在10w下租户的切量.
第二阶段:完成数据量在100w下租户的切量.
第三阶段:完成数据量在1000w下租户切量.
第四阶段:完成重点客户切量.

最终我们大概是花了三个月的时间完成了整体的切量.

3.4 ES 切换后

  • 持续的流量监控

    其实并不仅仅是 中间件切换 ,包括代码下线,老开关的移除.都需要一定的监控数据观测.在一定时间段后从监控的数据上能够确认流量的关闭.那么才能够继续往下继续后续的代码动作.

    一般具体的方式就是在代码中插入指定的观测入口.比如上报流量监控的key,通过流量观测平台来完成日常的监控.比如3个月(具体的业务场景请参考具体的指标和时间跨度)后仍然没有流量.那么确认切换完成.

  • 流量监控之后的代码移除以及资源的销毁

    从资源和成本的角度,特别是时下降本增效的背景.有能力的前提下肯定是资源和成本能够进一步收缩是为更好.

3.5 开箱即用

老规矩:

https://github.com/Baixiu-code/elasticsearch-util-starter 一键直达

大概介绍下整体的框架图.

3.5.1 开箱使用 demo 演示

elasticsearch 环境:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-5-4-3

git@github.com:Baixiu-code/elasticsearch-client-test.git

通过实现 AbstractTransportSearchIndexService .如本例中的 BrandIndexServiceImpl .通过注入的 type,index,client 完成索引操作.

3.5.2 使用过程的问题

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.boot.version}</version><exclusions><exclusion><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId></exclusion>               </exclusions>
</dependency>

四.总结

    行文总结了一次线上的由技术侧发起的一起 ES 集群数据迁移过程.从集群搭建到线上灰度以及灰度切换之后的资源释放的这样一个完整技术方案上线的闭环过程.欢迎大家一起讨论交流. 最后也放上了一个比较传统可能大家仍在使用的 Transport client 使用 api 封装.持续更新中.后续将更新 Restful ,欢迎大家的关注,交流.

赠人玫瑰 手有余香 我是柏修 一名持续更新的晚熟程序员
期待您的点赞,关注加收藏,加个关注不迷路,感谢
您的鼓励是我更新的最大动力
↓↓↓↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/793833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

团体程序设计天梯赛-练习集 01

天梯赛题解合集 团体程序设计天梯赛-练习集 (L1-001 - L1-012) 团体程序设计天梯赛-练习集 (L1-013 - L1-024) 团体程序设计天梯赛-练习集 (L1-025 - L1-036) 团体程序设计天梯赛-练习集 (L1-037 - L1-048) L1-001 Hello World 输出题 样例 输入 输出 Hello World!思…

图像处理ASIC设计方法 笔记13 图像旋转ASIC的输入输出电路

文章目录 1 DPRAM:双端口 RAM2 IDT Integrated Device Technology, Inc. 公司介绍3 IDT70T633S10DDI4 TMS320C64145 旋转ASIC的输入输出框图图像旋转ASIC的输入输出电路案例用到的芯片相关介绍如下。 1 DPRAM:双端口 RAM DPRAM 的特点是可以通过两个端口同时访问,具有两套完全…

数据结构入门系列-栈的结构及栈的实现

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 栈 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一段进行插入和删除元素操作&#xff0c;进行数据输入和删除操作的一端称为栈顶&#xff0c;另…

InternLM2-Chat-1.8B 模型测试

在interStudio进行InternLM2-Chat-1.8B模型访问&#xff0c;进入开发机后 配置基础环境 新建conda环境并且进入 conda create -n demo python3.10 -y conda activate demo 下载pytorch等相关包 conda install pytorch2.0.1 torchvision0.15.2 torchaudio2.0.2 pytorch-cuda11.…

ChernoCPP 2

视频链接&#xff1a;【62】【Cherno C】【中字】C的线程_哔哩哔哩_bilibili 参考文章&#xff1a;TheChernoCppTutorial_the cherno-CSDN博客 Cherno的C教学视频笔记&#xff08;已完结&#xff09; - 知乎 (zhihu.com) C 的线程 #include<iostream> #include<th…

四、MySQL读写分离之MyCAT

一、读写分离概述 1、什么是读写分离&#xff1a; 读写分离&#xff1a;就是将读写操作分发到不同的服务器&#xff0c;读操作分发到对应的服务器 &#xff08;slave&#xff09;&#xff0c;写操作分发到对应的服务器&#xff08;master&#xff09; ① M-S (主从) 架构下&…

Java设计模式:外观模式之优雅门面(九)

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在软件工程中&#xff0c;设计模式是解决常见设计问题的经验总结&#xff0c;它为开发者提供了一种通用的、可复用的解决方案。外…

书生浦语训练营2期-第二节课笔记作业

目录 一、前置准备 1.1 电脑操作系统&#xff1a;windows 11 1.2 前置服务安装&#xff08;避免访问127.0.0.1被拒绝&#xff09; 1.2.1 iis安装并重启 1.2.2 openssh安装 1.2.3 openssh服务更改为自动模式 1.2.4 书生浦语平台 ssh配置 1.3 补充&#xff08;前置服务ok…

Thread的基本用法

目录 正文&#xff1a; 1.线程创建 2.线程休眠 3.获取线程实例 4.线程中断 5.线程等待join() 总结&#xff1a; 正文&#xff1a; 1.线程创建 线程创建是多线程编程的第一步&#xff0c;它涉及到创建一个可以并行执行的新线程。在Java中&#xff0c;有几种不同的方法可…

【Laravel】08 RESTful风格

【Laravel】08 视图模板动态渲染数据 1. RESTful风格 1. RESTful风格 (base) ➜ example-app php artisan make:model Blog -mc Model created successfully. Created Migration: 2024_04_01_143040_create_blogs_table Controller created successfully.(base) ➜ example-…

简述JMeter实现分布式并发及操作

为什么要分布式并发&#xff1f; JMeter性能实践过程中&#xff0c;一旦进行高并发操作时就会出现以下尴尬场景&#xff0c;JMeter客户端卡死、请求错误或是超时等&#xff0c;导致很难得出准确的性能测试结论。 目前知道的有两个方法可以解决JMeter支撑高并发&#xff1a; …

阿里 对象存储OSS 云存储服务

1.简介 对象存储服务(Object Storage Service ,OSS) 是一种 海量、安全、低成本、高可靠的云存储服务&#xff0c;适合存放任意类型的文件。容量和处理能力弹性扩展&#xff0c;多种存储类型供选择&#xff0c;全面优化存储成本。 2.如何使用。参考文档 看文档&#xff0c;说的…

【python从入门到精通】-- 第四战:语句汇总

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

docker从入门到熟悉

一、什么是docker&#xff1f; Docker是一个用于开发&#xff0c;交付和运行应用程序的开放平台。Docker使您能够将应用程序与基础架构分开&#xff0c;从而可以快速交付软件。借助Docker&#xff0c;您可以以与管理应用程序相同的方式来管理基础架构。通过利用Docker的快速交付…

GPT3, llama2, InternLM2技术报告对比

GPT3&#xff08;September 22, 2020&#xff09;是大语言应用的一个milestone级别的作品&#xff0c;Llama2&#xff08;February 2023&#xff09;则是目前开源大模型中最有影响力的作品&#xff0c;InternLM2&#xff08;2023.09.20&#xff09;则是中文比较有影响力的作品。…

Linux文件搜索工具(gnome-search-tool)

opensuse下安装: sudo zypper install gnome-search-tool 操作界面:

JNews Theme最新版本:新闻网站首选的WordPress主题,功能强大且灵活

JNews Theme最新版本&#xff1a;新闻网站的首选WordPress主题 在当今数字化时代&#xff0c;新闻网站扮演着至关重要的角色。为了打造一个吸引读者、功能齐全的新闻平台&#xff0c;选择一款合适的WordPress主题显得尤为关键。而JNews Theme最新版本正是新闻网站的首选WordPr…

MacOS - brew 和 brew cask 有什么区别?

brew 是 ruby 的包管理&#xff0c;后来看 yangzhiping 的博客介绍了 brew cask&#xff0c;感觉 cask 是更好的关联关系管理&#xff0c;但是&#xff0c;我后来使用过程中&#xff0c;发现很多软件 brew cask 里没有&#xff0c;但是 brew 里面倒是挺多&#xff01;今天来给说…

java面试题(Redis)

事情干的差不多了&#xff0c;开刷面试题和算法&#xff0c;争取在短时间内快速成长&#xff0c;理解java面试的常见题型 一、redis使用场景&#xff1a; 缓存&#xff1a;穿透、击穿、雪崩 双写一致、持久化 数据过期、淘汰策略 分布式锁&#xff1a;setnx、redisson 计数…

【JavaScript】函数 ⑦ ( 函数定义方法 | 命名函数 | 函数表达式 )

文章目录 一、函数定义方法1、命名函数2、函数表达式3、函数表达式示例 一、函数定义方法 1、命名函数 定义函数的标准方式 就是 命名函数 , 也就是之前讲过的 声明函数 ; 函数 声明后 , 才能被调用 ; 声明函数的语法如下 : function functionName(parameters) { // 函数体 …