云原生(Cloud Native) 与Spring Cloud

1. 云原生的概念

讲到云原生(cloud-native),就不得不提Pivotal。

Pivotal Software(PVTL)是一家领先的云原生(cloud-native)平台,为企业客户的软件开发和运营提供策略性改善解决方案,提高开发人员的工作效率并支持现代软件开发方法。

Pivotal 脱胎于信息存储公司EMC(易安信)和云计算公司 VMware(威睿),整合了两者旗下的大数据和云计算资源,并于2013年成立。成立之初,Pivotal便获得美国工业巨头通用电气(GE)上亿美元的股权投资。2016年5月,Pivotal获得由福特(Ford)领投、微软(Microsoft)跟投的C轮融资,估值达到约28亿美元。由于戴尔(Dell)与 VMware 为母子公司关系,伴随戴尔后来对EMC的收购,戴尔成为Pivotal的第一大股东,并牢牢掌握公司的控制权。2019年,VMware 与 Pivotal 合并,VMware 将 Pivotal 合并入了 Tanzu。

这里顺便提一下 VMware 在2009年出资现金3.62亿美元收购了由 Spring 框架作者 Rod Johnson 创办的 SpringSource 公司。Rod Johnson 以一个软件架构师的身份在2003年正式发布了 Spring 开源框架,随后 Spring 迅速流行,并成为 Java 应用开发领域最主流的框架软件。Rod Johnson 为了更好的发展基于 Spring 的 Java 开源解决方案创办了 interface21 公司,之后拿到了风险投资改名为 SpringSource,并且展开一系列收购,比方说Java领域的快速开发语言和框架 Groovy 和 Grails 的团队,最终在2009年以相当高的价格套现,Rod Johnson 也摇身成为亿万富翁。Rod Johnson 凭借开源软件的创业成功经历也必将激励更多开源软件走向商业成功。

可以认为,VMware 将 Spring,Spring boot, Spring Cloud 的核心贡献公司尽收囊中。

Pivotal公司的 Matt Stine于2013年首次提出云原生(CloudNative)的概念;云原生“CloudNative”是组合词,Cloud指是以云计算为基础,Native指为云而设计,Cloud Native 指充分利用、发挥云平台的弹性与分布式优势。

2015年,云原生刚推广时,Matt Stine 在《迁移到云原生架构》一书(Spring Cloud官网可以下载)中定义了符合云原生架构的几个特征:12因素、微服务、自敏捷架构、基于API协作、扛脆弱性;到了2017年,Matt Stine在接受InfoQ采访时又改了口风,将云原生架构归纳为模块化、可观察、可部署、可测试、可替换、可处理6特质;而Pivotal最新官网对云原生概括为4个要点:DevOps+持续交付+微服务+容器。可见,云原生的概念是不断发展的。

2. Pivotal 和 Spring Boot,Spring Cloud 的联系

2013年,Pivotal 发布了重磅项目 Spring Boot。Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的 初始搭建以及开发过程。这使Spring Boot 逐渐成为应用敏捷开发领域的领导者。经过十多年的演进,Spring 难免变得体量庞大、复杂和臃肿,而 Spring Boot,通过采用约定优先配置的理念 对复杂度做了封装,对用户屏蔽了许多实现细节,使 Spring 重新回到轻量化这个初心。

2015年发布的 Spring Cloud,则体现了 Pivotal 在微服务技术上的领先实力。Spring Cloud 是基于 Spring Boot 提供的一套微服务解决方案,它为开发人员提供了一系列组件。在2014年微服务概念被提出后,流媒体巨头 Netflix 因成功实现了大规模生产级别的微服务架构,成为业界楷模。而当时给 Netflix 提供咨询服务的正是 Pivotal。于是,Pivotal 将 Netflix 的全套组件 Netflix OSS 纳入到 Spring Cloud 中,使 Spring 在云时代重新回到了 Java 应用开发框架的头把交椅上。

很明显,Spring Boot 和 Spring Cloud 是 Pivotal 在推广其云原生服务中,自己开发或者由客户实现其开发理念所产生的开源框架。

3. Spring Cloud

