记一次完整的上云经历

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 记一次完整的上云经历

大家好,我是坤哥


好久没更了,最近几周身体不好,得了比较严重的胃炎+心动过速症状,跑了好几趟医院,严重的时候心脏感觉很不舒服,有濒死感,胸闷气短,有时几乎整夜睡不好觉,在此奉劝大家还是要保重身体,千万不要做熬夜等伤身体的傻事,千万保重身体!


年前和年后我们完成了一次从 0 到 1 的上云之旅,其中踩了不少坑,也积累了不少宝贵的经验,所以在此总结成文,相信大家看了肯定有收获


先说下此次上云的背景,创业后,我们的业务是从集团中独立出来了,不过系统还是和集团共用的,共用系统本来也不是个事儿,但由于集团早已今非昔比,核心人员都走得差不多了,导致一些核心系统不稳定,甚至出现过反向代理层宕机无人修复而导致整个交易跌零的严重事故,所以我们决定将系统完全从集团中剥离出来,由于之前集团系统上云采用的是腾讯云,所以我们也用了腾讯云,这样网络可以做到互通,共用一些待迁移的系统的镜像,也可以用腾讯云的工具对数据进行增量/全量迁移等以降低迁移成本


云服务都有哪些



现在上云可以说是业界公认的趋势了,因为像阿里云,腾讯云等云厂商提供的工具真的太全了,基本上覆盖了一个大厂系统所需的方方面面,不信?我们不妨一起来看看,先来看下大厂的基本系统架构:


网络异常,图片无法展示
|


可以看到一个完整的可运行的系统需要提供:DNS 解析,CDN 服务,接入层,中间件,存储层,APM 等,云上这些工具全有 ,而且基本都是一键部署,这里简单举两个例子


  1. 以部署 ZK 集群为例,如果你要部署一个 ZK 集群,那一般要在三台虚拟机上部署(ZK集群要求至少提供三台服务器),还需要编辑配置文件等,涉及到这种人为的工作往往比较容易出错,但在腾讯云上点个按钮就可以自动帮你生成一个 ZK 集群,你所要做的只需在工程中替换此 ZK 集群地址,同时还可以查看它的基本信息(部署架构),数据管理运行监控(JVM,连接数,内存使用率等),运行日志
  2. 再比如你要部署一个 Redis 分片集群,一开始可能只需要一个分片,但后面随着业务的发展,需要进行分片扩容,那就比较麻烦了,一般需要用官方提供的 redis-trib 管理软件进行迁移,涉及到创建新的节点,将新的主节点加入集群转移slot(重新分片)将从节点加入集群这些步骤,很烦琐,但如果用腾讯云本身提供的工具,只要选择对应的分片选项,再点确定,即可一键搞定(如下),非常方便,同样的,腾讯云也提供了 Redis 的缓存命中率慢查询CPU 使用率等监控
    网络异常,图片无法展示
    |


以上只是简单举了两个例子,事实上,像 MySQL,ES,MQ 等组件腾讯云上也基本都提供了一键式生成的操作,并且都附带了相关的监控与告警机制,极大地降低了运维成本,使用这些工具唯一的缺点就是


网络异常,图片无法展示
|


但我们也有一些控制成本的手段 ,比如:


  1. 如果项目是内网的话(如运营中心等),完全可以把这些项目都部署在同一台低配的虚拟机上以节省成本
  2. 线上多个前端项目也可以同时部署在同一台机器上,配合 CDN 可以解决访问过慢的问题
  3. 我们需要部署 APM(查看分布式调用链,JVM 监控等),就得在机器上布署 Skywalking 这样的分布式追踪框架以便采集数据,如果在每个服务的每台机器上都采集其实没有必要,成本也比较高,所以我们后来调整为了每个服务只有一台机器进行采集,并且降低了采样率,这样上传的数据就少很多,可以降低成本,采用这样的方式之后, skywalking 的采集数据成本只需要每天 10 元左右


数据迁移



