微服务架构下 CI/CD 如何落地

本文系云原生应用最佳实践杭州站活动演讲稿整理。杭州站活动邀请了 Apache APISIX 项目 VP 温铭、又拍云平台开发部高级工程师莫红波、蚂蚁金服技术专家王发康、有赞中间件开发工程师张超,分享云原生落地应用的经验心得,以下是莫红波《微服务架构下 CI/CD 如何落地》分享内容。

莫红波,又拍云平台开发部高级工程师,目前专注于容器及虚拟化技术在又拍云的私有云实践,主要负责又拍云容器云的设计和开发工作。

大家好,今天分享的主题是《微服务架构下 CI/CD 如何落地》,围绕以下两部分展开:

  • 理论篇,讨论从单体到微服务的过程中会面临怎样的挑战,以及微服务的测试模型

  • 实践篇,围绕集成测试环境的服务发现需要怎么做,如何落地持续交付和持续部署

背景

或许大家对于互联网公司的共同印象是 996,对于我个人而言,互联网公司还有另一个特点,那就是经常需要拥抱变化。在互联网公司,新产品上线、下线、调整,这都是很家常便饭的事情。在这种情况下,一个好的松耦合的架构就显得尤为重要。

刚好我最近就有遇到这个问题,我在做的项目,账号这块是对标 GitHub 的注册制账号机制的。原本的需求是用户注册我们的平台,注册完成后可以创建一个属于自己的团队,并将其他人拉入自己的团队。但是当我们做完这部分内容后发现,客户还是更偏好「账号+子账号」的模式,公司一个总的账号,所有员工单独开子账号进行关联。这让我们已经做好的项目变得非常尴尬,需要立即拥抱变化,需要根据最新的需求进行调整。这时,我就发现拥有一套松耦合的架构的重要性,比如账号这一部分,如果把它单独拎出来,做好足够的抽象,提供必要的对外接口,可能会更加灵活,扩展性更加好。

**那怎样拥有一套松耦合的架构?有什么好的方案呢?在我看来有两个,一个是几年前出现的 SOA,即将服务进行单独化,将每一块都进行拆分;另一个就是最近几年火热的微服务了。**我认为,微服务跟 SOA 其实是一回事,只不过微服务比 SOA 拆分粒度更细,功能也更小。

在调研微服务过程中,很多人会有疑问:“我们是一个很小的团队,小团队适不适合上微服务呢?”。因为上微服务就意味着一个服务可能就会被拆分成 10 个、20 个甚至更多个的服务,这就让小团队不得不去考虑自己的测试、部署、更新成本是不是会翻很多倍。

那么我对于“小团队适不适合上微服务”这个问题的答案是什么呢?我认为是完全可以上的,不过你需要注意一点:做好自动化,能交给自动化来实现的,就不要人工介入了。

在聊如何做自动化集成测试(CI)之前,我先和大家谈一谈从单体如何到微服务,服务是如何拆分的,以及微服务的测试一般是怎么做的。

从单体到微服务

如上图所示,我们可以看到图左边是一个单体服务,右边则是经过微服务拆解后的。我们可以看到它有 4 个特点:

  • 根据不同领域拆分

  • 服务之间通过网络协议通信

  • 拥有独立的数据库

  • 拥有特定对外开放的接口

微服务测试模型

我们都知道,如果需要一个服务能够稳定运行,那测试肯定是少不了的。而就像我们微服务化有一套理论一样,微服务测试也拥有属于自己的金字塔理论:最底层是单元测试,成本相对较低,像我们在 API 认证部分做的签名校验模块,它一般不需要依赖其他东西,因此测试效率也比较高;第二层是集成测试,这一层你就必须要依赖一些第三方的服务模块或者组件,比如我们一般会用到数据库的测试,就属于集成测试的范畴;第三层是 e2e 测试,它会模拟客户端的行为来进行测试,大家也许都接触过这类测试,像K8S 就有一个 e2e 测试,当你去申请 CNCF 的一致性认证时,就需要通过官方提供的 e2e 测试;最上层是 UI 测试,比如对于页面的点击调整是否符合预期,这部分我们现在做的比较弱,还处在人工模式下,但我们也在努力将它更新成自动化。