Spring Cloud 是2015年发布的,因此遵循了《迁移到云原生架构》中对云原生架构的基本特征。也就是12因素、微服务、自敏捷架构、基于API协作、扛脆弱性;这个在Spring Cloud 官方文档上有所体现。

3.1 12-factor 应用

1. 基准代码 (Codebase)

一份基准代码,多份部署 (One codebase tracked in revision control, many deploys)

使用版本管理软件比如Git等,对源代码进行管理。每个应用,应当只有一份基准代码,多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库,然后使用 依赖管理 策略去加载它们。不同环境的代码,可以使用不同版本的代码进行发布。

2. 依赖 (Dependencies)

显式声明依赖关系 (Explicitly declare and isolate dependencies)

也就是说,应该使用额外的描述性文件,比如pom.xml等来声明依赖关系,在代码库中,不会存在具体的依赖项,只有在打包阶段,才将实际的依赖项打包到最终的包中。

3. 配置 (Config)

在环境中存储配置 (Store config in the environment)

通常,应用的 配置 在不同 部署 (预发布、生产环境、开发环境等等) 间会有很大差异。这其中包括:

  • 数据库,Memcached,以及其他 后端服务 的配置
  • 第三方服务的证书,如 Amazon S3、Twitter 等
  • 每份部署特有的配置,如域名等

有些应用在代码中使用常量保存配置,这与 12-Factor 所要求的代码和配置严格分离显然大相径庭。配置文件在各部署间存在大幅差异,代码却完全一致。

判断一个应用是否正确地将配置排除在代码之外,一个简单的方法是看该应用的基准代码是否可以立刻开源,而不用担心会暴露任何敏感的信息。

12-Factor推荐将应用的配置存储于 环境变量 中( env vars, env )。环境变量可以非常方便地在不同的部署间做修改,却不动一行代码;与配置文件不同,不小心把它们签入代码库的概率微乎其微;与一些传统的解决配置问题的机制(比如 Java 的属性配置文件)相比,环境变量与语言和系统无关。

配置管理的另一个方面是分组。有时应用会将配置按照特定部署进行分组(或叫做“环境”),例如Rails中的 development,test, 和 production 环境。这种方法无法轻易扩展:更多部署意味着更多新的环境,例如 staging 或 qa 。 随着项目的不断深入,开发人员可能还会添加他们自己的环境,比如 joes-staging ,这将导致各种配置组合的激增,从而给管理部署增加了很多不确定因素。

配置与代码相隔离,在spring的框架中,占有重要的篇幅,Spring Cloud Context 包中也有比较大的篇幅。

4. 后端服务 (Backing services)

把后端服务当作附加资源 (Treat backing services as attached resources)

后端服务是指程序运行所需要的通过网络调用的各种服务,如数据库(MySQL,CouchDB),消息/队列系统(RabbitMQ,Beanstalkd),SMTP 邮件发送服务(Postfix),以及缓存系统(Memcached)。

类似数据库的后端服务,通常由部署应用程序的系统管理员一起管理。除了本地服务之外,应用程序有可能使用了第三方发布和管理的服务。示例包括 SMTP(例如 Postmark),数据收集服务(例如 New Relic 或 Loggly),数据存储服务(如 Amazon S3),以及使用 API 访问的服务(例如 Twitter, Google Maps, Last.fm)。

每个不同的后端服务是一份 资源 。例如,一个 MySQL 数据库是一个资源,两个 MySQL 数据库(用来数据分区)就被当作是 2 个不同的资源。12-Factor 应用将这些数据库都视作 附加资源 ,这些资源和它们附属的部署保持松耦合。

依赖后端服务,可以使得当前的应用进程变成无状态的,重新启动数据不丢失。

5. 构建,发布,运行 (Build, release, run)

严格分离构建和运行 (Strictly separate build and run stages)

基准代码 转化为一份部署(非开发环境)需要以下三个阶段:

(1). 构建阶段 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包 依赖项,编译成二进制文件和资源文件。

(2). 发布阶段 会将构建的结果和当前部署所需 配置 相结合,并能够立刻在运行环境中投入使用。

(3). 运行阶段 (或者说“运行时”)是指针对选定的发布版本,在执行环境中启动一系列应用程序 进程

