写点什么

【腾讯云 TDSQL-C Serverless 产品测评】一场 ServerLess 方案和 Native 方案的小 PK!

作者:为自己带盐
  • 2023-08-29
    河北
  • 本文字数:5976 字

    阅读完需:约 20 分钟

【腾讯云TDSQL-C Serverless 产品测评】一场ServerLess方案和Native方案的小PK!

一、背景介绍

1.1 TDSQL-C ServerLess

在开始测评之前,先来认识下今天的主角吧——TDSQL-C ServerLess 关于该产品的说明,官方站点有非常详细且生动的介绍。其实,某种程度上,我们就可以把这个产品理解成 MySQL Plus 或 PostgreSQL Plus,也就是不用在关心,安装,性能,扩缩容,自动备份等复杂的配置性操作,这些将全部由腾讯云自动完成,我们只需要关注和业务的对接,就像办理手机套餐,只需月初月末关注下资费,真正做到即开即用。更多介绍:👉https://cloud.tencent.com/product/cynosdb


截止到发文(2023.8.28,serverless 形态的 TDSQL-C 只有 MySQL 版是可用的,PostgreSQL 的产品架构正在升级,后续可能还会有更多版本的数据库支持)

1.2 测评思路

根据活动的测评要求,我这里主要的测评目标是兼容性并发可靠性 3 个方面。



测评形式就是在本地跑通一个简单的项目,然后不修改任何代码,直接切换到 TDSQL-C ServerLess 产品,并分别进行一场压力测试,看看结果如何。


*注意:此次测评不涉及部分量化的性能指标,因为内网环境 VS 云端环境,有一个绕不开的变量,就是网络,在这方面内网肯定是碾压云端的,而此次测评的环境是在我本地的内网环境,不在腾讯云的服务器上,那通过外网链接到 TDSQL-C Serverless 数据库时,网络延时是避不开的,所以,我这次重点只关注刚提到的兼容性,并发和可靠性 3 方面。

1.3 开通服务

在开始之前,再简单介绍一下开通服务的流程,虽然本次活动主办方为开发者提供了免费账号👇



但了解过计费规则之后,我觉得,使用 ServerLess 形态的产品,按量计费完成这次测评顶天也就十来块钱不到的成本,所以决定真正的开一个服务来测试!开通基本流程如下


  • 进入 TDSQL 产品页👉https://cloud.tencent.com/product/tdsqlc,点【立即选购】

  • 形态选 Serverless,引擎目前支持 MySQL 和 PGSQL,其他按需填写,自动暂停选项勾上(省钱省心省力),计费模式我就直接选的按量计费

  • 填写集群的基础信息和配置,点【立即购买】即可


整体的流程其实也没啥可说,按页面提示一步步操作即可,我这边截了两个图👇




开通之后,到控制台界面,可以看到我们自己开通的数据库集群,需要注意的是,为了方便后面的使用,我们可能需要创建一个非 root 账号,创建流程就是点击下面👇,这个界面的【账号管理】,根据页面提示创建即可,非常简单,不再赘述。



配置好后,可以用本地的客 GUI 工具连接一下看下效果👇



好了,到此,云数据库就准备好了,接下来可以进入下一环节~

二、PK 方案

我这里的测评 PK 方案是这样👇


  • 先使用内网环境的数据库,跑通一个简单的业务(本地数据库使用 MySQL 8.0.34)

  • 分表

  • 编写一些简单的涵盖修改,查询数据库的操作,直接面向数据库,不经过任何中间件

  • 跑一下性能测试

  • 不修改任何代码,直接切换到 TDSQL-C ServeLess 地址,再跑一下性能测试


通过测评,可以得出迁移到 TDSQL 的平滑程度也就是兼容性,并发能力和稳定性的相关数据,为我们实际的业务上云提供客观的数据支撑。

三、搭擂台

在测评之前,咱先来准备个简单的项目,为了尽可能把变量控制在数据库层面,我这里采用统一的项目框架(.net 6),统一的 ORM(EFCore 7.0),分表中间件采用 ShardingCore,建立 2 个数据模型,并通过显示声明外键的方式建立一对多关联(避免分表查询时产生笛卡尔积而造成连接数爆炸)。除此之外,不再额外引用任何和数据读写相关的中间件,直接把请求打到数据库层,看看效果如何。


本篇会贴上一些关键的代码,并不完整,只为让此次测评过程更加的清晰,完整地址在这里:https://e.coding.net/tony_df/TestWeb/TestWeb.git

3.1 创建项目

通过命令行,或者使用 VS 集成开发工具,创建一个测试项目,项目形态可以是 web,控制台,或是.net 框架支持的任何终端形态(现在的.net 已经是全平台框架了哟~)我这里选择的是 web 项目,下图是准备好的项目结构。


3.2 配置项目

用熟悉的方式,引入此次需要的一些包文件,我这里主要用到了 Pomelo.EntityFrameworkCore.MySql,ShardingCore。全部的包引用配置如下👇


