热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

DockOne微信分享(二四六):同程艺龙大数据在Kubernetes的实践

【编者的话】同程艺龙是中国在线旅游行业的创新者和市场领导者,秉持让旅行更简单、更快乐的使命。作为同程艺龙的数据底层支撑部门,我们在2018年推动所有组件容器化部署,2019年推


【编者的话】同程艺龙是中国在线旅游行业的创新者和市场领导者,秉持 "让旅行更简单、更快乐" 的使命。作为同程艺龙的数据底层支撑部门,我们在2018年推动所有组件容器化部署,2019年推动所有服all in Kubernetes战略,在这个过程中我们也遇到了一些问题,比如存储组件是否应该上Kubernetes,外部世界如何和Kubernetes集群打通,本文将向大家介绍我们使用Kubernetes部署分布式系统的一些经验和思考。


同程艺龙数据中心容器化背景


同程艺龙是中国在线旅游行业的创新者和市场领导者,秉持 "让旅行更简单、更快乐" 的使命。作为同程艺龙的数据底层支撑部门,我们每天会产生海量的数据进行存储和计算,为了更好的支撑业务,我们在2018年推动所有的服务都采用了Docker Host模式部署 。 我们一开始采用脚本管理容器服务,虽然能够做到自动化部署,但是不同组件的资源池没有打通,机器剩余资源的把控不到位,服务的滚动更新和故障转移也处于一个人工处理的状态,这个时候我们急需一个统一调度和管理集群资源的平台,所以2019年我们开始尝试将所有服务部署到Kubernetes上,已经投产的存储服务有Elasticsearch,Tikv,Kudu,Kafka等一些节点类型少的服务,计算组件有Hive,Spark SQL等服务,在这条艰辛的on Kubernetes之路,我们也遇到了很多问题,今天向大家分享一下。


Kubernetes集群如何和外部世界打通


首先看下我们Kubernetes集群的架构图:



Kubernetes集群和外部机器通信,我们采用的OVS虚拟交换机的方式将物理网络和容器网络做成一个大二层的网络,这样Kubernetes集群外部的机器也能访问到容器。因为我们会部署分布式系统,有些分布式系统要求IP不变,所以Pod我们做了IP Local,根据Namespace和pod name来记录每个Pod的IP,IP保留时间为三天。为了防止极端情况下的需求,我们给Pod做了指定IP的功能,但是由于我们部署使用的是自定义对象或者StatefulSet对象,这个功能还需要在上层对象的Controller中支持。上面这些功能我们都是基于Contiv的netplugin插件,在使用过程中我们遇到节点veth pair删除不干净的情况,我们采用定时检查删除无用veth pair来保证网络的干净。


OVS架构图如下:



Pod网络的问题解决以后,Service的负载我们希望和Pod网络一样可以直接访问。这里我们使用Kubernetes Java Client Watch Service和Endpoints Event事件,将EndPoints和Service Cluster IP同步到同程艺龙的基础设施组件TVS上,TVS是一个四层负载均衡,我们通过HTTP的方式进行同步。在刚开始上线的时候,我们发现Kubernetes Client切换leader节点的时候会重新消费之前的Service event事件,所以同步一定要保证幂等性,Service删除事件同步要加上Kubernetes Service是否存在的校验,确认Service真的不在的时候,再去删除TVS的VIP。这种方式将我们的路由规则更集中式的管理,不会像kube-proxy将所有的规则同步到每台物理机器上。


Service网络解决以后,由于分布式系统的一些特性,有些组件是一定要通过域名才能启动和访问。所以我们会把Kubernetes集群内的节点域名全部注册到公司的DNS服务上,这里我们只要将Kubernetes内部域名改成公司提供的域名尾缀并重启集群和CoreDNS,然后将CoreDNS的域名同步一份到公司的DNS服务上。


做了上面这些支持后,我们觉得这样一个集群才符合生产环境的使用,既可以使用Kubernetes的很多特性,也和公司内部组件做了整合,用户的体验感也没有太大的变化,反而借助于Service和域名的自动同步,Kubernetes的编排能力,体验更佳。


存储计算组件上Kubernetes集群的实践


