架构实践:同时支持单体、微服务,单台服务器还能支撑十几万用户?

e095e503351c7ee740fd8fc851b8e847.png

dd6280aac54e67fcec3c9b13a09278e4.gif

??目录

1背景

2搬迁实践

3搬迁过程中的一些挑战

4落地成果

5 总结

面对十几万用户 SaaS 服务迁移的巨大挑战,如何在单台服务器上实现高效、稳定、安全的部署运行?

本文详细探讨了这一挑战背后的技术实践过程,包括技术架构的演进、面临的挑战及解决方案,以及最终实现的架构维度和资源维度的显著收益。通过这一创新实践,微服务数量从30+锐减至个位数,资源占用大幅下降,仅需 8C16G 即可轻松应对,为企业在成本、效率及灵活性上带来前所未有的突破。

关注,一手技术干货提前解锁??

//

12 月 26日晚 7:30,视频号「鹅厂程序员面对面」直播间,我们邀请了作者来为你分析《资金视角看支付系统架构设计》,预约观看有机会抢鹅厂周边好礼!

01

背景

1.1 前言

为了满足不同场景、不同的行业的用户诉求、以及为了满足传统行业安全合规等问题,都会要求采购的软件需要在本地化环境部署运行。在这种场景下,我们如何把公有云的 SaaS 平台服务搬迁到微搭单台服务器上?

传统的私有化是将所有服务涉及的计算+存储私有化,微搭低代码平台作为开发/运行平台,不仅承担了开发工具的职责,也承担了运行部署平台。这就意味着我们同时要把开发平台和运行部署平台都要搬迁到单台服务器上。

1.2微搭是什么

腾讯云微搭低代码是一个高性能的低代码开发平台。免前端开发,支持一码多端,自由定制管理系统和小程序,PC/H5 应用,支持连接本地和外部数据库,支持 AI 大模型自动生成页面,快速集成各类 AI 模型,支持被集成,一条命令将系统私有部署到任意服务器。支持打通企业内外部数据,轻松创建数据分析、业务管理、消息推送、用户权限等能力的企业管理系统。快速连接腾信生态,支持原生小程序,助力企业内外部运营协同和营销管理。

295f61395fc4bfe49c4546e76e42014c.png

02

搬迁实践

2.1 产品的形态

微搭低代码产品整体上分为两部分:设计态和运行态。

设计态:应用工作区,用来开发应用 ,把开发好的应用构建发布成物料。

运行态:应用运行环境底座,基于设计态开发好的物料,做部署安装。

0d4d519464c778e22655b459a5b11ea1.png

2.2技术架构

基于这种业务形态,结合我们公有云本身就是微服务的架构体系。我们快速落地了技术架构。

微搭低代码混合云的整体架构,包含基础服务、网关服务、服务控制、容器平台以及支撑组件;

  • 基础服务负责前端和后端 API 的接入,通过 DNS、LB 将用户请求分发到不同区域的控制台;

  • 网关服务负责对后端和前端流量分别进行处理;

  • 服务控制包含了所有微搭所有的服务组件**(微服务粒度30+)**,包含权限控制,数据模型,流程,消息中心,应用管理,企业工作台管理等;

  • 支撑组件,包含 MySQL、MongoDB、Redis、Kafka、S3 对象存储等 。

fbaa02749fda6aac1c2a2a87c58ac017.png

我们架构推进过程中,也遇到了一些问题挑战:

  1. 微服务粒度30+ ,针对私有化场景下客户机器数量有限。有没有一种方案可实现可以同时支持微服务和单体架构?

  2. 公有云产品能力实时迭代,软件化这块如何与公有云保持同步

下面我们来看下,微搭在这两个挑战上是如何解决的?

03

搬迁过程中的一些挑战

3.1 架构挑战

3.1.1 架构演进

有没有一种方案可实现可以同时支持公有云的微服务和软件化可合(单体)架构?

微服务 是「可分」

单体架构 是「可合」

我们要支持公有云的架构是「可分」,私有化的架构是「可合」,并且原则是:以公有云的微服务架构为基准。

那这块我们的思路是:「可分」单个微服务可以编译成单个进程,「可合」也可以编译成子模块集成到大进程中 这样相当于把30+个进程从架构基于领域来大大进行了压缩 。

注意:这里主要是将后端服务来做合并,因为本身前端只有一个微服务进程。

b79b11ba72edc9b932d92d6a37f246ef.png

3.1.2架构方案实现

原则是:以公有云的微服务架构为基准,通过搭建一个单体应用的S pring 启动框架,通过 dependency 将微服务的 jar 引入进来,通过 @ComponentScan来排除掉各个子进程的启动类 。

只启动单体应用的进程,进而达到 N 个进程合并成1个进程的效果。

单体架构应用:没有任何逻辑,只有启动类和一个配置文件。

