漫谈架构演变之路:为何要搞微服务架构?今天就为大家讲透!

image-20200403201347768

70~80s:集中式(大型机)


上世纪70年代和80年代,大型机是计算机的工作方式。

问题所在:最初的大型计算机使用打孔卡,并且大多数计算都在批处理过程中进行。没有在线处理,并且延迟为100%,因为没有实时处理。

架构演变:随着在线处理和用户界面终端的推出,大型机范式发生了一些变化。

90s:CS架构(分布式)


客户端/服务器体系结构将大多数逻辑放在服务器端,并将某些处理放在客户端上。

问题所在:在该体系结构的最初几年中,开发社区仍在使用与大型机开发相同的过程,采用单层原则来为客户端/服务器编写软件,从而产生了诸如意大利面条代码Blob之类的反模式。

架构演变:引入了一项称为面向对象程序设计(OOP)的重大改进;

客户/服务器模型基于三层体系结构,包括展示层,业务逻辑层和数据层。但是大多数应用程序是使用两层模型编写的,胖客户端将所有展示、业务和数据访问逻辑封装在一起,直接访问数据库。尽管业界已经开始讨论将展示与业务与数据访问分开的必要性,但是这种做法直到基于Internet的应用程序问世才真正变得至关重要。

2000:去中心化(Internet)


在90年代中期,互联网革命发生了,Web浏览器成为客户端软件,而Web和应用程序服务器托管所有处理和逻辑。

问题所在:开发人员仍在将软件设计为紧密耦合的设计,从而导致混乱和其他反模式。

架构演变:作为解决办法,业界提出了三层体系结构和实践,例如领域驱动设计(DDD),企业集成模式(EIP),SOA松耦合技术。

2006:云托管


21世纪前10年见证了云计算作为服务托管形式的重大改变。应用程序需要的一些能力,云计算平台托管了基础功能:分布式计算、网络、存储以及计算等,与传统的基础架构相比,云托管的方式能更好的控制成本。

问题所在:它诱使将尚未设计用于弹性分布式架构的遗留应用程序直接迁移和迁移到云中,从而产生了单体地狱这种反模式。

迁移到云还给行业带来了管理第三方库和技术上的应用程序依赖项的挑战。没有足够的标准来选择第三方工具,我们开始看到一些依赖地狱。另外服务扩容也是一个问题。

架构演变:了应对这些挑战,业界提出了新的架构模式,例如微服务12要素应用程序[1]弹性服务

2014:微服务


诸如DDDEIP之类的软件设计自2003年左右就已经开始实践起来了,此时一些团队将应用程序开发为模块化服务,但是传统的基础结构(如Java应用程序的重量级J2EE应用程序服务器和.NET应用程序的IIS)对模块化部署并没有帮助。

随着云托管的出现,尤其是诸如Heroku和Cloud Foundry之类的PaaS产品的出现,开发人员社区拥有了真正的模块化部署和可扩展业务应用所需的一切。这引起了微服务的发展。微服务为打造细粒度、可重用的功能和非功能服务提供了可能性。

问题所在:原本的单体系统、未被设计为微服务的传统应用程序开始被蚕食,试图迫使它们进入微服务体系结构,由于拆解的不当,从而导致了被称为微单体的反模式。单体和微服务是两种不同的模式,后者并不总是可以替代前者。如果我们不小心的话,最终可能会创建紧密耦合,混杂的微服务。微服务剧增的另一个不希望出现的副作用是所谓的“死亡星球”的反模式。

架构演变:诸如服务网格,边车,服务编排和容器之类的新兴架构模式可以有效地防御基于云的世界中的渎职行为。随着云平台的出现,特别是像Kubernetes这样的容器编排技术,服务网格已经引起了人们的关注。服务网格是应用程序服务之间的桥梁,可添加其他功能,例如流量控制,服务发现,负载平衡,弹性,可观察性,安全性等。

