重构国内游戏账号登录系统的思考和实践

本期作者

背景

账号登录系统,作为游戏发行平台最重要的应用之一,在当前的发行平台的应用架构中,主要承载的是用户的账号注册、登录、实名、防沉迷、隐私合规、风控等职责。合规作为企业经营的生命线,同时,账号登录作为在线链路转化的第一站,因此账号登录系统的稳定性,一直面临极高的要求。

出于稳定性需要,游戏发行平台在很早期就实践了两地三中心的多活架构。目前以公司公司机房为中心,同时在华东公有云和华南公有云,实现了两地三中心部署方案。依托公有云的主要考量因素在于,早期公有云提供的快速弹性和按量付费的能力,能够高效的承接游戏业务方的发展诉求;其次,对于华南地区的选择,也是优先考虑重要合作方所处的地理位置。

基于稳定性、效率、成本的多方考量,最终实现了公司机房、华东公有云A、华南公有云B的混合云架构。混合云架构带来便利的同时,也存在普遍的挑战,其中最显著在于两个方面:

其一、数据架构,数据在云端存储的存在的泄露风险。在具体实施层面,数据架构的差异化,将会导致底层的领域服务所能交付的API必定存在差异,主要差异体现在API的能力范围。比如,bilibili授权登录等能力,云上机房是无法做到实际支持的,服务端只能将相关请求转发至公司机房处理。

其二、PaaS平台的差异。公司基础架构在数据库管理平台、KV数据管理平台、消息队列等产品支撑已相当成熟,但早期在公有云的应用部署只能依托云原生的能力。这导致在底层的依赖上,原本需要建立一个标准防腐层,屏蔽具体的实现差异,但因为业务进度的需要,导致有所折中欠缺。

由于存在以上两个显著的挑战,项目进展等因素的考虑,最终演变的应用架构如下,也因此账号登录系统,在公司机房和公有云机房演变出了两套代码仓库(login-idc-api / login-cloud-api)。

图片

游戏账号登录应用的两套代码,迭代至今已近7年。当前应用,虽然在主观上理解已经迭代趋于稳定,但是基于最近一年完成的迭代版本统计,全年迭代版本超过10次,版本平均耗时接近4周,包括设计、开发、测试、上线。双代码仓库导致的设计、开发、测试,部署平均耗时增加了30%~40%。其次,在双代码仓库,且依赖Spring等核心组件版本较低的情况下,对齐公司基础架构的各项产品,可预见工作量的前提之下,该系统的重构工作,已经到了不得不行的地步。

挑战

为稳定性诉求极高、迭代长久的系统发起重构,需要巨大勇气,得失于转瞬之间。

  1. 重要性:承载千万MAU,L0不可降级链路;支撑113个SDK版本(采样周期:2024/02/15 - 2024/03/15)

  2. 稳定性:重构过程中SLO 4个9的约定,必须在执行之前规划完成执行细节和过程,全面又不失细致;

  3. 复杂度:业务本身内在的复杂度,7年来的高速发展,积累的大量技术债。

价值

1.效率:开发效率提升50%,迭代效率提升30%-40%

2.成本:节省人力(预期当前系统的生命周期至少5年)

3.质量:

  • 代码圈复杂度:降低40%;

  • 内网调用去SLB依赖,核心链路接口RT 99.9Line 提升31.5%

4.文化:践行“极致执行”的价值观。

实践:如何实现重构?

战略方向

方案一、放弃现有的两地三中心,账号登录全部统一到公司标准,不依赖云厂商。该方案作为未来的长期方向,完全回公司部署符合公司长期战略规划,难点在于发行平台的应用架构,目前绝大多数服务还是重点依赖公有云,短期内不具备独立完成的可行性。

方案二、推动主站账号团队,打通公司和公有云的数据架构,实现领域能力的对等,但存在数据安全风险,考虑到项目收益和跨团队的工作成本,并非当前最高ROI的选择。

方案三、将双代码仓库中,有关于数据架构和PaaS的差异,以重构的办法实现兼容,达到最终的代码仓库统一。

思考过程

重构的前提

回顾Martin Flower有关重构的著作《重构 改善既有代码的设计》一文中,将”重构“以名词、动词两种方式定义如下:

重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。

重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

