背景介绍说起有状态应用,要从无状态服务讲起。无状态是指应用的实例可以平滑迁移、水平扩展,实例之间没有显著差别。这类服务在云原生化过程中与 K8s(包括 Deployment)等对象配合得很好,因此成为第一批云原生受益者。 有状态应用指持有特定的数据、并依赖其提供服务的应用,大规模场景中通常具备分片(Sharding)和多副本(Replica)、数据持久化等特点。有状态应用又分为数据有状态和网络有状态。数据有状态应用有如下一些特点:1)数据依赖:运行过程中依赖本地数据;2)数据持久:升级前后数据不能丢失;3)依赖关系:服务实例之间存在主从、主备等依赖关系,因此每个实例有唯一的 ID 标识;4)网络有状态应用:指容器内业务服务要保持较长的网络 session。网络有状态是数据有状态之外的一种形态,本文分享的内容主要围绕数据有状态应用在字节的落地展开。
02
有状态应用业务场景字节内部大量应用了有状态应用。一些常见的场景有:1)搜索召回:实例需要加载大的模型,时间很长。如果每次升级都需要重新加载数据,对网络和存储会造成比较大的资源浪费,对业务的迭代效应也会造成很大影响,因此这些业务比较依赖本地存储。2)推送:有一些服务实例间有强依赖关系或者对实例有唯一 ID 需求。典型的如推送业务,每个实例负责一个分片用户的推送,对实例有唯一 ID 需求。3)存储服务:包括自研 KV(类 Redis 存储服务)、Druid、ES,兼顾了以上两种有状态的特点,既要依赖本地存储,同时服务间有实例依赖关系也就是唯一 ID 需求。在云原生化之前,服务多是通过物理机部署的。物理机时代的架构复杂、运维不够灵活敏捷、物理机环境不一致、资源碎片化等问题一直没有得到很好的解决。这也正是云原生化关注的痛点,字节对云原生的理解体现在效率和成本两方面。效率1)基础设施的标准化:云可以屏蔽底层系统(计算、存储、网络)的复杂性,抽象出统一的 API 接口,让用户表达对底层基础设施的需求。2)业务框架抽象化:业务的编排形态可以进行统一管理。3)规范流程自动化:让应用的更新和维护、运维变得更简单。4)交付形态一致化:基于镜像或容器技术让业务运行时保持统一的状态。成本1)应用迭代和发布的成本:关注秒级拉起容器,给业务更大的迭代、开发空间。2)资源成本优化:按需分配业务所需要的资源。当然云原生化这条路也不是一帆风顺的,在有状态应用的状态管理、基础能力增强和自动化运维等方面都存在一些挑战,在此过程中我们也解决了很多相关技术问题。总体来说,在内部 K8s 基座上我们通过编排的优化(包括 CRD、Controller、webhook 等能力)以及在基础能力方面的增强(包括性能优化、存储能力的增强),已经承接了内部上千个有状态服务,覆盖 2w+节点,100w+ CPU Core,5w+ Pod。