a88788dccdd28bd8448079451a290780.png

单体应用启动类伪代码如下:

@EnableFeignClients
@ComponentScan(basePackages = {"com.tencent.weda"},
        excludeFilters = {@ComponentScan.Filter(
        type = FilterType.ASSIGNABLE_TYPE,
        classes = {
                com.tencent.weda.WeDaBusinessApplication.class,
                com.tencent.weda.ServerApplication.class,
                com.tencent.weda.DsServerApplication.class,
                com.tencent.weda.DsAdapterApplication.class,
                com.tencent.weda.WeDaAuthServerApplication.class,
                com.tencent.weda.WedaApiServerApplication.class,
                com.tencent.weda.Application.class,                               com.tencent.weda.WedaWorkflowServerApplication.class,
                省略xxxxxxx.class
        }
)}
)
@SpringBootApplication
public class WedaApplication {


    public static void main(String[] args) {
        SpringApplication.run(WedaApplication.class, args);
    }
}

3.2服务合并落地挑战

架构上制定了服务合并的策略,那么接下来看下服务合并存在哪些问题和挑战?

3.2.1bean 冲突改造

如果各个业务中存在同名的bean,在 Spring 启动的时候,会基于 name 加载到 Spring 容器中,造成 Spring 启动失败 ,为了避免 Bean 冲突。

有以下处理策略:

1.每个微服务修改包名 ,基于「领域」修改包路径。例如:权限加 auth、流程加 workflow 等。

85119c265e8154b0099bdf5b965a6fa5.png

2.如果业务中存在通过之前 name 来注入 Bean 的。比如 @Bean(name=“”)、@Resource(name=“”)、@Autowired(name=“”) @Service(name=“”) @Qualifier(name=“”) 等,建议加上业务「领域」属性,避免冲突。

4459a8721cf7fca8406882e91ae9939d.png

3.2.2Feign + Consul 调用改造

我们公有云微服务之间的服务注册调用都是使用 Feign +Consul 来实现的。

由于是单体应用,软件化这块就没必要再使用 Consul 了(当然这块不是必须要修改的,不做修改也没问题。我们主要考虑是减少中间件的依赖)。因为单体应用对外提供的接口能力都是127.0.0.1, 所以需要我们把 Feign + consul 调用 ,改成 Feign + localhost (127.0.0.1)。

@FeignClient 注解默认也提供了这样的能力(在 @FeignClient 注解中,url 属性的作用是指定目标服务的 URL 地址)。

通过增加 url 属性值来制定到目标服务的 url 地址。

业务微服务 添加 url=“${spring.feign.ip:}”,公有云 url 默认为空(还是基于注册中心来进行选择实例),在软件化 yaml 中将该值设置为127.0.0.1:port 即可。

示例:

6a213f619f14e2d45d8e5449ffe59230.png

3.2.3 pom.xml 改造

原来公有云 pom.xml 有 dev、test、pre 和 prod 的对应的 profile,增加一个私有化所对应的 profile 节点 private,这样对公有云构建和编译也不受任何影响。

在单体流水线构建出包的时候,各个微服务的 SPRING_PROFILE=private。

mvn clean install -DskipTests -P$SPRING_PROFILE -s ../settings.xm

另外需要注意的地方,需要在 private 节点中移除 spring-boot-maven-plugin 的 maven plugin 和排除掉微服务中的 resources 配置文件。

(因为配置文件已经统一合并成一个了,在单体项目中引入即可)

# 私有化环境
<profile>
    <id>private</id>
    <build>
         <resources>
                    <resource>
                        <directory>src/main/resources</directory>
                        <filtering>true</filtering>
                        <excludes>
                        <exclude>application.properties</exclude>
                            <exclude>bootstrap.yaml</exclude>
                            <exclude>bootstrap.yml</exclude>
                            <exclude>application.yaml</exclude>
                            <exclude>application-*.yaml</exclude>
                            <exclude>application.yml</exclude>
                            <exclude>application-*.yml</exclude>
                        </excludes>
                    </resource>
                </resources>
    </build>
<profile>

3.2.4配置文件改造

通过制定规范来进行管控和约束。每个微服务 yaml 合并一个 yaml 。所有微服务的 yaml 针对存量的 key 统一做合并,新增的 key 统一加下微服务前缀标识来区分,确保每个微服务的 key 各不相同。

weda.model.xxx:123
weda.auth.xxx:456
weda.connector.xxx:789

3.3 公有云的数据库 DDL 与 DML 如何自动同步到软件化中?

那么技术上如何保证公有云的数据库 DDL 与 DML 自动同步到软件化中呢?在架构上我们设计了一个旁路服务,通过定时扫描监听 公有云数据库的 DDL 与 DML 变动,形成 SQL 物料 - 自动同步到 软件化的物料包中 ,这样软件化的数据库 就能实时与公有云保持同步。