因为Kubernetes设计的初衷是为了部署计算型的组件,所以我们觉得部署计算节点对我们来说难度不大,我们部署了 Hive,Spark SQL,Tensorflow server等计算组件,不同组件我们采用不同的Namespace进行管理,不同组件的机器资源我们打上标签,做好资源池的划分。针对Hive这种两种及以上类型的节点,一开始我们会采用Helm写好模板做好一键部署,然后我们会投入人力做Hive的Operator,开发Operator可以将我们的一些人工容灾的思想用代码去变现出来,更新多节点类型的组件也会简单很多。


我们都会遇到存储组件应不应该上Kubernetes,我到底应不应该用共享存储的问题。我们认为存储组件是可以上Kubernetes的,这里我们采用的 Local PV+Ceph的方式,针对大数据存储组件,比如ES,TiKV,Kafka等组件,我们采用Local PV的方式,像物理机一样将数据存在本地磁盘,保证性能。针对Jupyter一些非重要的组件我们会采用Ceph RBD Image的方式,用来节省本地磁盘的空间。刚开始的时候我们采用批量创建Local PV的方式,后来我们希望控制磁盘的使用,一个或者两个存储组件配一些计算组件做到资源的混部,我们将Local PV的创建做成按需分配,合理的控制磁盘的使用。


存储组件我们第一个部署的组件是ElasticSearch,ES是非常容易支持的,因为客户端是http访问,对外只需要提供 ES client节点类型,不需要暴露集群内部节点信息,利用Service只需要提供一个TVS的VIP给到用户。刚开始我们使用StatefulSet部署Elasticsearch,由于Statefulset顺序性的限制,我们不能指定下掉某个节点,于是我们开发了一个高级版的AdvanceStatefulSet,通过指定序号就可以下线Pod。


像这样配置即可:


offlineStrategy:
podOrdinals:
- 0

我们将ES部署方式用Helm模板写好,做到自动化部署,每一个节点类型的容错还局限于AdvanceStatefulSet的Controller。ES官方也提供了Operator,因为处于beta版本,自定义资源还有很多问题,没有基于Sts做CRD,所以我们没有选择这种方式。我们觉得在Sts上层再建立一层CRD,可以更方便去管理多种节点类型,但是人力有限,我们对这个需求的优先级还不是很高,当前基于AdvanceSts管理也能够运维起来。


在部署Kudu组件的时候,我们延用ES的套路,发现节点域名解析不到的问题,当时我们还没有将Kubernetes内部域名同步到公司层面的DNS。在分布式系统中,很常见的场景是客户端连接到Master节点,Master节点会返回Worker节点域名,在Kubernetes集群外部的机器是没法访问到Worker的域名的。在没解决DNS问题之前,我们先采用Host模式部署,注意一下port冲突问题就好了。


因为我们在2018年所有的组件已经on Docker,我们只要将组件的部署方式迁移到Kubernetes上来管理,所以像Kafka,TiKV,PG,ZK这些组件,我们都可以轻松的上Kubernetes。不过在大数据组件当中,机器资源最多就属Hadoop组件,在以前Docker Host部署的时候,DataNode和yarn节点会挂载sata的12块盘,TiKV EleatiscSearch我们采用的是ssd raid50单块盘的方式,我们发现Local PV的方式不能很好的挂载多块盘,如果强行的挂载12个PV,scheduler需要支持每个PV在不同的磁盘,才能符合我们利用多块盘读写的目的。Local PV没法解决我们的需求,我们开始尝试HostPath,HostPath现在没有一个好的资源管理器,HostPath不能和机器属性绑定在一起,简单来说就是让HostPath具备Local PV机器绑定的特性。所以我们正在开发一个将HostPath也转变成PV资源进行管理,具备和Local PV一样的特性的Agent。当前我们采用的折中方案是AdvanceStatefulSet+nodeSelector+Affinity来部署yarn和DataNode,不过我们没有大规模使用,因为不够优雅。


Kubernetes集群部署分布式系统总结


