云化背景
为了应对现代化的技术变革、业务诉求等诸多的挑战与风险,我们提出了传统应用现代化建设的“三步走”战略,及服务拆分、容器化、云原生架构升级。在领域驱动设计的加持下,我们顺利的完成了服务拆分,接下来我们迈出第二步,应用容器化。
上云价值
- 便捷的部署: 容器化允许开发人员在本地环境构建应用程序,并将其打包成一个可在任何地方运行的独立单元。这简化了应用程序在不同环境中的部署,并提供了更一致的部署体验。
- 资源利用率和成本效益: 容器化技术提供更高的资源利用率,使得应用程序可以更有效地利用计算资源。这有助于降低成本,尤其是在云环境中,因为它可以更好地适应按需分配的资源模型。
- 协作与持续交付: 容器化促进了团队之间更简单的协作,因为开发、测试和生产环境可以更加一致。此外,容器化还加速了持续集成和持续交付 (CI/CD) 流程,使得软件的交付更加快速和可靠。
- 可移植性和跨平台支持: 容器化提供了更大的应用程序可移植性,因为容器可以在任何支持容器运行时的平台上运行。这使得应用程序更容易在不同的云供应商之间迁移,也有助于构建跨平台应用程序。
- 弹性和可伸缩性: 通过使用容器编排工具,如Kubernetes,容器化应用程序可以更轻松地实现自动化的扩展和收缩,以应对不断变化的负载。
总的来说,容器化迁移的必要性在于提高开发、部署和运维的效率,降低成本,增加灵活性和可移植性,以及支持持续交付和云原生架构。
迁移步骤
- 评估和规划: 评估当前应用程序和基础设施,确定哪些部分适合容器化,并规划容器化迁移的整体策略。
- 容器化应用程序: 将应用程序及其依赖项打包到容器中。需要修改应用程序以更好地适应容器环境。
- 选择容器编排工具: 选择适合的容器编排工具,例如Kubernetes,以便对容器化应用程序进行部署、管理和扩展。
- 创建基础设施: 部署和配置容器化平台的基础设施,包括容器编排工具、持久存储、监控和日志管理等。
- 迁移和测试: 将容器化的应用程序部署到开发环境,并进行测试以确保应用程序在容器化环境中正常运行。
- CI/CD: 配置自动化部署流程,包括持续集成和持续交付工具,以实现自动化的构建、测试和部署。
- 扩展和优化: 根据实际需求调整和优化容器化环境,包括水平扩展、负载均衡、安全性和性能优化等方面。
- 培训和文档: 为团队成员提供培训,编写相关文档,使团队能够熟练地管理和维护容器化环境。
- 生产环境部署: 将容器化应用程序部署到生产环境,并确保高可用性、安全性和可扩展性。
- 监控和维护: 部署监控系统,跟踪应用程序的性能指标,并实施持续的维护和更新,以确保容器化环境的稳定性和安全性。
痛点环节
网络架构
- 云主机部署网络架构 - 传统云主机部署,基于云厂商的LB+Nginx实现多集群、多实例的负载均衡和服务发现。
- 容器化部署网络架构
- CNI - Calico
- 灵活性和可扩展性: Calico提供了高度灵活和可扩展的容器网络解决方案,能够适应各种不同规模和复杂度的部署。这使得它成为许多容器化环境的首选。
- 强大的网络策略支持: Calico支持丰富的网络策略功能,可以实现细粒度的流量控制和安全性规则。这使得它在需要严格网络安全控制的场景下非常有用。
- 基于BGP的路由机制: Calico使用BGP作为其路由协议,这使得它能够提供高效的容器间通信和跨主机的网络连接。BGP的使用也使得Calico在大规模部署中表现优异。
- 开源社区和生态系统: Calico是一个开源项目,并且有一个庞大的活跃社区支持和贡献。这意味着用户可以从开源社区的积极贡献中受益,并且有更多的支持和资源可用。
综上所述,选择Calico作为CNI的原因在于其灵活性、可扩展性、强大的网络策略支持、基于BGP的高效路由机制以及开源社区的支持,这些特点使得Calico成为许多容器化环境中的首选容器网络解决方案。
- 服务发现与负载均衡 - Consul+Nginx
| 方案 | 优点 | 缺点 |
|---|---|---|
| Nginx+Consul | 灵活性: 组合使用nginx和Consul提供了更大的灵活性,可以自定义负载均衡策略、健康检查和路由规则。自定义路由: 可以更容易地实现自定义路由规则,根据服务的不同路径进行流量转发。稳定性: Consul提供了服务发现和健康检查,有助于确保负载均衡器将流量发送到健康的服务实例。 | 复杂性: 组合使用nginx和Consul需要更多的配置和管理,相比Ingress更为复杂。维护成本: 需要花费更多的时间和精力来维护和管理nginx和Consul的组合。 |
| Ingress | 简化配置: Ingress提供了一种简单的方式来配置服务发现和负载均衡,可以通过Kubernetes资源声明进行配置。集成性: Ingress是Kubernetes原生概念,与Kubernetes集成紧密,使用Ingress能更好地利用Kubernetes自身的优势。 | 灵活性受限: Ingress的功能和配置选项相对较少,可能无法满足特定的高级负载均衡需求。定制性差: 无法轻松地实现特定的复杂负载均衡策略,需要额外的扩展或定制。 |
- 选型 - Consul + Nginx
- 从技术角度,更倾向于Ingress,其原生能力就已经满足了业务诉求,但是由于维护职责问题(SA负责),采用了Consul+Nginx,例如证书的维护。
资源隔离
- 性能隔离 - CPU/IO密集型应用
- Kubernetes 支持 CPU/IO 亲和性和反亲和性,通过 NodeSelector 和 NodeAffinity 来确保特定的 CPU/IO 密集型工作负载被调度到特定的节点或避开特定的节点,实现资源隔离。
- 根据应用类型,集群节点分为CPU密集型、IO密集型、通用型
- 资源超售
- 资源超售是不建议的,因为它可能导致性能下降和不可预测的行为。
数据同步
- 国内/海外单元化部署数据同步 - NDC (Netease Data Canal) 支持海外数据同步,NDC是网易自研的一套集数据迁移、数据订阅、数据实时同步于一体的数据传输服务,其大致可以分为源端系统、NDC集群和目标端系统三部分。
性能损耗
机房容器化迁移(阿里云云主机->腾讯云容器化)的过程中,发现容器化之后,在同等压测指标下资源规格要大很多。迁移后,同等资源或者大于原云主机资源的情况下,CPU/RT指标有明显的上升。怀疑是容器化的过程中有性能损耗。
- 问题分析
- 虚拟化开销
相比于传统的云主机,容器化引入了额外的虚拟化开销,包括轻舟组件、容器运行时、镜像管理和网络隔离等方面的开销,导致了资源消耗的增加,CPU尤其明显。
- 虚拟化网络(虚拟网卡、虚拟交换机、CNI-Calico)
容器化后,容器和宿主机在不同的网络namespace,数据需要在容器的namespace和host namespace之间相互通信(不同namespace的两个虚拟设备(veth pair)相互通信)通过虚拟的veth发送数据和真实的物理接口没有区别,都需要完整的走一遍内核协议栈,容器化使得整个数据发送路径变长。
- CPU调度差异
- 阿里云ECS:Linux内核提供了多种CPU调度算法,如CFS、Completely Fair Queuing、Deadline、Realtime等,阿里云基于此有针对性优化
- 容器:默认CFS;CFS(Completely Fair Scheduler)调度器追求的是对所有进程的全面公平,实际上它的做法就是在一个特定的调度周期内,保证所有待调度的进程都能被执行一遍,主要和当前已经占用的CPU时间经权重除权之后的值(vruntime)来决定本轮调度周期内所能占用的CPU时间,vruntime越少,本轮能占用的CPU时间越多;总体而言,CFS就是通过保证各个进程vruntime的大小尽量一致来达到公平调度的效果.
- 问题定位
- 问题方向 - 虚拟化网络造成的CPU增高
- 对比测试
- 用同等规格的云主机做测试,排除底层硬件的区别
- 容器vs云主机,网络使用hostwork,保证其他的不变
- 网络方案是calico,使用hostnetwork跟非hostnetwork做对比
- 验证测试
- 增大QPS观察CPU/RT曲线的变化
- 测试结论 - 入口服务,非CPU密集型
- hostnetwork
- Calico
- hostnetwork
- 问题结论
在容器化环境中,虚拟化网络开销由CPU承担。低负载的情况下,仅仅反映在CPU的消耗上面,高负债的情况下更容易出现应用、GC吞吐量降低的问题,从而影响整个集群的RT。
- 问题方案
我们需要为容器化买单,这点是超出我们意料的。
负载均衡
- 问题 - 实际生产环境中遇到了负载不均衡问题,导致RT增加明显
- 问题原因
- 集群内部服务直接使用k8s svc了
- K8s SVC的负载均衡基于IP tables实现,对于keep-alive的请求无法实现动态的负载均衡
- 文本聚类、分类检测服务只有两个节点(N-1=1),发布过程中只能逐一发布,这样会加剧负载不均衡的现象,例如,A\B两个实例,在初期处于均衡状态,但是发布会导致A下线,所有的链接转发到B,而A1上线后,keep-alive的链接仍旧保持在B实例上。
- 解决方案
| 方案 | 细节 | 优点 | 缺点 | 备注 |
|---|---|---|---|---|
| K8s升级 | 当前K8s版本1.19,从1.20起支持keep-alive的负载均衡 | 无需任何网络架构、代码适配成本 | K8s版本升级难推动 | |
| 引入代理-Ingress/Nginx | 不直接使用SVC,使用SVC前置代理 | 无需代码适配 | 需要调整网络架构,多引入一层代理,维护成本、资源成本增加 | 当前线上使用的Ingress |
| Client侧负载均衡 | 定期主动打破现有的长链接,实现负载均衡 | 无需网络架构调整 | 需要代码适配 | 目前方案为Client侧的负载均衡优化,链接最多保持300s |
| Server侧负载均衡 | 同上 | 同上 | 同上 | Server侧感知较为困难 |
- 方案选型 - 内部服务走Ingress
性能压测
- 问题 - 海外机房压测无法达到预期QPS和RT
- 正常压测
- 海外表象
- 原因
- 国内压测机压海外服务由于高延时导致错误率增加、并发链接无法达到预期
- 国内出口流量遭到安全拦截,导致服务链接失败率大大提高
- 方案 - 外海集群使用海外服务器压测
迁移总结
当我们梳理完迁移步骤,很多时候会在潜意识里认为这些操作都是按部就班的执行就可以了。但在实际的落地过程中,遇到了许多的“被刺”,有些是因为方案不够完善,有些是因为职责不够清晰,还有些是因为容器化自身的原因。但容器化为我们带来的收益和价值,值得我们为这些“被刺”买单。同时,也为后续的多区域机房的建设扫平了阻碍,为后续的云原生架构升级提供了条件。接下来,我们将继续前行,解开云原生架构升级的序幕。