几种架构反模式[2]说明

  • 单体地狱[3]

  • 好处:早期开发简单、易于对程序做重大更改、直接测试、直接部署、易于扩展;

  • 缺点:随着业务增长,暴露问题:复杂度高、开发效率低下、从提交到部署耗时长、伸缩性差、技术栈过时难以升级、缺乏故障隔离导致一个小功能可能会影响整个系统;

  • 微单体[4]

  • 一种非弹性和不可扩展的微服务系统,即所谓的微单体;单体和微服务是两种不同的模式,后者并不总是可以替代前者。如果我们不小心的话,最终可能会创建紧密耦合,混杂的微服务(微单体)。我们应该根据应用程序功能的业务和可伸缩性要求做抉择;

  • 积木塔:单体应用程序类似于积木塔:您永远不知道发生故障时哪块砖可能会出问题。由于该应用程序的所有模块都在同一进程中运行,因此,如果某个模块受到错误的影响,则会降低整个过程,从而影响整个应用程序。 在完成故障排除之前,您可能会失去数百甚至数千个商机;

  • 科学怪人[5]:科学怪人是一部著名的美国电影,讲述了一个天才科学家创造了一个怪物最终被其毁灭的故事。Istio 团队为以它来自嘲。Istio 本想扮演上帝一般的角色(统一 Service Mesh 江湖,成为微服务架构的事实标准),却因为过度设计与现实脱离,成为了一个怪兽(monster)。因此,重构的第一阶段,就是从肢解怪兽开始,把微服务架构重新改回了单体架构,但是内部模块划分还是很清晰的;

  • 方轮:重新发明方的轮子,已经有了一个很好的方案,又搞一个方案来替代它;

  • 死亡星球[6]

  • 在服务交互和服务到服务的安全性(身份验证和授权)方面,如果没有治理模型,微服务的泛滥通常会导致任何服务都可以随意调用任何其他服务的情况。就有可能出现想死亡星球那样的调用视图,异常复杂。诸如服务网格,边车,服务编排和容器之类的新兴架构模式可以有效地防御基于云的世界中的渎职行为;

  • 意大利面条式的设计:面条之间互相缠绕在一起,很难梳理清楚它们之间的关系。意大利面式的设计很形象的说明了软件开发中的这种现象:系统很难维护,各种功能逻辑缠绕在一起,没有清晰的模块和层次关系;

  • The Blob:表示的是一个类型具有了过多的职能,导致其过于庞大,最后使代码难以维护。

架构演变步骤

一般的,每一个架构的出现,不是一蹴而就的,都会经历以下几个过程:

  • 引入新模型;

  • 最佳架构实践未知或者不存在;

  • 反模式,技术债务剧增;

  • 行业开发新的体系结构以适应新的范式;

  • 团队研究并采用新的标准架构;


下面我们将于Java工程师的角度来观察架构的大致发展史。

1、第一阶段:学好SSH框架,走遍天下都不怕

======================

早期,大部分IT系统都是单体系统,例如传统的SSH架构,此时前后端也没有分离,UI组件也包含在了控制层:

image-20200330214906608

这一时期服务的对象主要是传统企业,并发不高,主要是业务开发,这种开发方式很方便。当年刚毕业的时候我还和同学在纳闷,那些互联网公司是不是也用SSH框架。

其实真实情况呢?随着互联网企业的崛起,DAU持续增长,业务并发量也逐渐增高,SSH架构单JVM部署这种简单的方式并不能满足高并发场景,我们需要一种能够支持给系统进行水平扩展的架构。

2、第二阶段:分布式系统

============

为了方便给系统扩容,以及增加系统的复用性,出现分布式系统。

另一方面,系统模块快速膨胀,为了降低系统内部的复杂度,于是对系统模块进行拆解,分不到不同的系统中,降低模块耦合,加快迭代速度。

业界提出了三层体系结构和实践,例如域驱动设计(DDD),企业集成模式(EIP),SOA和松耦合技术。

3、SOA

=====

早期的分布式系统是基于面向服务的架构SOA。SOA是微服务的前身,主要是为了摆脱单体应用的问题,达到以下效果:

  • 充分利用现有的基础设施;

  • SOA体系结构依赖于消息传递(AMQP,MSMQ)和SOAP作为主要的远程访问协议。

  • 快速响应业务变化;