<ItemGroup>  <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.21" />  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10">    <PrivateAssets>all</PrivateAssets>    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>  </PackageReference>  <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />  <PackageReference Include="ShardingCore" Version="7.7.1.13" />  <PackageReference Include="Spectre.Console" Version="0.47.0" />  <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /></ItemGroup>
复制代码

3.3 创建模型,配置分表规则

这里,我引入的模型关系是考试和试卷的关系,每场考试包含多张试卷,这里采用 EFCore 的 CodeFirst 模式来维护数据库模型,其中对试卷表(Paper)进行分表操作。

3.3.1 创建模型

public class Examination{    //主键,采用Yitid插件提供的数字生成器ID    public string Id { get; set; }=YitIdHelper.NextId().ToString();        public List<Paper> Papers { get; set; } = new List<Paper> { };        //其他属性,节约篇幅这里就不一一列举了    ...}
复制代码


public class Paper{    //主键,采用Yitid插件提供的数字生成器ID    public string Id { get; set; }=YitIdHelper.NextId().ToString();        public Examination Examination { get; set; }        //显示声明考试id外键     public string ExaminationId { get; set; } = "";        //其他属性,节约篇幅这里就不一一列举了    ...}
复制代码

3.3.2 FluentAPI 定义模型属性

配置完成后,使用 EFCore 提供的 FluentAPI,设定其模型关系


public class ExaminationEntityConfig:IEntityTypeConfiguration<Examination>{    public void Configure(EntityTypeBuilder<Examination> builder)    {        builder.ToTable(nameof(Examination));        builder.HasKey(x => x.Id);        //...    }}
public class PaperEntityConfig : IEntityTypeConfiguration<Paper>{ public void Configure(EntityTypeBuilder<Paper> builder) { builder.ToTable(nameof(Paper)); builder.HasKey(p => p.Id); //设定1对多关联关系,并声明外键Id builder.HasOne<Examination>(e => e.Examination).WithMany(p => p.Papers).IsRequired().HasForeignKey(p => p.ExaminationId); //... }}
复制代码

3.3.3 创建数据库上下文,引入 ShardingCore 扩展

创建一个类文件,继承 AbstractShardingDbContext,如果不分库也不分表的话,继承 DbContext 就可以了,而 ShardingCore 实际上是 DbContext 的扩展,所以我们直接继承该扩展即可。因为涉及到分表,所以还需要 IShardingTableDbContext 接口。


public class MyDbContext:AbstractShardingDbContext,IShardingTableDbContext{    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)     { }
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); }
/// <summary> /// 分表路由的尾部命名规则,默认是{表名}_{从大到小的索引} /// </summary> public IRouteTail RouteTail { get; set; }}
复制代码


到这里,如果我们不使用分表,就可以去注入服务,执行迁移来生成库表了,但因为我们想把测评的维度拉高一点,所以还要再多一些步骤。

3.3.4 配置分表路由

这里,对 paper 进行分表操作,通过对主键取模的规则来分表,更多关于分表的信息,大家可以参照 ShardingCore 的官方文档,这里由于篇幅有限,不过多介绍了~