从这个微服务测试金字塔我们可以看到,越靠近底层成本越低,你只需要几行代码就能完成,效率也非常高。同时越底层它对于三方或组件的依赖也越低,自动化也就越简单。到这里可能就有人想问:“既然越底层的成本越低,那我们能不能只跑单元测试?”在解答这个问题前,大家先看下面这张图。

这两扇窗户,每一扇单独存在的时候都是完好的窗户,可以正常开合。但是两个都安装到墙上后就没有办法正常开合。这就是我们不能只跑单元测试的原因了,不跑集成测试就无法发现一些问题。同理不跑单元测试也会有一些无法发现的问题,所以我们在跑测试的时候,集成测试和单元测试,一项都不能少。

那具体实践的时候要如何做呢,我推荐大家分成两步来进行:

  • 第一步是将底子打好:你需要对你的的微服务进行单元化测试,编写单元化的测试用例,然后再强化集成测试。没有好底子的微服务是不可靠的,任何时候都可能会出问题,而且出问题后的排查会非常费时。

  • 第二步是自动化的持续集成环境:将能够自动化的部分全部进行自动化,减少人工的介入。

GitLab/CI

自动化集成环境这块目前已经有很多的开源方案了,比如常见的 Jenkins,还有 GitLab。我们选择的是 GitLab,或者说是选择了 GitLab/CI,选择它的原因有以下几点:

  • 统一的 web 页面

  • 可以再 MR 中跳转查看

  • Pipeline 编排直观展示

  • 所有操作都在项目中搞定

  • GitLab 官方支持

GitLab WorkFlow

既然我们选择使用了 GitLab,那我们内部就会严格遵守 GitLab 的 WorkFlow。WorkFlow 主要分为两个部分。

第一部分是面向代码仓库。代码仓库中,我们一般会有三类分支,第一类分支是 master 分支,一般只会有一个,我们会定义 master 分支,并基于这个分支进行线上版本的发布。第二类分支是 develop 分支,一般也只会有一个,develop 分支是从 master 分支中 checkout 出来的,功能比 master 领先,包含一些已经完成功能开发,但是还没有发布的功能。第三类分支是 feature 分支,特性分支,一般会有很多个,新功能都会在这个分支上进行开发,往往一个功能对应一个 feature 分支。最后一类是 hotfix 分支,这个就比较常见了,线上发布后,如果发现了一个需要紧急修复的bug,这时你就可以在 master 分支上 checkout 出来一个 hotfix 分支,把代码改掉。不过进行这个操作时你需要注意,master 分支和 develop 分支都需要进行该 commit 合并,否则就不能算完成了 bug 修复。

第二部分与 CI/CD 有关。以我们的流程举例,研发的同学提交代码到 GitLab 仓库,之后 GitLab 会触发事先约定好的 CI 的 pipeline 进行测试和构建。等待测试和构建成功后再进行 code review 的确认,确认无误后会合并到 develop 分支并最终合并到 master 分支进行发布。这就是 GitLabCI 的一个配置,总结来看可以划分为下图的四个阶段。

下图是配置文件对应的 pipeline 的展示,大家可以看一下。

微服务下的场景变形

其实到目前为止的方案,已经是微服务没有大热前的完备方案了。如果你想要将方案运用到微服务的集成测试里,你还需要做一些变形,不妨参考下图中所示的又拍云现在使用的整套流程。

从图中可以看到,我们目前使用的整套流程相比标准的其实有做一些小的变形,变形主要集中在中间的集成测试环境这一块,我们将每个服务器都部署在了集成环境内,使集成环境变成一个准发布环境。具体流程是,当我们的创建 projectA 后,由它来 push 代码,完成后触发 CI,也就是在 GitLab runner 上进行测试。

在跑测试的过程中,因为 A 服务需要调用 B 和 C 服务,所以通过 API 去请求集成环境中的对应服务。如果测试完成后没有问题,则合并到主线。再通过在 master 分支打 tag 的方式来触发容器构建并推送到 Harbor 镜像仓库。最后我们会做一个线上 release。这个就是我们的大致流程了。

那么接下来我们来具体看一下变形中会遇到的问题。

服务发现