根据一位印度小哥的介绍,我画了下面这张SOA的架构图:

image-20200331221123493

也就是说,异构系统,也可以通过消息中间件的协议转换进行相互调用。一般这个消息中间件通常是用ESB企业总线实现的。ESB 是传统中间件技术与XML、Web服务等技术相互结合的产物,消除了不同应用之间的技术差异,让不同的应用服务器协调运作,实现了不同服务之间的通信与整合。不同公司提供了不同的ESB中间件实现。

但是其表现并不佳,主要是其太重了,主要体现在:

  • SOA更强调系统集成的规范与便利性,对业务服务本身没有过多要求,一般服务拆分粒度不够细,模块间仍然会有比较大的耦合,迭代困难;

  • SOA服务之间的通信相对比较复杂,重量级。WebService中常用的SOAP通信协议,通常使用XML格式进行通信,数据冗余,协议过重;EBS通过总线隐藏内部复杂性,其中心化管理模式,系统变更,对系统的影响范围会扩大。

  • 在SOA模型下通常只有一个数据库,限制了系统的扩展性;

  • 服务化管理和治理设施不完善;

后来逐渐演变为了现在的MSA(Micro-Service Archeticture 微服务架构),从而实现了更加松耦合以及更加灵活的系统。

4、微服务(MSA)

==========

微服务使用各个子服务控制模块的思想代替SOA中的总线。服务控制模块通常至少包含:服务注册与发布、路由、代理。

微服务与SOA的对比

  • 目的:

  • SOA强调异构服务之间的协作和契约,强调有效集成,最大化应用程序服务的可重用性

  • 微服务的目的是拆分解耦应用,专注去耦合,让不同不同的业务团队服务不同的微服务,专人专事,缩小迭代影响范围,让微服务更容易进行水平扩展微服务遵循单一职责,是一种克服系统复杂性的分解技术。如果你觉得你的某个微服务很复杂,那么考虑看看是否拆分的不够细?也正是因为这种拆分,本质上增强了安全性故障隔离

  • 部署方式:

  • SOA服务不多,一般打包后直接通过war形式部署到服务器;

  • 微服务由于数量众多,需要实现快速扩容和缩容,一般借助容器化技术来实现部署,微服务之间独立部署,互不影响;

  • 服务粒度:

  • SOA对粒度无要求,通常是粗粒度的,更强调的是接口的规范化;

  • 微服务提倡进行细粒度的拆分,保证服务职责的单一。

|   | SOA | 微服务 |

| — | — | — |

| 服务粒度 | 粒度较粗 | 细粒度拆分 |

| 部署难度 | 需要重新创建或者部署整个应用 | 每个微服务可以独立构建部署 |

| 通信开销 | 大部分业务模块在一个应用里面,通信开销低 | 更多的远程调用,增加了通信开销 |

| 存储 | 一般所有服务共享数据存储 | 每个可以拥有单独的存储 |

| 业务易上手 | 需要了解整个应用的业务,上手较难 | 单服务上手容易,但是服务集群理解比较难(复杂度守恒定律:业务复杂度不会因为迁移到了微服务而降低) |

| 通信方式 | SOA体系结构依赖于消息传递(AMQP,MSMQ)和SOAP作为主要的远程访问协议,协议偏重量级; | 使用轻量级协议,如HTTP/REST |

| 可扩展性 | 难以扩展 | 使用容器技术很方便扩展 |

4.1、微服务的优势


4.1.1、方便扩容与保证服务可伸缩性

正是因为微服务的拆解,让我们增加了系统的安全性和故障隔离,可以让我们针对不同的服务,实施不同的扩容和存储技术。

例如,一些微服务可能使用关系数据库,而另一些可能使用NoSQL数据库甚至挂载的文件系统。以这种方式构建应用程序增加了团队构建应用程序的可伸缩性。

4.1.2、降低耦合,利于团队协作与版本快速更新