 /// <summary> /// 创建虚拟路由 /// 该路由为简单的取模hash路由,分表字段是string类型,接受3个参数,第一个参数表示后缀的位数,第二位表示取模的基数,第三位是取模后缀不足的左补字符. /// </summary> public class PaperVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<Paper> {     public PaperVirtualTableRoute() : base(2, 3)     {     }
public override void Configure(EntityMetadataTableBuilder<Paper> builder) { builder.ShardingProperty(o => o.Id); builder.AutoCreateTable(null); builder.TableSeparator("_"); } }
复制代码

3.3.5 注入服务,启动项目

因为是测试项目,我们采用默认方式注入服务(实际上,生产项目应该考虑集成 AutoFac 来完成容器注入)我这里使用了.net 6 的顶级语句,没有之前常见的 Startup.cs 文件,为了保证入口文件的简洁,这里把配置服务也分到了一个单独的文件中,主要代码如下


public static WebApplicationBuilder SetupServices(this WebApplicationBuilder builder){     _configuration = builder.Configuration;     builder.Services.ConfigureMvc();     //..其他服务     return builder;}private static void ConfigureSharding(this IServiceCollection services){                //添加分片配置    services.AddShardingDbContext<MyDbContext>()        .UseRouteConfig(op =>        {            op.AddShardingTableRoute<PaperVirtualTableRoute>();        }).UseConfig((sp, op) =>        {            var serverVersion = new MySqlServerVersion(new Version(8, 0));            op.UseShardingQuery((conn, builder) =>            {                builder.UseMySql(conn, serverVersion);            });            op.UseShardingTransaction((conn, builder) =>            {                builder.UseMySql(conn,serverVersion);            });            op.AddDefaultDataSource(Guid.NewGuid().ToString("n"),_configuration.GetConnectionString("DefaultConnection")               );        }).AddShardingCore();}
复制代码


以上配置完成后,就可以执行迁移,启动项目啦



四、擂台赛开始

4.1 Warm-up

正式测评之前,先来一个热身赛,项目准备好以后,我想先准备一些种子数据,虽然都是随机的,但我这里准备的多一点,10,000 条考试记录,100,000 条试卷记录,然后分别写入到本地库和 ServerLess 库,看看写入种子数据的效率如何


  • 这是本地的执行截图👇



  • 这是切换到 TDSQL 后的执行截图👇



这里实际已经可以印证 TDSQL 的兼容性了,我只是改了下连接串,然后分别启动了一下项目,10 万+条记录,就这样平滑的插入了。




这里 TDSQL 的用时之所以比本地长,并不是性能不行,而是网络因素影响,毕竟云端再快,也跑不过本地内网链接,所以这个执行时间具体的值参考价值不大,重要的是稳定。当然如果我把环境架到腾讯云的服务器,然后通过 serverless 提供的内网 ip 来测试,那情况就有不一样了,这里因为成本因素,我的测试程序还是在我本地的内网环境下运行。除此之外,云服务的最大 CCU 我只开到了 2,按官方的介绍,相当于 2 核 4G 内存,所以硬件配置也确实比不上本地内网服务器的配置,在此情况下,我分别执行了几次,所用时长几乎没有波动。稳定性兼容性可见一斑。

4.2 压力测试

4.2.1 测试接口

压测之前,我分别准备了三个接口,分别用于模拟实际的简单检索,复杂检索和入库操作


[Route("[controller]/[action]")]public class TestController : Controller{    private readonly ILogger<TestController> _logger;    private readonly MyDbContext _ctx;    public TestController(ILogger<TestController> logger, MyDbContext ctx)    {        _logger = logger;        _ctx = ctx;    }
public async Task<IActionResult> QuerySimple() { //模拟简单查询 //代码略 }
public async Task<IActionResult> QueryComplex() { //模拟复杂查询 //代码略 }
public async Task<IActionResult> Insert() { //模拟插入 //代码略 } }
复制代码


这部分具体的业务代码不在贴了,后续提供完整地址,主要就模拟 2 种不同程度的读操作和 1 种写操作

4.2.2 部署测试环境

这里我是把测试系统分别部署到了内网的两台服务器上,然后通过 nginx 做了一个负载均衡,如下图👇




如此,测试环境就准备好了

4.2.3 准备测试计划

测试计划如下,


  • 目标运行环境:Kestrel(Windows server)

  • 测试工具:JMeter 5.5

  • 负载:2 台

  • UVs(线程数):200 * 2 (2 台压力机,CentOS 环境)

  • 压测时长:300s(5 分钟)

  • 线程启动步长(ramp-up):20 秒内全部线程启动


资源有限,暂时把压测参数定在这个范围


关键 jmx 配置信息如下👇


<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="tdsql-c测评" enabled="true">  <stringProp name="ThreadGroup.num_threads">500</stringProp>  <stringProp name="ThreadGroup.ramp_time">20</stringProp>  <boolProp name="ThreadGroup.scheduler">true</boolProp>  <stringProp name="ThreadGroup.duration">600</stringProp></ThreadGroup>
复制代码

4.4.4 开整!

第一组:将数据库设定为本地的内网环境,测试结果如下




第二组:将数据库设定为 TDSQL-C Serverless,测试结果如下




*注意,将连接串切换到云数据库时要在控制台修改最大连接数,我刚开始就时没有改,压测刚开始没多久就拉了,一看默认的最大连接数是 80



通过压测结果可以得出


  • 简单的单表查询和写入操作,本地库和云端库的并发能力相当

  • 涉及到分表的查询时,TDSQL-C 的优势就发挥出来了,响应时长反超了本地数据库,注意,我这配置的 CCU 时最低标准!

  • 压测时出现的一些错误,是并不都是数据库造成的,还有框架的并发能力,网络等因素等,因为我是把检索直接打到了数据库,没有缓存层,所以数据并不太好,这个就暂时不考虑了。


同时,可以看一下 TDSQL 的一些监控图表 QPS👇



TPS👇



CCU 自动扩缩👇



最后再看一下,从开通,到完成这次测评,中间还折腾了好几次,一共花了多少钱



1.75 元!

五、总结

通过整个的开发,部署,测试环节的对比情况,前面提到的对 TDSQL 的测评维度,基本可以得出以下结论


  • 稳定性

  • 兼容性

  • 并发能力


而且云数据库的控制台给出的各种监控图表非常丰富,可以帮助我们快速定位瓶颈所在,十分方便,如果服务器也在腾讯云,再搭配 TDSQL-C 一起使用,那性能应该会直接起飞。好了,此次的测评就这样了.最后的,一句话总结就是,TDSQL-C Serverless,可以闭眼入!


本篇同步发表于 CSDN:https://blog.csdn.net/juanhuge/article/details/132563811

发布于: 刚刚阅读数: 4
用户头像

学着码代码,学着码人生。 2019-04-11 加入

是一枚,热爱技术,天赋不高,又有点轴,的猿。。

评论

发布
暂无评论
【腾讯云TDSQL-C Serverless 产品测评】一场ServerLess方案和Native方案的小PK!_Serverless_为自己带盐_InfoQ写作社区