在微服务场景下的变形中遇到了很多问题,我觉得其中值得注意的是“服务发现”。比如我们现在有这样一个场景,A 服务在跑测试时需要依赖 B 服务和 C 服务,面对这个需求,在没有引入 Kubernetes 之前,我们可以通过使用一台共用机器,将服务都布置到这台机器上,并在测试代码里写死 IP 地址,让每一次测试都在这个环境内跑。但这个方法会有下面四个无法忽视的问题:

  • 服务更新延迟

  • 环境权限混乱

  • 人工操作容易出错

  • 维护成本过高

因此我们引用了 Kubernetes Service 的方案进行优化。

Kubernetes Service 的流程大家可以大概看一下。我们先定义一个 Service, 我们这边创建的 ClusterIP 类型的,定义了暴露端口 8000,目标端口 8000,协议是 TCP,标签选择器是 app=holdon。通过这种方式,我们可以把一组相同功能的服务,绑定在同一个 Service 下。在 Kubernetes 集群内,定义好 Service 后,会提供内部的 DNS 解析,你可以通过一个固定的域名访问指定的 Service。这样当在跑测试的时候就可以通过这个域名加对应端口,调用到对应服务了。

持续交付

持续交付(英语:Continuous Delivery,缩写为 CD)。每个项⽬都要有⼀个 Dockerfile,提供了服务运⾏所需的环境,以及服务对应的软件包。当需要发版本的时候,我们会在主线上打上⼀个 tag,触发镜像构建,然后推送到 Harbor 镜像仓库。其中,这个 tag 也会对应到镜像的版本号。

上图是我们的 CD 流程大家可以参考看一下。需要提一下的是,我们引用 Harbor 的原因是因为它相对官方的 Registry 更安全。大家应该都知道,官方的 Registry 本身不带权限校验,当你公司内部使用的时候,这个问题会导致你的镜像有被其他部门的人覆盖掉的可能性,所以我们引入了 Harbor。但这里也有一个问题,使用同一个 tag 去推依然会被覆盖的情况。不过好歹做到了小组和小组之间、部门和部门之间的隔离。

持续部署

持续部署(英语:Continuous deployment,缩写为 CD),目前这块,在实践过程中,我们是只针对集成测试环境,线上更新还是走常规的流程。给项⽬增加⼀个 k8s-deploy.yaml 的⽂件,⾥⾯包含了服务相关的配置、部署⽅式、访问⽅式等等,等待镜像构建完成后,apply 该⽂件就可以了 。

持续部署流程图

回顾

现在我们再回到服务变形的流程图来看一下,当我们有 A、B、C 三个服务,且 A 服务在测试时需要调用集成环境内的 B 服务与 C 服务时,可以通过 K8S 提供的内部域名进行访问。等待整块测试跑完后,我们在主线上打 tag,让 CI 去帮执行 image build 构建镜像并推送到 Harbor 仓库。

其中涉及到的准发布环境,可以通过 kubectl apply 的方式进行部署。由于线上环境更复杂,推荐大家通过自研的容器云平台来进行操作,我们就是这么处理的,通过云平台发布,功能更加全面安全,更加符合线上部署的流程。

成果展示

最后,跟大家分享下最近正在做的项目的情况。从 2019 年 12月 开始到现在,我们每天基本保持在一个较高的 commit 数上,而这其中一共进行了大约 4500 次的测试。想象下,如果没有这套自动化持续集成环境,测试需要怎么来进行,需要投入人力资源。

点击阅读可直接跳转,获取现场分享视频、下载 PPT。

相关推荐

3 分钟了解 NVIDIA 新出的 H200

英伟达在 2023 年全球超算大会上发布了备受瞩目的新一代 AI 芯片——H200 Tensor Core GPU。相较于上一代产品 H100,H200 在性能上实现了近一倍的提升,内存容量翻倍,带宽也显著增加……

github_36774378的博客 2380

深入了解浮点运算——CPU 和 GPU 算力是如何计算的

算力最基本的计量单位是 FLOPS,英文 Floating-point Operations Per Second,即每秒执行的浮点运算次数。浮点运算其实就是带小数的加减乘除运算。

github_36774378的博客 5104

加速计算,为何会成为 AI 时代的计算力“新宠”