我们认为在Kubernetes上部署存储或者计算型的组件是可行的,做好外部世界和Kubernetes集群内部的通信,或者将所有的组件都放在Kubernetes集群内部。针对性能要求比较高的组件,采用Host模式+Local PV的方式部署。在没有人力和开源成熟的Operator的时候,可以先用Helm模板化部署方式,先解决自动化部署。提供可视化的运维操作,通过人工组合操作的方式先代替Operator自动化运维。将一些通用的功能搬到Operator之上,并将Operator定制化能力提供给用户,让用户成为你的开发者,共同构建Kubernetes生态。当前我们维护了自己的AdvanceStatefulSet Controller,提供镜像原地升级,指定下线节点的功能,维护一个基础的Base Operator,我们希望将一些功能通用的覆盖所有组件,针对Hive这种多节点类型的服务开发独立的Operator。在社区我们积极参与TiDB Operator的开发,我们觉得当前TiDB的云原生方案是比较成熟,利用TiDB Operator部署的TiKV我们已经上生产了。这些支持得益于我们对于Service Pod DNS的支持,赋予Kubernetes的网络和磁盘静态分配绑定的能力。


以前我们会部署一个大的分布式系统业务混用,比如ES,现在我们可以利用Kubernetes切成小集群,每个集群都做好日志和监控的功能,业务可以申请自己的集群,资源上是隔离的,不会因为资源互相影响。懂组件的业务也可以根据自己的场景,不断优化自己集群的配置。当我们对组件性能把控不到位的时候,采用小集群是规避风险的一种方式。


关于监控,我们使用一个集群配一个Prometheus+Grafana的方案,做到监控隔离,Prometheus我们采用Thanos架构,提供统一的监控查询。


监控参考:



关于日志,我们采用sidecar注入到Pod的方式,收集到Kafka,Flink落地ES,保留七天,我们可以针对日志做一些报警策略。


日志参考:



一些天生支持云原生的组件探索


除了已有组件尝试部署到Kubernetes,我们也在探索新的组件,比如JupyterHub,JupyterHub我们采用的是Ceph共享存储。基于JupyterHub接口能力,提供自定义镜像和定制化框架的能力,每个用户可以申请自己的Jupyter,分配固定的资源配比。我们也尝试部署了KubeFlow,想借助于TensorFlow Operator 部署分布式任务能力提升算法侧的能力,不过因为KubeFlow要绑定Istio组件,我们觉得太大了,所以没有将其放到线上。我们会基于Jupyter提供更好的数据分析层面的交互能力。


我们还部署了TensorFlow Server,打通HDFS和TensorFlow Server,用户使用Spark训练的TF model生成到HDFS之上,可以自动部署成TF server,做到模型的自动部署和滚动更新。还有Dask等等服务。


我们发现已有组件官方都在做云原生的支持,新组件会自带Kubernetes的支持,所以on Kubernetes未来一定可以走的更远。


遇到的问题和未来规划


在on Kubernetes这条路上,Kubernetes不能拿来即用,要根据自己的场景适配。在不影响已有业务的情况下,提供不改变用户行为的场景。原本用户可以很方便看到日志,知道请求落到哪个点上,那么你就需要提供很好的日志收集服务,提供更稳定的服务,才能让用户相信你的能力。


在网络方面,我们会尝试DPDK来加速容器网络以及其他硬件方案,将大数据服务本地性需求弱化,做到存储和计算的分离,提升扩展性。


在磁盘方面,我们会提供不同的规格的尝试,当前我们是混部,我们会提供LVS+混部+分区的方案选择,提供更灵活的部署方式。


在平台层面,我们会将机器和底层研发用户分开,可视化的运维集群,提升安全性和便捷。


在技术变革的快车道上,我们要制定好如何在行驶中换轮胎,甚至是换引擎。


Q&A


Q:存储集群,出现Pod迁移怎么解决数据盘问题?


A:Local PV,只要你不删除PV和PVC,不会产生Pod偏移。你可以使用Sts volume Template试试。


Q:以前做过Zeppelin(类似Jupyter的工具)+Spark的应用,经常因为各种队列资源计算不足需要调整配置那些,如果上Docker的话,这种方便操作吗?就是担心容器集群会不会不稳定?


A:方便的。当前我们使用JupyterHub来创建Jupyter,Jupyter和Spark集群打通,提供用户直接写代码和集群交互。不过要注意资源控制。我们直接和Spark交互用的是Apache的Livy。Kubernetes集群你提高稳定性就可以了,我们现在用的很稳定。


Q:日志监控保留一周,那资源利用的数据保留多久?比如CPU内存网络硬盘这些数据?


A:容器的监控我们保留12天。历史数据我们用的Thanos架构,保存到Ceph中。物理机的监控我们是放在小米的Falcon。


Q:如果Pod挂了,出现Pod自动漂移到其他节点,挂载的Local PV数据是否也要做迁移?


