云原生这个词相信大家都不陌生,那如果要问你,到底什么是云原生,该怎么回答呢?
云原生
云原生计算基金会 CNCF 在他们的官网上给出的解释是这样的。
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可观测的重大变更。
其实上面的定义讲了这么多,对应什么是云原生还是很模糊的,不过从上面的定义中我们可以得到几个关键的信息
- 云原生应用是需要部署在云环境中的,但是反过来部署在云环境中的应用并不一定是云原生应用。
- 云原生应用具备一定的可扩展性、容错性和可观察性;
- 云原生不是一种技术或者框架,而是一种思想;
这个也比较好理解,早期的时候如果一个公司想要上线应用或者服务,需要自己购买机器部署机房,然后才能在机房的服务器中部署自己的应用,这种肯定不是云原生,毕竟连云都还没有上。
后面渐渐的很多云厂商起来了,提供了云环境,这个时候大家如果要部署应用就不再需要自建机房了,只需要在云厂商那里购买对应数据中心的服务器就行,就可以部署应用了,但是到这里只能说我们的应用上云了,我们的应用还并不是云原生应用。
这也是我们上面提到的应用部署到了云环境上面,并不是代表就是云原生应用的,因为这个时候我们的应用并没有充分利用云厂商的能力,同时也不具备扩展性、容错性和可观察性。
十二要素应用
前面介绍了什么是云原生,现在说下什么是十二要素应用。十二要素应用的提出是知名的 PasS 平台 Heroku 的 CTO Adam Wiggins 提出的,原本说的是云上运行的应用需要遵守的 12 条最佳实践,不过它也同样适用于云原生应用。
1、基准代码
基准代码说的是在我们日常开发和部署的时候,可能会有很多个环境,比如开发,测试,线上等,我们需要是同一份基准代码。不过这里主要强调的还是线上,因为我们云原生应用的部署是随时随地都可以动态扩展的,这就要保证我们线上的环境都是基于一份基准代码来进行部署,实现一套代码多份部署。
这点也很好理解,跟我们的分布式架构一样,也是同一份代码部署多个实例。
2、声明式依赖
声明式依赖说的是我们要显示声明依赖关系,现在有很多依赖管理工具,比如说我们的 Java 项目就会有 maven 和 gradle,其他语言的项目也会有其他的包管理工具。
除了我们开发中需要的类库的依赖需要显示之外,如果还需要依赖系统级别的工具或者库,我们也需要进行声明式的依赖,不能隐式依赖,这是因为在云原生的环境下,我们都是基于容器来部署应用的,如果不显示的将这些依赖声明出来,我们是不能创建出一模一样的容器镜像,这可能会导致服务不可用。
3、配置管理
一个应用如果想要正常的启动,除了代码没问题之外还要有正确的配置才行,对于云原生应用来说也是一样的。我们要做到不同的环境对于不同的配置,如果环境是一样的,配置也需要是一样的。并且要求我们的配置必须是和代码分开的,这也是很好理解的,毕竟我们一份应用代码要多环境部署,如果配置一样那是没有办法部署的。
对于配置的管理可以用一些中间件,比如 Diamond 或者其他的一些配置中心来管理,配置中心可以实现配置的实时变更和推送,很方便我们进行管理和变更。
4、后端服务
这里的后端服务更多说的是我们应用依赖的一些下游服务、组件服务、中间件服务,比如消息队列、数据库、缓存、调度平台等。云原生应用要求我们把这些后端服务都要当成资源来调用,并且这些资源也要符合云原生应用的规范,也就是能随时动态扩展。
5、构建、发布、运行
云原生应用要求我们严格将应用的构建、发布和运行进行隔离。应用的这几个过程是每次需求迭代过后上线的必经过程,并且这几个步骤是按照这个顺序进行的,也就是说不存在还没构建就进行发布,这个很好理解。对于我们 Java 应用来说,构建就是将源代码进行编译和打包,在构建阶段如果不通过是不会进行下一步的。
应用构建的时候如果缺少依赖或者有编译错误都会终止构建;发布则是将我们编译好的 Jar 包或者其他形式和配置文件一起进行部署到指定环境的容器中;运行则是将需要发布的内容进行启动,这个时候如果我们的配置有问题有可能会导致应用启动不了。
6、进程
云原生应用要求我们的应用是无状态的,这个也很好理解,毕竟云原生是随时可扩展的,那就必须要求我们的应用是无状态的,这就要求我们在开发的时候就要注意不要在代码中使用一些需要状态的逻辑。比如定时任务 scheduled 这种,会导致每个实例都会定时运行,可能会产生问题,可以采用类似于 XXL-JOB 这种分布式调度平台。
7、端口绑定
应用通过绑定端口来提供服务,这一点可能有些小伙伴不理解,因为现在大部分情况下我们已经是这样做的了,之所以提出这一点是为了避免在应用中使用进程通信。
8、并发
要求在高并发的时候支持通过进程扩展,也就是要求我们的应用是无状态,能通过更多的进程部署来实现扩展。这一点也很好理解,跟我们前面提到的无状态也是有关联的。
9、易处理
所谓易处理说的是我们的云原生应用应该具备快速启动和优雅终止的能力,因为的云原生环境要求具有弹性扩容的能力,那就需要我们的应用能够快速的启动和结束。
快速启动可以让我们的应用更快的提供服务,更快的满足弹性伸缩的要求,而优雅的终止也是为了避免在应用关闭的时候还存在任务或者流量访问。
10、开发环境与线上环境等价
此外我们需要尽量的保持开发环境、预发环境以及线上云原生环境相同,当然这里的相同只是是尽可能的保持相同,同样的环境能保证我们实现的功能不会因为环境问题而出现不可用的情况。但是要知道因为一些资源的问题,开发环境、预发环境跟线上环境是不会完全一样的。
11、日志
云原生要求我们把日志当成事件流,同样是因为云原生环境应用的实例个数随时都在发生着变化,每个实例时时刻刻都会产生日志,我们不能说在每台实例上面查看日志,所以我们要把日志统一收集和采集到特定的日志系统中。这一点其实在分布式系统里面也是一样的,一般会通过 ELK 技术,将日志进行存储和分析。
12、管理进程
最后一条这个管理进程指的是将后台管理系统的任务当成是一次性的进程进行执行,其实这一点不算是普适的要素,跟具体的后台系统功能有关,这里就不讨论了。
总结
上面提到了什么是云原生以及 12 条云原生应用的要素,很多跟我们分布式系统的要求都是一致的,只不过云原生应用的要求会更高一点,更严格一点,更自动化一点。
从了不起的角度来看云原生应用是目前看来最好的一种方式,对于企业或者个人来说都是最快和成本最低的。
对于很多小公司来说完全没必要自建一套基础设施,直接采用云厂商提供的能力就好,从而快速实现自身业务的发展,毕竟小公司活下去才是最重要的,没必要在这种事情上面浪费时间和精力。
参考
- 学透 Spring 从入门到项目实战
- 网络资料