加速计算是指使用专用硬件来执行某些类型的计算,其效率要比仅使用通用中央处理器(CPU)高。利用图形处理单元(GPU)、专用集成电路(ASIC)(包括张量处理单元(TPU))和现场可编程逻辑门阵列(FPGA)等设备的强大功能,以更高的速度执行计算,从而加速计算过程,一般我们也将这些设备称之为加速器。这些加速器尤其适用于可被分解为较小并行任务的项目,如高性能计算 (HPC)、深度学习、机器学习、人工智能和大数据分析。通过将指定类型的工作分派到这些专用加速计算硬件上,大大提高了系统的性能和效率。

github_36774378的博客 1072

NVIDIA RTX4090,你能用它做什么?

如果女生选择给男生送礼,我相信一块 RTX4090 就足以让他高兴得死去活来。RTX4090 到底是何方神圣?它凭什么赢得所有男生的“芳心”?

github_36774378的博客 2353

3 分钟看完 NVIDIA GPU 架构及演进

近期随着 AI 市场的爆发式增长,作为 AI 背后技术的核心之一 GPU(图形处理器)的价格也水涨船高。GPU 在人工智能中发挥着巨大的重要,特别是在计算和数据处理方面。目前生产 GPU 主流厂商其实并不多,主要就是 NVIDIA、AMD、Intel、高通等厂家。本文将主要聊聊 NVIDIA GPU 的核心架构及架构演进。

github_36774378的博客 1983

聊聊 GPU 产品选型那些事

随着人工智能的飞速崛起,随之而来的是算力需求的指数级增加,CPU 已经不足以满足深度学习、大模型计算等场景的海量数据处理需求。GPU 作为一种强大的计算工具,无论是高性能计算、图形渲染还是机器学习领域,在各个领域展现出了巨大的潜力和应用前景。说起 GPU,绕不过的当然是 NVIDIA 这个公司了,现在市面上火热的 A100/A800、H100 等 GPU 全是他家的产品。但当你有业务需求或者个人需求,想要采购 GPU 的时候,你会发现各个型号的 GPU 令你眼花缭乱。

github_36774378的博客 985

巅峰对决:英伟达 V100、A100/800、H100/800 GPU 对比

近期,不论是国外的 ChatGPT,还是国内诸多的大模型,让 AIGC 的市场一片爆火。而在 AIGC 的种种智能表现背后,均来自于堪称天文数字的算力支持。以 ChatGPT 为例,据微软高管透露,为 ChatGPT 提供算力支持的 AI 超级计算机,是微软在 2019 年投资 10 亿美元建造一台大型顶尖超级计算机,配备了数万个 NVIDIA A100 GPU,还配备了 60 多个数据中心总共部署了几十万个 NVIDIA GPU 辅助。

github_36774378的博客 1万+

InfiniBand 的前世今生

今年,以 ChatGPT 为代表的 AI 大模型强势崛起,而 ChatGPT 所使用的网络,正是 InfiniBand,这也让 InfiniBand 大火了起来。那么,到底什么是 InfiniBand 呢?下面,我们就来带你深入了解 InfiniBand。

github_36774378的博客 865

揭秘神秘的字符串匹配工具——正则表达式

每个正则表达式都有一个有限自动机(也称为状态机),它接受表达式指定的语言,并使用 Thompson 构造算法将正则表达式转化为一个与之等价的非确定有限状态自动机(NFA)。同时,对于每个有限自动机来说,还有一个描述该自动机所接受语言的正则表达式。该表达式可以通过克莱恩算法或高斯消元法生成。正则表达式的一个著名应用是文本编辑器中的搜索和替换功能,计算机先驱 Ken Thompson( UNIX 操作系统的开发者之一)首先在 20 世纪 60 年代的面向行编辑器 QED 中实现了该功能。

github_36774378的博客 382

深入了解 GPU 互联技术——NVLINK

随着人工智能和图形处理需求的不断增长,多 GPU 并行计算已成为一种趋势。对于多 GPU 系统而言,一个关键的挑战是如何实现 GPU 之间的高速数据传输和协同工作。然而,传统的 PCIe 总线由于带宽限制和延迟问题,已无法满足 GPU 之间通信的需求。为了解决这个问题,NVIDIA 于 2018 年推出了 NVLINK,以提高 GPU 之间的通信效率。

github_36774378的博客 3874

各快 100 倍?4G、5G、6G 相差这么多吗

