纵横小说的上云之路

背景

       纵横自建站时选择IDC数据中心托管方案支撑业务服务,已经经过10+年之久。随着业务的不断增长,业务逻辑变得日益复杂, 对大数据量、低响应延迟、弹性计算资源、快速技术迭代与敏捷开发等都有了更高的要求。同时硬件设备逐渐老化,需要频繁的升级和维护,增加了管理和运维的复杂性,也带来了额外的费用和风险。面对业务波动和峰值流量时,传统IDC的弹性伸缩能力受到限制,导致资源分配不够灵活,已经开始面临难以应对突发性的问题。传统IDC的基础设施作为核心业务的支撑平台,已经存在很多吃力点。

       当前云计算的成熟为企业提供了迁移上云的机遇,带来了灵活的成本控制、弹性伸缩、管理简化和全球化部署等众多优势。纵横技术中心也决定拥抱云计算,使用云服务Iaas替代以往需要运维频繁关注的基础组件,提高技术驱动力加速业务发展。

       纵横由于长时间IDC的架构沉淀,内部已经形成了一套相对完整的体系,上云之路中很多系统架构和运维管理都会是其中的难点,本文将介绍其中重要组件的迁移方案与技术实践。

整体架构与迁移方案选择

       纵横在IDC中的服务组件结构如下图所示:

       云服务商我们讨论选择的是阿里云;同时计划此次上云迁移,将纵横与熊猫业务直接打通,所以地域上决定选择在北京;对于迁移上云过程中我们优先选择阿里云成熟SaaS产品作为迁移目标服务替代,其次再考虑开源工具,这样可以获得更多阿里云同学的支持,有更多的成熟案例可参考,并且大大减少运维同学的调研时间。

       讨论得出两种迁移方案:

       第一种、双DC多活的方式逐步迁移

       此方案通过搭建一条专线连接IDC与云上,但在初步测试中却发现其中存在很大问题。因为位于武汉的IDC距离北京阿里云的接入点物理距离太远,专线间延迟达到了17ms,这对纵横业务整体使用dubbo框架的服务之间RPC调用影响很大。高并发场景下测试节点负载大幅上升(如下图),同时服务响应时间增加到明显卡顿。此方案行不通。

       第二种、整体统筹迁移并一次性切换上云

       此方案通过提前在阿里云上部署完整服务架构,并以停机维护的方式一次性迁移至云上;由于是独立于IDC的完整架构,迁移周期和迁移的关键节点上就会有更高的要求;SaaS云产品替代开源组件需要提前做好兼容测试,无法逐步迁移的话就要做好迁移切换失败回滚方案。最终我们也是选择了此迁移方案。

整体迁移流程

1. 调研IDC开源组件对应阿里云替代的云产品
       正如上面提到,此次迁移同时也要尽量使用云产品替代现有开源组件,那么就需要对兼容性进行调研和严格的测试,无法解决兼容问题的依旧保持云主机上部署相同开源组件。主要涉及的组件如下表:

IDC组件替换云产品替换问题
LVSCLB无兼容问题,直接替换
DockerACK原本跑在Docker内的go应用,系统性的迁移到k8s(ACK),解决容器内外RPC网络直通问题
Redis阿里云Redis版需要将所有Redis升级到4.0以上(原IDC版本均在3.2版本以下)解决DTS数据同步的兼容问题
MySQL阿里云RDS需要将所有MySQL升级到5.7版本(原IDC版本均在5.5与5.6为主),同时解决业务兼容性,方可替换
Elasticsearch阿里云Elasticsearch无兼容问题,直接替换
ZooKeeperMSE无兼容问题,直接替换
Kafka阿里云Kafka无兼容问题,直接替换
RabbitMQ阿里云RabbitMQ无兼容问题,直接替换,但阿里云实例不支持自定义静态用户,需要在切换时独立配置
ELKSLS全栈日志收集与分析看板需要重新配置
GlusterFS阿里云NAS无兼容问题,直接替换
Harbor容器镜像ACR无兼容问题,直接替换

2. 确定云上完整技术架构
       各组件测试兼容替换的可行性后,确定云端环境完整的技术架构,最终如下图所示:

3. 整体环境部署,细化组件迁移方案
       确定好整体技术架构环境,开始每个技术组件进行迁移测试,并落成详细的组件迁移方案,记录迁移细节,细化组件的迁移或同步步骤,以便正式环境部署时进行参考。逐个组件在云上部署测试,直至完成整体的环境构建。涉及的几个比较关键的组件迁移下面会补充几个方案单独说明。
4. 数据同步方案
       整体云端兼容环境的部署完成,要实现业务的上云切换,最主要的便是数据到云端的同步。业务主要涉及需要同步的数据包括MySQL数据、Redis数据、RabbitMQ元数据、静态文件等。其中最主要的就是MySQL与Redis数据的同步,这里还涉及到切换失败切回有可能造成数据丢失与一致性问题,所以在数据同步方案选择时决定利用DTS实现MySQL的双活双向同步的方案,Redis也选择利用DTS进行数据同步,具体也会在下面补充详细说明。
5. 整体业务测试与性能摸底
       云上环境我们反复多次进行完整部署,全量数据同步也进行多次配置,以熟悉整个流程。同时每次全量数据同步之后,都会安排多轮的业务测试与性能测试,迭代优化掉过程中发现和可能出现的各种问题,确保最终迁移切换的顺利进行。
6. 迁移切换
       具体从IDC到阿里云的流量切换方案,我们选择停机维护期间进行,切换前将所有域名都接入到DDoS高防或者CDN,切换时在IDC入口挂维护页面进行全流量阻断,同时快速修改CDN和高防的回源IP到阿里云,避免等待DNS生效时间的问题。

7. 回退方案
       正如上一步图中所示,在整体方案中,主要数据都是进行双向的同步,原则上是支持自由切换入口流量的,所以回退方式也就相对比较简单,就是云测入口挂维护页面进行全流量阻断,CDN与DDoS高防回源改回到IDC入口。为了避免数据出现问题,不管是切换上云或是回退,我们都是保证入口只能同时从单一一侧进入。

主要组件迁移方案

MySQL数据同步方案

       MySQL的数据同步在讨论后决定以DTS双向数据同步实现数据的迁移,双向同步还有一个优点,就是可以实现云上和IDC的自由切换,上云切换便捷的同时也为失败切回做好了准备。

       纵横如果使用DTS还面临的一个问题,就是通过DTS同步数据到阿里云的RDS,支持兼容的自建MySQL版本最低需要是5.7及以上才行。此时就需要将所有业务MySQL升级到5.7版本。前期就要完全对比好5.6与5.7的版本差异与业务兼容问题,这里我们主要分三步进行。

  • 先梳理MySQL5.6与5.7的版本功能差异

       通过阿里云和mysql官网信息整理的5.6与5.7的版本功能差异表以及5.7版本新功能与弃用功能列表,结合纵横业务代码的sql情况,排查可能对业务造成影响的兼容问题。

  • 抓取线上业务所有SQL

       通过slow_log记录所有线上执行的SQL,通过pt-query-digest工具对SQL进行分析,通过生成指纹的方式进行合并和抽样,再通过pt-upgrade工具对5.6与5.7实例进行执行SQL的结果对比,排查确认兼容问题。

  • 对存在影响的SQL进行优化交于开发更新

       在以上梳理对比测试后,发现了两个对业务有影响的SQL问题:

       问题一:order by limit排序问题

       SQL查询结果出现了第二页数据重复的问题,是因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。在完成select之后,所有记录是以堆排序的方法排列的,在进行order by时,仅把Order By字段值大的往前移动。但由于limit的因素,排序过程中只需要保留到20条记录即可,Order By字段如并不具备索引有序性,所以当第二页数据要展示时,mysql见到哪一条就拿哪一条,分页是建立在排序的基础上,进行了数量范围分割,需要通过LIMIT查询优化解决。

       问题二:ORDER BY GROUP BY同时使用,结果集不一样的问题

       如果不加limit,系统会把order by优化掉,即mysql5.7中order by不起作用。在mysql5.7手册的8.2.2.1中有解释。子查询的优化是使用半连接的策略完成的使用半连接进行优化,子查询语句必须满足一些标准(In MySQL, a subquery must satisfy these criteria to be handled as a semijoin)。其中一个标准是:必须不是一个包含了limit和order by的语句(It must not have ORDER BY with LIMIT.)

       解决掉上面问题后,开始对线上所有MySQL进行无停机轮换升级,升级到5.7版本后开始配置测试DTS数据双向同步,最终在阿里云多次环境的部署测试后,未发现MySQL迁移上云方案存在问题。