12-factor 应用严格区分构建,发布,运行这三个步骤。 举例来说,直接修改处于运行状态的代码是非常不可取的做法,因为这些修改很难再同步回构建步骤。

6. 进程 (Processes)

以一个或多个无状态进程运行应用 (Execute the app as one or more stateless processes)

运行环境中,应用程序通常是以一个和多个进程运行的。

12-Factor 应用的进程必须无状态且 无共享 。 任何需要持久化的数据都要存储在 后端服务 内,比如数据库。

一些互联网系统依赖于 “粘性 session”, 这是指将用户 session 中的数据缓存至某进程的内存中,并将同一用户的后续请求路由到同一个进程。粘性 session 是 12-Factor 极力反对的。Session 中的数据应该保存在诸如 Memcached 或 Redis 这样的带有过期时间的缓存中。

与第8点相辅相成

7. 端口绑定 (Port binding)

通过端口绑定来提供服务 (Export services via port binding)

12-Factor 应用完全自我加载 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 通过端口绑定来提供服务 ,并监听发送至该端口的请求。

通常的实现思路是,将网络服务器类库通过 依赖声明 载入应用。例如,Python 的 Tornado, Ruby 的Thin , Java 以及其他基于 JVM 语言的 Jetty。完全由 用户端 ,确切的说应该是应用的代码,发起请求。和运行环境约定好绑定的端口即可处理这些请求。

8. 并发 (Concurrency)

通过进程模型进行扩展 (Scale out via the process model)

简单来说,可以通过启动多个实例进程,来扩展程序,提高程序的服务能力。

9. 易处理 (Disposability)

快速启动和优雅终止可最大化健壮性 (Maximize robustness with fast startup and graceful shutdown)

12-Factor 应用的 进程 是 易处理(disposable)的,意思是说它们可以瞬间开启或停止。 这有利于快速、弹性的伸缩应用,迅速部署变化的 代码配置 ,稳健的部署应用。

10. 开发环境与线上环境等价 (Dev/prod parity)

尽可能的保持开发,预发布,线上环境相同 (Keep development, staging, and production as similar as possible)

11. 日志 (Logs)

把日志当作事件流 (Treat logs as event streams)

日志应该是 事件流 的汇总,将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行,日志最原始的格式确实是一个事件一行。日志没有确定开始和结束,但随着应用在运行会持续的增加。

总体而言,12-Factor 应当只是按照一定的格式输出日志文件,后续的查看,搜索和处理由其他系统去处理。

12. 管理进程 (Admin processes)

启动管理任务当作一次性进程运行 (Run admin/management tasks as one-off processes)

也就是说,可以启动一些一次性的进程来做一些额外的操作,比如数据迁移等。 一次性管理进程应该和正常的 常驻进程 使用同样的环境。这些管理进程和任何其他的进程一样使用相同的 代码配置 ,基于某个 发布版本 运行。后台管理代码应该随其他应用程序代码一起发布,从而避免同步问题。

3.2 微服务(Microservices)

微服务,是将一个庞大的系统拆分成很多个小而美的服务。这方面的资料比较多,因此不做展开。

3.3 自敏捷架构(Self-Service Agile Infrastructure)

也就是说,一个团队在开发基于云原生架构的应用时,通常还需要负责应用的发布和持续集成,因此需要授权团队一个发布和持续集成平台的权限。这个平台可以满足一个团队发布和维护应用的需求。

3.4 基于API协作

在云原生架构下,服务间的调用只能通过发布版本化的API来沟通。通常是基于JSON序列化的HTTP REST形式。团队在不修改现有API的情况下,发布新的API是不需要通知其他团队的。

3.5 扛脆弱性

在遇到压力的时候,不是变得脆弱,而是变得更强,比如人体的免疫系统。可以参考Netflix的猴子军团(Netflix Simian Army),也就是在生产环境中引入一些组件,主动制造一些混乱(比如关掉某台服务器),对系统进行施压,对出现的问题及时修复。这样在生产上遇到类似的问题时,系统可以存活。

3.2 Spring Cloud

查看Spring Cloud 的官方网站,第一段介绍如下:

Developing distributed systems can be challenging. Complexity is moved from the application layer to the network layer and demands greater interaction between services. Making your code ‘cloud-native’ means dealing with 12-factor issues such as external configuration, statelessness, logging, and connecting to backing services. The Spring Cloud suite of projects contains many of the services you need to make your applications run in the cloud.