二狗子今天晚上有点 emo,为什么呢?原来是二狗子心心念很久的一个手游上线了,二狗子兴冲冲地下载了 40 多分钟,终于下载完了游戏。结果打开游戏一看,发现游戏内部的更新写着预计 30 分钟完成更新。这就把二狗子搞得 emo 了。二狗子突然发现自己的室友已经在这款游戏的新手村大杀四方了。“你怎么这么快?”二狗子问。“我用手机流量下载的,5G,当然快。”室友都没看二狗子一眼,沉浸在自己的游戏世界里。5G 真的有这么快吗?好学的二狗子就让游戏保持着后台更新,在网上冲浪学习下知识充实自己。

github_36774378的博客 468

为什么大家都在用 WebP?

WebP 是谷歌在 2010 年提出的一种新型的图片格式,放到现在来讲,已经不算是“新”技术了,毕竟已经有了更新的 JPEG XL 和 AVIF。但是在日常工作中,大家时常会碰到保存下来的图片的后缀是 .webp。那么 WebP 到底有什么魔力,让越来越多的网站“抛弃”常用的 PNG、JPG 而青睐它呢?

github_36774378的博客 958

从驾考科目二到自动驾驶,聊聊 GPU 为什么对自动驾驶很重要

这些数据包含前车和本车的距离,左右两边的道路指示标志,周围汽车的距离,前方道路指示标志,红绿灯信号,马路边行人,非机动车等信息等,大量的图像和视频信息被转换成电脑能处理的二进制信息,这就需要 CPU 和 GPU 的共同加持才能完成安全稳定的自动驾驶工作。

github_36774378的博客 361

聊透 GPU 通信技术——GPU Direct、NVLink、RDMA

AI 技术对算力的需求是非常庞大的,虽然 GPU 的计算能力在持续提升,但是对于 AI 来说,单卡的计算能力就算再强,也是有极限的,这就需要多 GPU 组合。而 GPU 多卡的组合,主要分为单个服务器多张 GPU 卡和多个服务器,每个服务器多张卡这两种情况,无论是单机多卡还是多机多卡,GPU 之间需要有超强的通信支持。

github_36774378的博客 2569

这个 AI 机器人会怼人,它是怎么做到的?

人工智能可以定义为计算机科学的一个分支,其目标是创造与人类智力相当的技术。但智力到底是什么?如何利用技术来复制智力?这个疑问并不存在单一的理解,目前已经有了许多理论和方法来回答这些问题。人工智能的实现方式主要有两种:一种是基于规则的人工智能,通过预先编写的规则和逻辑来实现特定的任务;另一种是基于机器学习的人工智能,通过让计算机从数据中学习和优化算法,来实现特定的任务。

github_36774378的博客 717

如何评估计算机的算力:从 CPU 到 GPU 的演变

这就是 CPU 和 GPU 在计算能力上的区别,这是由它们的架构决定的,CPU 可以执行任何程序,而 GPU转为多任务而生,并发能力强。当然,上面的两张图并不是说 GPU 比 CPU 厉害,事实上,CPU 和 GPU 各自具有不同的特点和优势,选择哪种设备取决于具体的应用场景和需求。其中,CPU(中央处理器)和 GPU(图形处理器)是计算机中最为核心的两个组件,它们的算力和性能对于计算机的整体性能具有决定性的影响。CPU 是计算机的核心组件之一,它的主要功能是执行指令、控制计算机的运行和处理数据等任务。

github_36774378的博客 2390

浅谈 Linux 下 vim 的使用

底线模式的进入方法为:在命令模式下按":“键,Vim 窗口的左下方会出现一个”:"符号,这时就可以输入相关的指令进行操作了。在此模式下可以使用上、下、左、右键或者k、j、h、l键进行光标的移动,还可以对文件内容进行复制、粘贴、替换、删除等操作。当编辑完成,就可以按 Esc 退出插入模式,进入到命令模式。p : 黏贴,此命令是在命令模式下,按照上面的命令复制后,然后光标移动到想要复制的位置,然后按 p 黏贴。直接到某行:在底线模式下直接输入数字就可以到想到的行,如果输入的数字比文档的行数多就会到最后一行。

github_36774378的博客 1311

如何高效实现 MySQL 与 elasticsearch 的数据同步