由于我们之前的系统是与集团共用的,现在要独立成一套,那就必须搞独立的 ZK,独立的 Redis,独立的 MQ,独立的数据库。。。,所有的这一切显然需要做到数据的平滑迁移,具体的操作如下


  • 数据库迁移:使用腾讯云上的数据迁移服务,进行全量+增量的升级,保证数据的一致性后再把数据全部切成我们的库
  • 配置中心数据迁移:之前集团使用的 ZK 作为配置中心,所以我们直接使用了一款开源好用的迁移工具 zkcopy,执行以下命令即可完成 ZK 的数据迁移


java -jar target/zkcopy.jar --source server:port/path --target server:port/path
复制代码


  • Redis 迁移:另建一个 Redis 实例(只是 host 不同),使用 AOP 的形式让原 Redis(集团 Redis)在写入后新 Redis 也写入,这样维持一周左右,基本上就能把 Redis 的数据迁移完毕,伪代码如下


@Slf4j
@Aspect
@Component
public class AopRedisReadWriteAspect {
    @Resource
    private RebateNewCacheClient rebateNewCacheClient;    // 新 Redis 实例
    // RedisCacheClient 即集团 Redis 实例,使用 AOP 的方式可以让集团的 Redis 写入的同时也同步到我司的 Redis 实例来
    // 从而最终实现数据一致性
    @Around(value = "execution(* com.xxx.RedisCacheClient.setex(" +
            "String,int,String)) && args(key,expire,value)")
    public Object setEx(ProceedingJoinPoint joinPoint, String key, int expire, String value) {
        rebateNewCacheClient.setEx(key, expire, value);
        return invokeOrigin(joinPoint);
    }
      private Object invokeOrigin(ProceedingJoinPoint joinPoint) {
        try {
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            // 打印日志
        }
        return null;
    }
}
复制代码


  • MQ 迁移:首先 MQ 的创建和 ZK 集群等创建一样方便,我们要做的,只是确定好分区数等,确定好之后动动手指点击一下,这样就会一键生成一个高可用的 RocketMQ 集群,包括各种监控,消息状态查阅等也应有尽有,如果你自己部署估计要搞半天,在迁移的时候,我们做了两手准备,一是同时向集团和我司的 broker 发消息,然后灰度一部分用户,这部分用户只向我司的 broker 发消息,确认没问题后,再停掉发集团的 broker 逻辑,这样可以做到平稳过渡


Ansible 简介



虽然云上有很多服务可以帮助我们快速接入 Redis 等中间件,快速迁移 DB 等数据,但除了这些基本上云服务可以提供的并不是说我们其他啥也不用干了,接下来我们来谈下本文的重点:项目部署的架构设计。比如一个 Java 项目,你要跑起来,总得先编译打包(生成 jar 包)吧,打包之后发布总不能立马中断正在运行的服务吧,你得用优雅停机的方式来停掉服务然后再部署新包,部署之后如果发现有问题要回滚吧,这些步骤如果用手工操作肯定不现实,最好的方式其实是写成脚本的方式然后一键部署,不过一个服务可能有多台机器,难道我们需要一台台登录然后再手动触发相应的部署脚本?显然不现实,所以我们需要一个批量部署的自动化运维工具,经过调研,我们选择了 Ansible

什么是 Ansbile ,它有什么优势?

Ansible是一款简单的运维自动化工具,只需要使用ssh协议连接就可以实现批量系统配置批量程序部署批量运行命令等功能


网络异常,图片无法展示
|


ansbile 有以下几个优势:


  1. 它是通过 SSH 来接管对应机器的控制权的,对应的机器无需安装任何的 ansible 客户端,也无需启用额外的服务,所以即便 ansible 升级也不影响对应的机器
  2. 有大量常规运维操作模块,可实现日常绝大部分操作
  3. 配置简单、功能强大、扩展性强;
  4. 通过 Playbooks(剧本) 来定制强大的配置、状态管理,所谓剧本,即 YAML 格式文件,多个任务定义在此文件中,定义主机需要用哪些模块(主要有核心模块和自定义模块)来完成这些功能


由于它的上述这些特点,ansible 很快流行了起来,甚至可以说是运维必备的一款神器了,上图是 ansible 的极简版,我们再稍微展开一下它的架构看看