在SOA系统,或者是传统的单体系统中,使用一个项目的时候,通常会有一个大团队的人在同一个项目的同一个分支上工作,并且总是互相干扰,出现各种代码冲突,随着代码增长,开发速度会呈现指数级增长。这是我们以前遇到过的问题,特别头疼,后来花了很大的精力对系统做了服务化改造拆分。

当然主导这个服务化改造也是需要申请不少资源的,即使没有新的业务上线。为了让老板认为我们正在做的改造是存在价值的,当时还写了改造前后的各种利弊对比。这是很重要的,我们总不能无故的去改造一个运行良好的系统。

有了微服务架构,应用程序由小型分散的开发团队构建,这些团队独立地工作和更改微服务。

4.1.3、服务自治

这使得测试和升级服务以及随时间增加功能变得更加容易。

最终,如果一个微服务在规模和功能上增长,它可以被分解并分成多个微服务,从而保持微服务的小型、可管理和自治。

4.1.4、让项目保持技术多样性

最后,采用微服务体系结构允许使用最适合其开发的任何语言技术堆栈来编写单个服务。并没有严格的限制所有的微服务都必须使用相同的技术来开发,只要它们都通过相同的轻量级协议(如HTTP和消息)进行通信,并且数据结构以相同的格式进行序列化(JSON是最流行的选择)。

微服务的特点是:

  • 轻量级的组件;

  • 服务独立的部署能力;

  • 轻量级、粗粒度api;

  • 轻量级的服务总线;

  • 轻量级的数据存储;

4.1.5、避免了单体系统开发效率低下的问题

单体系统要么是数据库变得太大了,要么是代码行太多了,更有可能的是,现在的开发人员不能快速地添加新特性。微服务体系结构避免了单体系统的缺陷,使用真实且可靠的分解技术来解决这些缺陷,并将重点放在敏捷开发和可替换性上,而不是可重用性上。

此外,与单体系统不同,微服务是一个可持续的体系结构,通过添加新的微服务来满足快速变化的业务需求,而不是修改(和破坏)旧的服务。

4.2、微服务面临的问题


没有什么架构是免费的

尽管微服务有很多好处,但它并不是万能的。微服务在减轻整体应用程序固有的许多问题的同时,也带来了其他挑战。与技术领域的任何事情一样,总是需要在不同的体系结构和微服务之间进行权衡。

4.2.1、增加了运维的复杂度,以及维护微服务集群的复杂度

它所提供的敏捷性和开发速度是以增加操作复杂性为代价的,因为自然有更多的活动部件(或服务)—可能比单体应用还要多。

使用微服务架构可能会增加运维开销。 使用这种方法,您的部署可能需要大量资源。您可能需要更多的时间和精力来创建基础架构。 所有服务可能都需要群集以实现故障转移和弹性。 您的系统可能具有数十个单独的组件,并且在您添加新功能时,它将变得越来越复杂。

您可能会得到一个由20或30个或更多服务组成的解决方案,而不是一个整体系统,每个服务都运行多个进程。

最佳实践是,您应该通过DevOps自动化解决这些额外的工作开销

4.2.2、单体系统迁移到微服务比价困难

**把单体系统迁移到微服务也是一个巨大的工作量。**不推荐用微服务重写系统,这不太现实,特别是单体系统业务比较复杂的时候。建议采用一种更渐进的方法,逐步地重构一个单体系统,逐渐地将它转变成一个由微服务组成的“新”应用程序。随着时间的推移,单体应用程序实现的功能数量会减少,直到完全消失或变成另一个微服务应用程序。最后,不要觉得有必要立即开始分解一切;花时间和工作在最合理的方式为你的团队。

4.2.3、提高了开发的技术门槛

在开始实际的迁移过程之前,我们得思考权衡以下问题:可以肯定的是,具有微服务体系结构的系统提供了大量的好处,例如独立部署强大的子系统边界技术多样性

但是,因为微服务是一个分布式系统,它带来了开发分布式应用程序相关的复杂性的代价,如:独立的数据模型、微服务之间的弹性通信、最终一致性和操作复杂性等。开发和运行大规模的分布式服务也不是一件容易的事情。