MySQL 自身简单、高效、可靠,是又拍云内部使用最广泛的数据库。但是当数据量达到一定程度的时候,对整个 MySQL 的操作会变得非常迟缓。而公司内部 robin/logs 表的数据量已经达到 800w,后续又有全文检索的需求。这个需求直接在 MySQL 上实施是难以做到的。

github_36774378的博客 724

国密证书 VS 传统 SSL 证书,到底区别在哪?

国密算法,即国家商用密码算法。是我国自主研发创新的一套数据加密处理系列算法。从 SM1-SM4 分别实现了对称、非对称、摘要等算法功能。尤其适用于嵌入式物联网等相关领域,完成身份认证和数据加解密等功能。

github_36774378的博客 1310

又拍云邵海杨 - 25年Linux老兵,聊聊运维的“术”与“道”

邵海杨,从1998年开始使用Linux至今快25年了,资深Linux系统运维/架构师,DevOps八荣八耻倡导者,喜欢交流分享,活跃于社区,一直积极投身于开源活动的组织和传播。

github_36774378的博客 745

从 AI 绘画到 ChatGPT,聊聊生成式 AI

无论是 AI 绘画,还是现在风靡全球的 ChatGPT,它们都属于 AI 的一个分支——生成式AI(Generative AI)。相较于传统的 AI 模型,生成式 AI 是一种特定类型的 AI,它专注于创建新内容。

github_36774378的博客 5755

从 B 站出发,用 Chrome devTools performance 分析页面如何渲染

页面是如何渲染的?从 Chrome 的性能工具开始,具体看看一个页面是如何进行渲染的,以及进行页面优化时需要关注哪些指标。

github_36774378的博客 1136

【白话科普】聊聊网络架构变革的关键——SDN

SDN 即软件定义网络,它描述了一种网络架构,可以使用软件对单个硬件组件进行集中、智能的管理和控制,使用 OpenFlow 等开放协议允许访问网络设备,如交换机、路由器或防火墙等。

github_36774378的博客 1838

二狗子翻车了,只因上了这个网站……

通过 fetch API 或 XMLHttpRequest 等方式发起的 HTTP 请求,必须要遵守同源策略 ,那什么是同源策略呢?为什么这个策略会导致我们的信息在浏览器上被盗用。

github_36774378的博客 659

一文读懂 Kubernetes 存储设计

在 Docker 的设计中,容器内的文件是临时存放的,通过在 docker run 启动容器时,使用 --volume/-v 参数来指定挂载卷,将容器内部的路径挂载到主机,来保证即便容器被删除,保存到主机路径中的数据也仍然存在。

github_36774378的博客 545

从实战出发,聊聊缓存数据库一致性

在云服务中,缓存是极其重要的一点。所谓缓存,其实是一个高速数据存储层。本文主要介绍更新数据库成功后,更新缓存和删除缓存这两个操作的区别和改进方案。

github_36774378的博客 584

当谈论 React hook,我们究竟说的是什么?

React hook是什么,所谓 React hook,就是增强函数组件能力特性的钩子,把不同的特性「钩」进纯函数。React hook 的由来,其实也可以看作是前端技术不断演进的结果。

github_36774378的博客 589

视频网站节约 30% 成本的秘密在这里

今年,爱奇艺宣布2022年第一季度首次实现季度盈利,长视频行业发展十几年来,一直深陷亏损旋涡。爱奇艺的首次实现季度盈利,也意味着降本增效将成为视频平台的发展方向。

github_36774378的博客 965

【白话科普】从“熊猫烧香”聊聊计算机病毒

到底什么是计算机病毒呢?它是什么途径传播的,又会带来哪些危害,我们又该如何在日常使用电脑中防止感染病毒呢?

github_36774378的博客 1642

【实操日记】使用 PyQt5 设计下载远程服务器日志文件程序

PyQt5 是一套 Python 绑定 Digia Qt5 应用的框架,是最强大的 GUI 库之一,使用 PyQt5 我们能够很容易的开发桌面应用,我们如何用 PyQt5 设计一个下载服务器指定日期日志文件的程序。

github_36774378的博客 1117
上一篇: 网骗欺诈?网络裸奔?都是因为 HTTP?
下一篇: 白话科普系列——网站靠什么提升加载速度?
又拍云 UPYUN
又拍云 UPYUN 又拍云官方账号 又拍云官方账号
博客等级 码龄10年 153粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值