Redis数据同步方案

       Redis在纵横业务中广泛使用,可以说也是非常重要的数据存储,在选择上云的数据同步方案时,也是考虑像MySQL一样通过DTS进行双向数据同步的方式。阿里云DTS虽然支持Redis双向同步,但要求是源和目标实例为均为阿里云Redis企业版且5.0及以上版,这不符合我们实际情况。

       之后我们又调研了x-pipe的多数据中心复制管理的方案,替换为x-pipe集群可提升可用性,同时可以提升多数据中心的管理,x-pipe整体架构图如下所示:

       x-pipe的架构和管理机制确实很优秀,不过我们目前Redis的时候有主从的结构,也有Redis集群的结构,这对于我们迁移上云前的准备就增加了先迁移Redis到x-pipe的过程,不仅增加的升级、调研、测试、迁移的整个时间排期,还增加了整个架构的复杂度。

       最终我们还是选择更为灵活和简单的一种方式:双DTS三实例同步的方式。

       简单来说就是由A-->B-->C的一种数据链同步。IDC到云上的数据迁移是通过DTS进行单向同步,也就是A-->B;要满足我们一直都在做的切回准备的话,就需要云上的数据也能实时的同步到IDC,在DTS不支持双向同步的前提下,我们就新起DTS将云上Redis同步到IDC的一套完整的新实例C中,也就是B-->C;形成一个半闭合的数据流向,而真正发生切回时,如果需要整体切回,就通过切换域名解析来实现A到C的切换,保障数据的连贯性。

       此方案只需要为了满足DTS兼容性对老Redis进行版本的轮换升级即可实现,在环境测试阶段也多次测试了Redis数据同步与切换/切回,没有发现任何问题。