在实际的把单体系统拆分为微服务的过程中,**不建议用服务大小来衡量拆分效果,而是拆分的业务边界,可以考虑使用DDD的方式去进行建模设计。**DDD是我们架构师工具箱中用于标识和设计微服务的优秀工具。

4.3、微服务技术体系


微服务需要关注的点很多,下面画了一张图来表述:

image-20200401225233763

总的来说,微服务MSA架构需要以下技术点的支持:

  • 配置管理;
  • 服务发现和负载均衡;
  • 弹性和容错;
  • API管理;
  • 服务安全;
  • 日志管理;
  • Metrics监控;
  • 分布式调用链追踪;
  • 调度和发布;
  • 自动伸缩和自愈;

除了技术相关的,组织结构和团队文化也是很重要的。

下面是一般微服务涉及到的各种组件:

image-20200401231158596

5、微服务技术选型

=========

我们先来关注下微服务的各种技术栈的优缺点。

5.1、Spring Cloud


为开发人员提供了用于构建MSA的工具,例如:配置中心、服务发现、断路器、路由等。它是基于Java的Netflix OSS库构建的。

image-20200401235821995

5.1.1、优点

  • Spring技术栈,快速上手,开箱即用:Spring平台提供了统一编程模型,以及Spring Boot快速创建应用程序的功能,为开发人员提供了出色的微服务开发套件,仅仅需要很少的配置,就可以创建应用;

  • 组件库丰富

  • 不同Spring Cloud组件可以很好的集成工作,一切基于注释驱动,易于开发,感觉就像是Java开发者的天堂。

5.1.2、缺点

  • 仅限于Java。我们前面提到MSA架构的魅力在于能够在需要时修改技术栈,库甚至语言的。Spring Cloud则无法做到这一点。Netflix的Prana项目中使用了边车模式,通过HTTP调用可以在系统中集成非JVM的应用。通过HTTP与Prana进行跨进程通信,使得用其他语言编写的应用程序或Memcached、Spark和Hadoop等服务能够利用Netflix OSS库提供的特性,而不必为目标语言或平台重新编写库;

  • Java程序员承担了太多的责任,服务发现、负载均衡、配置中心均需要单独部署,而且我们要保证高可用,除了实现服务功能,我们还必须构建和管理一个微服务平台;

  • 不能覆盖MSA整个生命周期:微服务平台部分必备功能缺失,自动化部署、调度、资源管理、进程隔离、自我修复等仍然是一个问题。我们仍然需要引入Kubernetes或者Cloud Foundry来解决此类问题。

5.2、Dubbo


其实dubbo只是一个rpc框架,其架构如下(来源于官方网站[7]):

image-20200401173814120

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  1. 服务提供者在启动时,向注册中心注册自己提供的服务。
  1. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  1. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  1. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  1. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

其提供了Metrics监控,服务发现和负载均衡,rpc调用,其实不能算是一个MSA体系,不过后来阿里整合了Spring Cloud,推出了Spring Cloud Alibaba,作为微服务开发的一站式解决方案。其中包含了Dubbo Spring Cloud

由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus,不仅完全覆盖 Spring Cloud 原生特性,而且提供更为稳定和成熟的实现:

  • 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。

  • 服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。

  • 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。

  • 消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。

  • 分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。

  • 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。

  • 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。

  • 阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。

5.3、Kubernetes


Kubernetes是一个开源系统,用于应用程序自动化容器部署、扩展和管理。它支持多语言,并提供了用于配置,运行,扩展和管理分布式系统的原语。

优点

  • 多语言和通用容器管理平台,能够运行云原生和传统容器化应用程序;

  • 易于构建跨团队的平台:提供的服务(例如配置管理,服务发现,负载平衡,指标收集,日志聚合)可以通过多种语言来使用;

  • 解决了更多MSA的问题:除了提供运行时服务外,Kubernetes还允许您置备环境、设置资源约束、RBAC、管理应用程序生命周期、启用自动缩放和自我修复等;

  • 社区活跃,技术发展迅猛;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

image

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

[外链图片转存中…(img-VhF2McNW-1713751998245)]

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

[外链图片转存中…(img-OFq5JrYh-1713751998245)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值