这本关于重构的经典,在两种定义方式中,提到了3个关键概念,”调整“、”结构“、”不改变软件可观察行为“。这3个关键词组合起来,约等于行动指南。”不改变软件的可观察行为“作为前提,如何理解可观察行为,Martin并未在技术和业务上做过明确的定义,因此在这个概念的理解上,不免要多一些执行者的个人理解和思考。

如果把应用架构视为当前的结构,对于“可观察行为”的理解,从以下几个角度尝试去思考:

1.系统职责,前后端分离的应用架构之下,交付这些职责的API是一类可观察的行为;

2.系统依赖项,是一类可观察的行为,包括两个大部分:

  • bilibili账号的领域服务、游戏发行的领域服务、第三方服务(比如:极验服务提供商)

  • PaaS基础架构(公司的数据库、KV数据系统、消息队列等等;公有云的云MySQL、Redis、Kafka等等)

3.系统的横向服务。从分层架构的层次上来说,当前定位是应用服务层BFF,本不应该出现较大的横向影响,但是过往高速演进的过程中,承载了部分领域服务的职责(比如:查询游戏信息、查询活跃游戏、查询用户信息等),因此姑且对于这一类概括为横向的影响。

形形色色的差异

当前应用架构下,双仓库在逻辑模块、应用内分层(J2EE的3层模型)的特点,展示如图:

图片

在不可变的前提之下,试图通过对齐双仓库代码差异,以求得统一的思路,单从Service这一层来说(其依赖的bilibili账号服务API超过80个),理解起来已足够让人头大,其变更风险也是极其巨大,更何况还有JDBC ORM、Redis在技术选型和使用约束上的差异。如此风险再加上即将投入较大的工作量,势必提案困难重重。基于静态的模块和应用内代码分层来看,这巨大的差异看似是无法“暴力”抹平。

消失的复杂度

柳暗花明时刻,来源于应用运行时的一个事实:“生产环境多次高可用切流”。这个事实不仅实现了对SDK上游异地多活的承诺,而且经过了生产环境的多次验证。简而言之,双仓库在Controller、Service这两个最业务逻辑最复杂,技术债积累最多的分层,虽各有千秋,但殊途同归。

由此推理,重构过程中的最大的认知注意力负担,可以直接从这两层忽视。这两层注意力的移除,同时也利好DB和Redis的兼容工作量,作为基础架构中最重要的两个组件,完全无需再关注各类RedisTemplate/Jedis,Key命名、JdbcTemplate/Mybatis 、SQL的之间的逻辑差异,因为他们只是Controller和Service最终呈现出来的一部分。

在混沌中聚焦

SDK API链路:由于Controller、Service复杂度的消失,那么剩余的不可变的可观察行为,就只集中在DAO。DAO差异的本质来源于混合云部署架构的挑战(数据架构、PaaS差异),那么实现策略也就清晰了,在DAO层基于运行时ZONE来标识依赖的bilibili账号API调用即可。参考六边形架构,对于外部依赖和业务逻辑的隔离方式,实现核心业务逻辑对于外部API和PaaS解耦,以此降低变更侵入的影响面。

图片

PaaS的差异在业务逻辑层Service(或者少量的Controller)已经被消化,因此无需再考虑逻辑上的差异,只需关注框架和数据库的版本兼容性。

领域类和通知类API链路:这条链路虽然不是核心,但这是混合云数据架构差异的体现。生产环境的调用集中在公司机房,能力”较小“的公有云应用,向公司应用融合靠拢,也正因如此,统一之后的代码仓库是以公司机房代码仓为基准。

转发类API链路:这条链路差异化的本质也是来源于混合云部署的数据架构差异,在当前的融合方案中无法解决,因此只能沿用现有的转发策略,但转发后续可向上移交至API GW实现,这个已在计划当中。

具体实现

图片

公司机房原仓库为基准,在公有云A/B可用区部署,可用区选择与当前两地三中心保持一致。依赖的DB Schema在三机房原本就相同,因此可直接复用已有的DB实例。Redis,因其均有读写操作,避免灰度过程对于线上应用的数据污染,因此部署单独的Redis集群用于数据隔离,待完成灰度之后,一并下线原应用和原Redis集群。

数据验证

产品视角

  1. 基于用户维度,验证比对新老集群的数据写入和查询;

  2. 基于游戏维度,验证比对新老集群的数据写入和查询;

  3. 生产环境SDK,基于测试域名,实现核心SDK产品回归验证,覆盖全量用例;

  4. 其他非SDK API,实现全量的单测覆盖,基于接口实现验收。