网络异常,图片无法展示
|


它的执行流程如下


  1. 用户登录(一般通过跳板机) ansible 所在机器
  2. 通过 Host Inventory 来指定要控制的主机,这个一般是个 yaml 文件,我们可以在此文件中指定所有我们可以控制的 host,另外一个服务通常有多台机器,我们也可以指定哪些机器属于某个服务,这里简单举个例子


all:
  hosts:
    10.100.1.2:
    10.100.1.4:
    10.100.1.5:
  children:
    build:
      hosts:
        10.100.1.2:
    operation_center:
      hosts:
        10.100.1.4:
        10.100.1.5:
复制代码


  1. 上图中, 10.100.1.410.100.1.5即属于同一个服务 operator_center ,如果我们到时要发布这个服务的话,只需要指定其服务名 operator_center 即可(下文会介绍)
  2. 通过步骤 2 我们即可指定需要操控哪些机器,然后 ansible 再通过连接模块(即 Connection Plugins,采用 SSH 连接)连接步骤 2 中指定的 host 然后利用核心模块(core modules)等来执行我们写好的 Playbooks(剧本)


ansible 的 core modules(核心模块)有很多,功能也很强大,基本不需要自定义模块,像我们这次上云也只用了核心模块,来看几个比较常见的模块


  1. shell模块:可以在远程主机上调用 shell 解释器运行命令,支持 shell 的各种功能,例如管道等。
  2. copy 模块:将文件复制到远程主机,同时支持给定内容生成文件和修改权限等
  3. file 模块:设置文件的属性,比如创建文件、创建链接文件、删除文件等
  4. fetch模块:从远程某主机获取(复制)文件到本地(即 ansible 所在机器)
  5. command 模块:在远程主机上执行命令,并将结果返回到调用机上(也就是 ansible 所在主机)
  6. cron 模块:定时任务模块,这个大家应该比较熟悉了


我们知道一般工程都需要构建(或者说打包,两个概念相差不大)之后才能部署,比如 Java 工程要打包成 Jar 文件然后再部署(执行 Jar 包),前端工程也需要打包后才能部署(比如把多个 js 文件合并成一个以减少请求提升性能,再比如你可能使用 SCSS 或 less 来写 CSS,也需要编译成 CSS 文件,并且合并起来),那么问题来了,能否直接在生产机器上执行打包操作呢?答案显然是否定的,主要有两个原因


  1. 打包由于采用了各种优化手段(比如并行打包等)是很耗费 CPU 的,如果在生产上正在对外服务的机器上执行打包操作的话,那么很可能由于打包时耗费的 CPU 过大而导致当前正在执行的机器出现响应太慢,拒绝请求等问题,这显然是不可接受的
  2. 服务是以集群的形式存在的,可能一个服务有好几台机器,这些机器部署其实所需的 jar 包完全是一样的,没有必要在各个机器上都执行一遍通过的打包操作


部署架构设计


综上,我们需要一个专门的打包机,将打包的工作交给打包机,打包机打包好之后,我们再把相应的包发到生产的机器上,然后再执行部署脚本,架构模型如下


网络异常,图片无法展示
|


通过这样的方式,打包机承担了所有繁重的活,打包之后,ansible 会通过 fetch 模块将这些 jar 包拉到本地,然后再通过 push 模块把 jar 包 push 到服务集群上的所有机器,然后再执行比较轻量级的部署脚本


提到上文中的诸多模块,大家可以没有什么概念,那么接下来我们一起来看下 ansible 如何利用上文所述的几个核心模块来完成我们所设计的这个打包部署步骤,这样大家对 ansible 的功能也能有更全面的认识


样例脚本我们一一介绍下:有三个文件


  1. production-hosts.yaml 文件:即我们上文提到的的 host inventory


#production-hosts.yaml
all:
  hosts:
    10.100.1.2:
    10.100.1.4:
    10.100.1.5:
  children:
    build:    # 打包机
      hosts:
        10.100.1.2:
    operation_center:   # operation_center 服务
      hosts:
        10.100.1.4:
        10.100.1.5:
复制代码


  1. 打包 playbook: java-build.yaml


# java-build.yaml
- name: build project artifact
  hosts: build    # build 表示打包机,定义在 production-hosts.yaml 文件中
  tasks:
    - name: Pull source code and checkout branch
      ansible.builtin.git:
        repo: '工程git地址'
        dest: workspace/operation_center
        version: master
        force: yes
    - name: Grant execute permission to build.sh
      ansible.builtin.file:                         # file 模块
        path: workspace/operation_center/build.sh
        mode: '0755'
    - name: Build project                           # 执行打包脚本
      ansible.builtin.shell: ./build.sh             # shell 模块
      args:
        chdir: workspace/operation_center
        executable: /bin/bash
    - name: Create archive project  # 打包后会生成 jar 包,创建目录存放存放即将压缩后的 jar 包
      ansible.builtin.file:
        path: archive/operation_center
        state: directory
      args:
        chdir: /home/buser
    - name: Archive latest artifact   # 压缩 jar 包到上一步创建的目录中
      ansible.builtin.shell: cp workspace/operation_center/target/operation_center.jar archive/operation_center/latest.jar
      args:
        chdir: /home/buser
    - name: Fetch project artifact to local   # 使用 fetch 模块将上一步压缩的 jar 包从打包机拉到 ansible 所在机器上
      ansible.builtin.fetch:
        src: archive/operation_center/latest.jar
        dest: /tmp/operation_center/
        flat: yes
    - name: Fetch bin file to local   # 将部署脚本从打包机拉到本地,准备传给线上机器执行部署操作
      ansible.builtin.fetch:
        src: /home/buser/workspace/operation_center/deploy.sh
        dest: /tmp/operation_center/
        flat: yes
复制代码


  1. 部署 playbook: java-deploy.yaml


# java-deploy.yaml
- name: Deploy project
  hosts: operation_center # 表示线上服务器,定义在 production-hosts.yaml 文件中
  serial: 1
  any_errors_fatal: true    # 只要一步失败,部署流程即终止
  tasks:
    - name: Upload artifact & restart project
      block:
        - name: Push project artifact to remote   # 将 ansbile 上的 jar 包 push 到服务器上
          ansible.builtin.copy:
            src: /tmp/operation_center/latest.jar
            dest: /opt/apps/business/operation_center.jar
        - name: Push deploy file to remote        # 将 ansbile 上的部署脚本 push 到服务器上
          ansible.builtin.copy:
            src: /tmp/operation_center/deploy.sh
            dest: /opt/apps/bin/
        - name: Start operation_center
          ansible.builtin.shell: bash bin/start.sh    # 执行部署脚本
          args:
            chdir: /opt/apps
            executable: /bin/bash
          environment:
            appEnv: prod
        - name: Health check 8001                     # 健康检查
          uri:
            url: http://127.0.0.1:8001/service/health/deepCheck
            return_content: yes
            status_code: -1
          register: this
          failed_when: "'health' not in this.content"
          when: health_check == "8001"
        - name: Health check 8081
          uri:
            url: http://127.0.0.1:8081/health/check
            return_content: yes
          register: this
          failed_when: "'health' not in this.content"
          when: health_check == "8081"
      become: yes         # 在线上服务器上以 root 身份执行上述的部署步骤
      become_user: root
复制代码


有了以上三个文件,只要分别执行打包和部署操作 playbook 即可,如下


ansible-playbook -i production-hosts.yaml java-build.yaml     # 打包
ansible-playbook -i production-hosts.yaml java-deploy.yaml    # 部署
复制代码


可以看到只要使用 ansible 的核心模块即可完成我们的打包部署需求,执行流程会通过上文中的 name 展示,部署流程部分展示如下


网络异常,图片无法展示
|


可以看到整个流程部署流程非常的清晰!