A:如果Pod挂了无法拉起,不删除PV和PVC,Pod是不会漂移到其他节点。这是Local PV调度决定的。如果需要漂移到其他节点,需要手动的删除PV和PVC,Pod漂移到其他节点,然后将有问题那个物理机上的数据迁移到新的PV上来。


Q:Thanos监控数据如何存放?查询速度比原生的Prometheus如何?


A:Thanos是Prometheus的高可用架构,我们用来做一个集中查询。历史归档数据是存储在Ceph中,Prometheus存储比如七天的数据,还是和原来一样存储在本地。查询速度我们使用下来还可以,查询速度取决于你的监控数据的体量,你可以做一些横向扩展,数据量大的时候该慢还是慢的。


Q:请问一下Pod指定IP是怎么实现的?


A:Kubernetes是支持CNI接口的,我们使用Contiv的netplugin插件,当Pod调度起来,会走CNI接口申请一个IP。根据Namespace+podname对应一个唯一标识,这个标识和IP是存储在一个单独的etcd中。podname用deployment部署是随机的,所以我们基本上都会用我们开发的AdvanceSts来部署,这样名字是固定的。


Q:Kubernetes是直接部署在物理机还是虚拟机上的?


A:物理机,我们OVS网络没办法在虚拟机上部署。


以上内容根据2020年1月14日晚微信群分享内容整理。 分享人 程威,同程艺龙数据中心Kubernetes负责人 。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiese,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。




推荐阅读
  • 本文详细介绍了HDFS的基础知识及其数据读写机制。首先,文章阐述了HDFS的架构,包括其核心组件及其角色和功能。特别地,对NameNode进行了深入解析,指出其主要负责在内存中存储元数据、目录结构以及文件块的映射关系,并通过持久化方案确保数据的可靠性和高可用性。此外,还探讨了DataNode的角色及其在数据存储和读取过程中的关键作用。 ... [详细]
  • 从0到1搭建大数据平台
    从0到1搭建大数据平台 ... [详细]
  • RocketMQ在秒杀时的应用
    目录一、RocketMQ是什么二、broker和nameserver2.1Broker2.2NameServer三、MQ在秒杀场景下的应用3.1利用MQ进行异步操作3. ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在当今的软件开发领域,分布式技术已成为程序员不可或缺的核心技能之一,尤其在面试中更是考察的重点。无论是小微企业还是大型企业,掌握分布式技术对于提升工作效率和解决实际问题都至关重要。本周的Java架构师实战训练营中,我们深入探讨了Kafka这一高效的分布式消息系统,它不仅支持发布订阅模式,还能在高并发场景下保持高性能和高可靠性。通过实际案例和代码演练,学员们对Kafka的应用有了更加深刻的理解。 ... [详细]
  • 在Java分层设计模式中,典型的三层架构(3-tier application)将业务应用细分为表现层(UI)、业务逻辑层(BLL)和数据访问层(DAL)。这种分层结构不仅有助于提高代码的可维护性和可扩展性,还能有效分离关注点,使各层职责更加明确。通过合理的设计和实现,三层架构能够显著提升系统的整体性能和稳定性。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • 美团优选推荐系统架构师 L7/L8:算法与工程深度融合 ... [详细]
  • 技术日志:深入探讨Spark Streaming与Spark SQL的融合应用
    技术日志:深入探讨Spark Streaming与Spark SQL的融合应用 ... [详细]
  • 修复一个 Bug 竟耗时两天?真的有那么复杂吗?
    修复一个 Bug 竟然耗费了两天时间?这背后究竟隐藏着怎样的复杂性?本文将深入探讨这个看似简单的 Bug 为何会如此棘手,从代码层面剖析问题根源,并分享解决过程中遇到的技术挑战和心得。 ... [详细]
  • 本文介绍了如何使用 Spark SQL 生成基于起始与终止时间的时序数据表。通过 `SELECT DISTINCT goods_id, get_dt_date(start_time, i) as new_dt` 语句,根据不同的时间间隔 `i` 动态填充日期,从而构建出完整的时序数据记录。该方法能够高效地处理大规模数据集,并确保生成的数据表准确反映商品在不同时间段的状态变化。 ... [详细]
  • Apache Hadoop HDFS QJournalProtocol 中 getJournalCTime 方法的应用与代码实例分析 ... [详细]
author-avatar
追忆幽梦_554
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有