开发一个分布式系统将会是一个挑战。复杂性从应用层转移到了网络层和服务之间的交互。让你的代码符合云原生风格,意味着需要处理 12-factor 的问题,比如外部配置文件,无状态性,记录日志,与后端服务进行连接等。Spring Cloud 套件包含了很多服务,使用这些服务,可以让你的应用部署在云上。

很明显,Spring Cloud 是一些依赖或者服务,让你可以更快地开发出云原生的应用。比如 Spring Cloud Gateway,Spring Cloud Netflix等。其中最核心的当属核心模块:Spring Cloud Commons,有很多 Spring Cloud 组件实现了相关的接口。包含两个核心的依赖 Spring Cloud Context and Spring Cloud Commons。Spring Cloud Context 提供了一些实用的功能(bootstrap context, encryption, refresh scope and environment endpoints),而Spring Cloud Commons主要提供了一些抽象类或者公共类,提供给一些Spring Cloud组件进行实现,比如Spring Cloud Netflix,Spring Cloud Consul等。

Spring Cloud Context

特性如下:

  • Bootstrap Context (Bootstrap 上下文)
  • TextEncryptor beans (文本编码)
  • Refresh Scope (刷新配置类)
  • Spring Boot Actuator endpoints for manipulating the Environment (操作环境的端点)

Spring Cloud Commons

特性如下:

  • DiscoveryClient interface (服务发现接口)
  • ServiceRegistry interface (服务注册接口)
  • Instrumentation for RestTemplate to resolve hostnames using DiscoveryClient (使用DiscoveryClient来真实域名)

可以看到,Spring Cloud Commons 提供了服务发现和服务注册的基本接口,DiscoveryClient 接口的方法如下:

public interface DiscoveryClient extends Ordered {
	int DEFAULT_ORDER = 0;
	String description();
	List<ServiceInstance> getInstances(String serviceId);
	List<String> getServices();
	default void probe() {getServices();}
	@Override
	default int getOrder() {return DEFAULT_ORDER;}
}

public interface ServiceRegistry<R extends Registration> {
    void register(R registration);
    void deregister(R registration);
    void close();
    void setStatus(R registration, String status);
    <T> T getStatus(R registration);

}
public interface ServiceInstance {
    default String getInstanceId() {return null;}
    String getServiceId();
    String getHost();
    int getPort();
    boolean isSecure();
    URI getUri();
    Map<String, String> getMetadata();
    default String getScheme() {return null;}
}

DiscoveryClient 和 ServiceRegistry 的接口定义的方法非常简单,就是向注册中心提交当前客户端信息(服务名,实例id,端口号,host, 是否是安全的通信(https),其他一些元(map)),实现了DiscoveryClient 和 ServiceRegistry 的接口, 通过实现 DiscoveryClient 和 ServiceRegistry,可以将现有的一些流行注册组件包装成为一个Spring Cloud的服务注册中心,比如 Eureka, Consul, Zookeeper 等。

4. 总结

云原生(Cloud Native) 是一种编程风格,符合云原生的应用,可以充分利用、发挥云平台的弹性与分布式优势。其特征跟随着技术的不断发展有所变化,目前认为,其特征包括:DevOps+持续交付+微服务+容器。为了能够让JAVA应用云原生化,Pivotal 在2015年开源了 Spring Cloud 。这不是一个新的框架,而是一些依赖或者服务。比如注册中心,配置中心,API网关等,可以认为是一些基础设施,通过这些服务,可以让JAVA适应现代的编程方式,并能利用云平台达到分布式部署,快速扩容或者缩容的目的,节省人力和设备成本。

5. 参考

pivotal公司简介
云原生架构_云原生架构-与Matt Stine的对话
走进 Spring 身后不一般的 Pivotal
十二要素应用 (The Twelve-Factor App)
VMware4.2亿美元收购SpringSource,构建PAAS平台梦想
Spring Cloud Commons
Pivotal Software 维基百科
云原生的崛起【The Rise of Cloud-Native】(Migrating to Cloud-Native Application Architectures译文)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值