为了方便起见,以上脚本只是简单介绍了一下打包部署的部分步骤,其实我们还需考虑回滚等操作,由于不是本文的重点,所以这里就不再做介绍了。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
机器学习/深度学习 人工智能 自然语言处理
从服务内部到实现商业化,美团云所经历的这两年
100 万单、 1000 万单到 1400 万再到 1600 万单的峰值,美团点评的外卖日订单迅速上涨。与此同时,配送体验要求也在不断提升,平台也始终面临运力的挑战,必须不断平衡配送成本和配送体验的要求。
426 0
从服务内部到实现商业化,美团云所经历的这两年
|
存储 SQL 关系型数据库
加入阿里技术团队三年,哪些习惯让我在工作上持续受益?
2017年研究生毕业,我加入阿里巴巴数据库技术团队,从事分布式数据库研发,如今算来已经有三年时间了,在这期间,我深度参与了双十一背后的数据库PolarDB-X从设计到实现的全过程。在这三年的时间里,于我而言,最大的收获来自两方面:
3900 0
加入阿里技术团队三年,哪些习惯让我在工作上持续受益?
|
运维 监控 Cloud Native
考拉上“云”的431天:经历了怎样的“脱胎换骨”?
今年双11,是考拉海购加入“阿里动物园”的第二年,其成绩单备受外界关注。 加入阿里431天,考拉交出了一张漂亮的成绩单:会员规模增长104%,刷新过往双11纪录。 很多人不知道,增长来之不易——2019年9月,考拉被阿里正式收购后,经历了一场“脱胎换骨”:数据库应用架构重新设计、百万级节点的容器集群大规模迁移、数据中心从杭州机房迁移到上千公里之外的张北、从基础组件到中间件全面拥抱云原生……
考拉上“云”的431天:经历了怎样的“脱胎换骨”?
|
数据安全/隐私保护 网络架构
在阿里网络团队实习两年是一种怎样的体验?
大家好!我是田冰川,南京大学2016级直博生,导师为田臣老师,研究方向为计算机网络。2018年6月,我以研究型实习生的身份入职阿里巴巴基础设施事业部网络研究团队,实习期间主要从事网络验证相关的研究工作,即通过形式化方法与灰度测试,来降低网络变更中的潜在风险。
2461 0
在阿里网络团队实习两年是一种怎样的体验?
|
人工智能 大数据
【已更新回顾视频】金融云化之路:让你少踩坑,保险领域老司机和你一起聊聊金融企业上云的那些事
随着DT时代的到来,上云成了金融企业跟上时代步伐最迫切、也最至关重要的一步。由于金融自身的特殊性,如何选择可靠的云平台,成了当下难题。为此,云栖说邀请一位已经上云的金融用户天安人寿姚仁毅和山虎,现身说法他们是怎么想怎么做的?同时阿里云金融专家戴飞飞、张伟伟也会一起聊聊金融企业上云的那些事。
4206 0
|
SQL 前端开发 安全
阿里云新品发布会周刊第47期 丨 加入阿里技术团队三年,哪些习惯让我在工作上持续受益?
新产品、新版本、新技术、新功能、价格调整,评论在下方,下期更新!关注更多新品发布会!
2450 0
|
云计算 架构师 容器
对话首席架构师|阿里云迁云实战解析(一):全面上云拐点已到,云架构师get 何种技能?
摘要:本文整理自驻云科技首席架构师,阿里云MVP苏炎的分享。本文首先将与大家分享苏炎对云架构师的理解以及目前整个中国云计算市场的发展趋势和上云需要关注的重点。
3774 0
|
机器学习/深度学习 监控
初创企业的成长之路,如何走好第一步?
“作为公司管理,最让我难过的不是没有客户,而是客户来了把握不住!”-------来自某初创公司的管理者沟通交流 当代的企业竞争是残酷的,每个细节都可能决定着成败,做好服务是企业长久立足的根本,如何活下去?如何走好第一步?
经历:我被网络公司坑了之后用上了阿里云
很久之前,我找网络公司建了一个小网站。 我根本不懂建站这块,对服务器了不了解。 当时跟我说的是交钱,给我建好网站,然后就可以上了。 交了两年的服务费,然后前不久到期了。 我的悲剧就开始了。 坏人坐地起价,我无计可施。
2509 0