静态数据同步方案

       纵横小说静态数据主要存储在GlusterFS中,由于GlusterFS采用的是FUSE(用户空间文件系统(Filesystem in Userspace,简称FUSE),是完全在用户态实现的文件系统。Linux通过内核模块对此进行支持,文件在GlusterFS上不会切块进行存储,也不会进行数据格式转换,而是数据文件按照原样存储,相应的数据文件可以直接拷贝直接使用。对于文件的同步方式就比较灵活,同时阿里云同学建议我们此次迁移可以考虑使用他们的OSS对象存储。对此我们也是讨论了两种方案;

       第一种、静态数据迁移至OSS

       纵横小说静态文件由于存储在GlusterFS这种FUSE文件系统中,所以在业务代码对于静态文件的存取是直接访问通过NFS协议挂载的本地目录进行存取的。如果将GlusterFS文件迁移到OSS,业务代码想要直接访问,就需要后端同学将涉及的逻辑全部修改为OSS对象存储的方式进行存取。要么就通过增加一层云存储网关再挂载至服务本地,这样既不需要业务代码也可以把静态数据迁移至OSS。

       第二种、静态数据迁移至云NAS

       云上NAS天然适配原生操作系统,提供共享访问,NAS在成本、安全、简单、可靠性以及性能上都具有自身的优势。并且NAS文件存储提供良好的协议兼容性,支持NFS和SMB协议方案,兼容POSIX文件系统访问语义。那么我们就可以直接启用GlusterFS的NFS协议通过文件迁移进行文件级别同步。同步配置简单,同步速度走专线的情况下也比较快。

       考虑到我们这次上云迁移还是以稳定可靠为前提,尽量少修改业务代码逻辑,尽量避免增加架构复杂度。最终我们还是选择的第二种方式进行静态数据上云的迁移,将静态数据迁移到阿里云NAS进行存储,由于文件数量较多,采取一次全量之后定时增量的方式进行同步。对于切回方案,也很容易通过对比最后文件修改时间进行反向数据同步。OSS虽然各个方面都比较优异,但是完全可以在上云后再统一进行替换,到时从云NAS到OSS的迁移既方便又快捷。

RabbitMQ的迁移方案

       对于RabbitMQ的迁移,按照原理特性,其实迁移切换相对是比较简单的,不过在上云前了解到阿里云的RabbitMQ是通过AMQP 0-9-1标准协议自研实现的,阿里云同学提示是需要对我们使用的客户端版本进行梳理排查是否存在兼容性。

       对此我们梳理了纵横业务的客户端使用情况,JAVA主要是spring-rabbit的1.4.6版本(依赖于amqp-client),Golang主要使用的是Go AMQP 0.9.1 client支持RabbitMQ 2.0之后的版本。

       RabbitMQ官方amqp-client客户端兼容支持情况:

  • 4.x 此客户端版本独立于RabbitMQ Server版本,并且兼容低版本的RabbitMQ 3.x版本,JDK支持1.6-1.8;
  • 5.x 此客户端版本独立于RabbitMQ Server版本,并且兼容低版本的RabbitMQ 3.x版本,JDK最低要求1.8;
  • 3.7.x 此版本开始,Java客户端不再追随 RabbitMQ Server版本,将独立区分客户端版本;
  • 3.6.x 以及之前版本是随RabbitMQ Server发布的,由于走amqp协议所以相近版本支持是没有问题的,线上amqp-client版本为3.5.5对支持Server 3.6.11版本比较稳定,相远版本不好验证建议升级amqp-client;

       基于以上对比阿里云版RabbitMQ,是完全兼容支持直接迁移至阿里云的。迁移也只需要元数据的一次性迁入即可,而且无需关心切回的问题。

       不过还是有两点注意事项:

  1. 阿里云RabbitMQ的静态用户名密码不支持自定义,是根据AK/SK自动生产的。所以在代码的配置上想要保持相同,就需要先在阿里云MQ实例生成静态用户名密码,再在开源MQ创建相同的用户名密码。
  2. 切换期间需要保证关注所有队列消费情况,需要保证所有队列消费完全再进行流量的切换,避免消费时序错乱导致的问题

Kafka的迁移方案

       Kafka在纵横小说业务中的使用场景主要是用在神策数据日志的同步。提供给UGC服务通过书id查询不同维度的点击量信息。对于Kafka消息队列来说迁移切换一样是比较简单好控制的。

       提前下载kafka-migration-assessment.jar工具,利用该工具从zk获取集群元数据并生成json文件,包含业务中完整的的topic和consumer group配置信息。将元数据进行提前迁移导入,然后等消费完旧集群的消息即可,过程中上层业务完全无感知。

总结与展望

       纵横小说业务从传统IDC迁移到云上的过程,历经数月,我们研发中心也是经历了一场全面的业务优化和改变的过程。上面提到的只是在最终上云执行中的一部分,而整个上云的过程是复杂且繁琐的,是在所有运维、后端、测试、产品等同学的一点点一轮轮的调研、讨论、测试中一步步完成的,其中的细枝末节都要经过数次的沟通测试,最终才成功完成上云的迁移。上云后也在慢慢加固云上业务的运维保障,体验到了云计算的便捷与种种优势。云上运维工具为我们带来了灵活性和弹性,使我们能够根据业务需求动态地扩展或缩减资源。不再需要提前投资于硬件设备,这使得资源的利用更为高效。高可用性和灾备机制保障了我们业务的持续性,同时为运维同学卸下了底层硬件维护的负担。监控与管理工具也更加的体系化,抛弃了之前IDC的零散的管理方式,优化补充了很多合规审计的漏洞。

       未来我们期待充分利用云上的资源和服务不断提升我们的业务水平,积极探索新的解决方案,以提高我们的运维效率、创新能力。上云也并非一蹴而就的过程,我们将持续关注新技术的发展,灵活调整我们的架构,这不仅仅是技术上的改变,更是一种全面的理念转变。

展示评论