数据视角

  1. 数据库:基于Job任务,实现源与目标数据源内容比对;

  2. 缓存:纯缓存场景,灰度期间隔离部署,回滚后不影响业务逻辑。缓存未命中直接远程调用;

  3. 埋点/报表:基于灰度过程观察游戏维度的报表趋势,并与过往数据进行比对。

发布方案

发布计划设计,严格遵守公司安全生产要求:可灰度、可观测、可恢复。

可灰度

灰度过程一共分为两个大步:

Step1

在公司机房执行灰度部署,分批部署导入生产流量,发现异常立即回滚。

Step2

在公有云A执行全量发布,但未接流;通过SLB规则配置,基于域名、规则的重要性、API的量级(调用量/周)制定规则级的SLB发布计划。公有云B部署同样重复此步骤。

可观测

观测的主要维度:业务和SLO、日志、性能

观测1:原公有云A应用流量切流后分布和成功率

图片

观测2:新公有云A应用流量切流后分布和成功率

图片

观测3:新公有云A应用错误码分布

图片

观测4:新公有云A应用API性能

图片

观测5:新公有云A应用JVM性能

图片

可恢复

1.公司机房应用执行灰度部署,如遇异常立即回滚,且不产生脏数据

2.新的公有云A/B应用,通过SLB基于规则分批发布,如遇异常立即回滚,回滚后流量指向原有对应机房服务集群,Redis写产生的脏数据不影响回滚后业务逻辑

3.新的公有云可用区,申请单独的Redis实例,用于隔离不同代码仓库,不同Key命名风格的数据,避免回滚过程中脏数据,对于原可用区服务的影响。

参考资料

  • 《B站安全生产专项建设实践》 https://mp.weixin.qq.com/s/tj1PEUWAyRZ1QzeW_oCWfg

  • 《重构 改善既有代码的设计》Martin Flower

  • 《Complexity Has to Live Somewhere》https://ferd.ca/complexity-has-to-live-somewhere.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557677.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构系列-堆的实现

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 堆的实现,其实也就是二叉树的实现,我们在这里是基于数组对其进行实现的! typedef struct Heap {HPDataType* a;int size;int capacity; }HP;…

毕业设计做一个linux操作系统怎么样?

毕业设计选择做操作系统的话,不太建议做的规模太大,你可以参考一下Linux内核的代码量,完全从头写的工作量还是挺大的。如果是一行一行从头写,学生期间,一学期写10000-20000行有效代码就很强了,而且还要学习…

【面经】2024春招-云计算后台研发工程师1(3个问题,移动TW等)