9d57b3aad204d6379f240fe8dad55841.png

公有云还保持原来的设计和链路,软件化这块做适配。针对微服务使用不同的 database,这块软件化统一合成一个 database,由统一的 init-data 服务来完成数据库的创建和初始化。

bea4e0eb9b7d824bda77542d3f755bf6.png

3.4 如何简化服务运维以及功能准确性?

3.4.1合流 + 自动化测试保障单体架构

为了保证单体应用功能的正确性,我们在公有云合流阶段做了流水线,当公有云微服务代码合并主干分支时触发「软件化应用」构建&部署 。如果部署成功,会执行自动化测试用例来提前发现私有化功能上的一些问题(通过技术手段来保证:用来检测每个微服务 yaml、Bean 要互斥,不能出现同名的 key 和同名的Bean)。

af1d51319a883def932a9170692d54f5.png

3.4.2服务做了合并,出问题了如何定位代码分支

下面我们再来看下服务做了合并,出问题了如何定位代码分支?如果说单体架构中某个业务模块出现问题/报错了,如何定位到其错误信息具体对应公有云的 git仓库上的 commit/代码片段?

1cbc4fc9aa05cb8b49095e19f1ed6216.png

我们在软件化出包的时候,会实时获取到每个微服务对应的 commitId(微服务出包时对应的分支/tag),实时写入/推送到固定的 git 上,业务研发同学可基于当前部署包的版本号来统一查找各个微服务对应的 commitId,从而快速定位到具体公有云微服务对应的代码片段。

ae4c5790632d3b7e873cb6741e5993b4.png

04

落地成果

4.1架构维度

从架构上来看:

我们进行架构改造实践落地后,从之前的微服务架构做了大量的服务合并,微服务数量从 30+个 变成个位数 。

72d905b59f5946b3b6396ffbddbe5ac9.png

4.2资源维度

从资源维度来看:新架构下占用的机器资源大幅下降。

公有云微服务架构下30+服务,占用大量的cvm 资源,软件化的架构下由于服务做了大量合并,这块仅需 8C16G 就可以运行起来。

4.3交付客户

我们能力上把十几万用户的公有云使用的 SaaS 服务搬到只使用1台服务器就可以部署运行,那么我们能够满足什么的客户呢?我理解有以下诉求的客户都可以考虑来使用我们。

  1. 客户机器 IDC 预算不足(机器数量有限,我们只需1台 8C16G 机器)。

  2. 私有部署开发模式,开发者可在本地服务器上使用微搭低代码本地部署管理工具进行应用开发。

  3. 有本地软件化部署的诉求 (一键部署本地化系统到任意服务器,5min 完成安装运行)。

  4. 支持多平台 小程序、web、H5。

  5. 集成企微等相关能力。

总而言之,腾讯云微搭低代码提供了应用开发的一站式低代码开发服务,从底层能力迭代至行业级方案,前后端一体可视化构建发布,让您能够完全专注于业务场景,小白也可以极速搭建出成熟、专业的应用。

05

总结

我们把十几万用户的公有云 SaaS 搬到单台服务器的实践来看,对于客户来说有以下优势:

  1. 微服务的减少让响应更快了。

  2. 新架构资源让用户投入的硬件资源更少了,成本更低了。

  3. 客户预算不足的,有跨平台应用开发需求的,应用需要本地化开发的,都可适配这个版本(而且我们再不断完善)。

当然了,也不是说软件化可合并的架构比微服务架构要好,可合并架构在运维方面相对(微服务)而言还是有些弊端。至于是在交付业务时选择软件化架构还是微服务架构,我想这块没有一个严格确切的答案。主要还是要基于业务场景来权衡利弊,在业务发展中不断探索最合适的模式。

软件设计的首要目标应该是满足业务需求,而不是为了设计而设计。如果一个设计没有为业务需求服务,那么它就是过渡设计,是没有意义的。

-End-

原创作者|谢艳祥

29579dfeef80bd651b337f46994903d4.png

你觉得把十几万用户搬到单台服务器最大的难点是什么?欢迎评论留言。我们将选取1则优质的评论,送出腾讯云定制文件袋套装1个(见下图)。1月2日中午12点开奖。

9eb1ca321f42bb29f27cca3bddab62de.png

???欢迎加入社群,享前沿资讯、大咖干货,找兴趣搭子,交同城好友,更有鹅厂招聘机会、限量周边好礼等你来~

a8d7db3d649b3da0ff69cc4817a5ac73.jpeg

(长按图片立即扫码)

c081d210ab28089fc321737fb292940b.png

[这里是图片021]

[这里是图片022]

[这里是图片023]

1a980456992c3cd1011e65235cd424e4.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值