【面经】2024春招-云计算后台研发工程师1(3个问题,移动&TW等) 文章目录 岗位与面经基础1:数据库 & 网络(3个问题)基础2:系统 & 语法模板3:算法 & 项目(移…

探索人工智能绘图的奇妙世界

探索人工智能绘图的奇妙世界 人工智能绘图的基本原理机器之美:AI绘图作品AI绘图对艺术创作的影响未来展望与挑战图书推荐👉AI绘画教程:Midjourney使用方法与技巧从入门到精通内容简介获取方式👉搜索之道:信息素养与终身…

Timelapse - 2024.04.09 -Win

阅读须知: 探索者安全团队技术文章仅供参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作,由于传播、利用本公众号所提供的技术和信息而造成的任何直接或者间接的后果及损失,均由使用者 本人负责,作者不为此承担任何责任,如…

centos6.5重启docker容器死机问题

概述 近期在整理服务问题,使用docker容器重新部署服务。 过程中有不少坑,主要是系统配置和系统版本的问题。 环境 CentOS release 6.5 (Final) docker version 1.7.1 问题现象 使用restart命令重启docker容器,系统突然卡死&#xff0c…

protobuf抓包,读包

protobuf抓包 有时候会遇到使用protobuf协议的http请求, 而protobuf封包后的二进制几乎不可读, 如何调试呢 protobuf就是类似一个json的数据传输协议, 相比json更快, 体积更小; 缺点就是不可读 Content-Type: application/x-protobuf数据大概是下面这样的(浏览器开发者工具 自…

(十八)C++自制植物大战僵尸游戏的游戏暂停实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/uzrnw 游戏暂停 当玩家遇到突发事件,可以通过暂停功能暂停游戏,以便及时处理问题。在激烈的游戏中,玩家可能需要暂停游戏来进行策略调整。此外,长时间的游戏对战可能会让玩…

爬取微博评论数据

# -*- coding: utf-8 -*- import requests #用于发送请求并且拿到源代码 from bs4 import BeautifulSoup #用于解析数据 1.找到数据源地址并且分析链接 2.发送请求并且拿到数据 3.在拿到的数据中解析出需要的数据 4.存储数据 headers { "User-Agent": "…

ubunt18.04安装ROS2

本文无废话,实现了ubunt18.04 下ros2的安装,并且同时兼容ros和ros2 如果想完ros(1)的,请参考我的前一篇文章:ubunt18.04安装ROS避坑指南 参考: https://blog.csdn.net/cau_weiyuhu/article/deta…

Ubuntu20.04版本命令行设置挂载磁盘,并设置开机自动挂载

最近部署应用 系统是Ubuntu20.4版本的Linux系统,加了数据盘,需要格式化后挂载,记录下: Linux 数据盘挂载(采用 parted 分区工具)-格式化为 ext4 1. 初始化 Linux 数据盘 挂载数据盘后或者随实例创建时一并创建的数据盘&#xff…

【数学建模】最优旅游城市的选择问题:层次分析模型(含MATLAB代码)

层次分析法(The analytic hierarachy process,简称AHP)是一种常用的决策分析方法,其基本思路是将复杂问题分解为多个组成部分,然后对这些部分进行逐一评估和比较,最后得出最优解决方案。(例如&a…

Linux 5.10 Pstore 学习之(二) 原理学习

目录 编译框架模块初始化pstore子系统ramoops模块初始化实例化注册回调数据结构 pstore_blk模块pstore_zone模块 测试扩展调试 编译框架 目标结构 linux_5.10/fs/pstore/ ├── blk.c ├── ftrace.c ├── inode.c // 核心1 ├── internal.h ├── Kconfig ├── …

Vitis HLS 学习笔记--scal 函数-探究

目录 1. Vitis HLS重器-Vitis_Libraries 2. 初识scal() 3. 函数具体实现 3.1 变量命名规则 3.2 t_ParEntries解释 3.3 流类型详解 3.4 双重循环 4. 总结 1. Vitis HLS重器-Vitis_Libraries 在深入探索Vitis HLS(High-Level Synthesis)的旅程中&…

了解 containerd 中的 snapshotter,先从 native 开始

本文内容节选自 《containerd 原理剖析与实战》,本书正参加限时优惠内购,点击阅读原文,限时 69.9 元购买。 上一篇文章《一文了解 containerd 中的 snapshot》中,介绍了containerd 的 snapshot 机制,了解到 containerd…

64B/66B编码 自定义PHY层设计

一、前言 之前的一篇文章讲解了64B/66B的基本原理,本篇在基于64B/66B GT Transceiver的基础之上设计自定义PHY。基本框图如下。 二、GT Mdule GT Module就按照4个GT CHannel共享一个GT COMMON进行设置,如下图。要将例子工程中的GT COMMON取出&#xff…

3.4 海思SS928开发 - 烧写工具 - BurnTool Emmc 烧写

3.4 烧写工具 - BurnTool Emmc 烧写 BurnTool 工具提供了多种烧写方式,这里只介绍最常用的 烧写emmc方式。 环境准备 PC 与单板之间连接好调试串口以及网线。 将厂商提供的出厂镜像拷贝至 PC 硬盘上,解压后得到的文件如下: . ├── boot_…

解决Ubuntu安装NVIDIA显卡驱动导致的黑屏问题

前言 本文是在经历了3天内5次重装Ubuntu系统后写下的,根本原因就是这篇文章的主题——安装NVIDIA显卡驱动!写下本文是为了让自己今后不再出同样类型的错误,同时,给其他出现同样问题的人一些启发! 本文实例的电脑配置如…

WEB前端-笔记(二)

一、事件 1.1类型 focus 获取焦点事件 ipt.addEventListener("focus", () > {.log("") }) blue 失去焦点事件 ipt.addEventListener("blur", () > {console.log("") }) inout 文本输入事件 txt.addEventListener("i…

实在智能协办2024中国核能行业RPA数字员工专项培训会

2024年中国核能行业RPA数字员工专项培训会于4月16日-19日在杭州举办,由中国核能行业协会信息化专业委员会主办、实在智能承办。本次培训由理论讲解、技术深化和实际操作三部分组成,旨在帮助核能行业从业人员学习与掌握基于大模型的RPA技术应用&#xff0…