微服务浪潮中,程序猿如何让自己 Be Cloud Native

前言

CNCF 与 Cloud Native 这两个技术词汇最近频频走进了程序员的视野,一切和他能搭上边的软件意味着标准、开放、时尚,也更能俘获技术哥哥们的心;这篇文章不想去带大家重温这个词汇后面的软件体系,笔者觉得单凭用到了这些开源软件,不等于我们自己的软件就已经是 Cloud Native,在使用哑铃和成为肌肉男之间还隔着科学使用和自律锻炼两道工序;在此,笔者想根跟大家聊聊让我们的应用真正变得 Cloud Native 时的理论依据:微服务的十二要素。这篇文章也是先从作者自身项目的角度(一个基于 EDAS 的微服务架构),来阐述对这十二条要素的前两条 —— 仓库(Code Base)与依赖(Dependency)的理解

Code Base 的原文释义是:"一份基准代码,多份部署,基准代码和应用之间总是保持一一对应的关系;不同环境中的相同应用,应该来源于同一份代码"。我的理解有两个:

  1. 一个应用,产生自同一个仓库。
  2. 一个仓库,只产生一个应用。

为什么推演出这么两个结论呢?让我们先看一个实际的项目。

为什么是一个应用?

? 给大家举一个一个仓库包含多个应用的反例,笔者自己的一个项目是一个的微服务的架构,和大部分的微服务架构一样,一开始是由一个单体的应用拆解而来,拆解之后,大致简化成四个服务:微服务网关(Gateway),两个后台服务(UserService, OrderService),后台管理控制台服务(Admin),简单的架构示意图如下:

? 在拆分的过程一开始为了项目上线的减少风险,将拆分之后的应用都放在了一个 GIT 仓库中进行管理,同时也共用了同一个库。重构之后仓库的目录如下:

~/workspace/java/app/ $ tree -L 2
.
├── README.md
├── service-api # 通用的 API 接口定义
│   ├── userservice-api # 服务 UserService 的声明
│   ├── orderservice-api # 服务 OrderService 的声明
│   ├── rpc-api # 远程服务调用相关的接口声明
│   ├── common-api # UserService 与 OrderService 都依赖的声明
|   .....
├── service-impl # 对应 API 的相关具体业务实现
│   ├── userservice-impl
│   ├── orderservice-impl
│   ├── common-impl
|   .....
├── web-app # Web 应用工程
│   ├── admin
│   ├── userservice
│   ├── orderservice
│   ├── gateway

? 一开始这些服务之间的发布和改动彼此都不受影响,这一过程持续了大约两个迭代,随着迭代的不断进行和新人的加入,后来我们线上发现一个很奇怪的现象,每次用户进入刷新订单的地址列表的时候,会伴随这一次用户 Token 的刷新而导致用户被踢出,线上的排查过程在 EDAS 的分布式链路跟踪系统 EagleEye 的帮助下,马上就定位到了出问题的代码:

// User Service 中
public class User {
    public void refresh() {
        // 刷新登录 token
    }
}

// Order Service 中
public class OrderUser extends User {
    // 函数少了一个字母,导致 refresh 调用了父类的 refresh
    public void refesh() {
        // 刷新地址列表
    }
}

?这个故障,我先邀请大家一起思考一下几个问题:

  1. 从编码角度,如何避免上述重写的方法因为名字误写造成故障?
  2. 从设计角度,OrderUser 和 User,是否是继承关系?
  3. 这个问题的根因是什么?

以上的几个问题中,第一个问题的答案,很多同学都知道,就是使用 Java 自带的 Annotation @Override,他会自动强制去检查所修饰的方法签名在父子类中是否一致。第二个问题,需要从领域边界来说,这是一个典型的边界划分的问题,即:订单中的用户,和会员登录中的用户,是不是相同的“用户”?会员中的用户,其实只需要关心用户名密码,其他都是这个用户的属性;而订单中的用户,最重要的肯定是联系方式,即一个联系方式,确定一个人。虽然他们都叫做用户,但是在彼此的上下文中,肯定是不一样的概念。所以这里的 OrderUser 和 User 是不能用继承关系的,因为他们就不是一个 "IS A" 的关系。
__仓库共享__,加上没有多加思考的模型,导致依赖混乱;如果两个 User  对象之间代码上能做到隔离,不是那么轻易的产生“关系”,这一切或许可以避免。

为什么是一个仓库?

严格意义上说,一个应用的所有代码都肯定来源于不同的仓库?我们所依赖的三方库如(fastjson, edas-sdk 等)肯定是来源于其他的仓库;这些类库是有确切的名称和版本号,且已经构建好的"制品",这里所说的一个仓库,是指源码级别的“在制品”。可能在很多的项目中不会存在这样的情况,以 GIT 为例,他一般发生在 submodule 为组织结构的工程中,场景一般是啥呢?在我们这个工程中确实是有一个这样的例子:

为了解掉第一个问题,我们决定拆仓库,仓库的粒度按照应用粒度分,同时把 common 相关的都拆到一个叫做 common 仓库中去;业务服务都好说,这里特殊处理的是 admin 应用,admin 是一个后台管理应用,变化频度特别大,需要依赖 UserService 和 OrderService 一大堆的接口。关于和其他仓库接口依赖的处理,这里除了常见的 Maven 依赖方式之外,还有另外一个解决方案就是 git submodule,关于两个方案的对比,我简单罗列在了下表之中:

  优点 缺点
Maven 依赖 可指定已固化的版本进行依赖 必须发布成二方包
Submodule 依赖 灵活、可直接共享代码库 变更不可控

我觉得如果这个项目组只有一两个人的时候,不会带来协作的问题;上面的方案随便哪一个都是不需要花太多时间做特殊讨论,挑自己最熟悉最拿手的方案肯定不会有错,所谓小团队靠技术吗,说的就是这么个道理;我们当时是一个小团队,同时团队中也有同学对 submodule 处理过类似的情况,所以方案的选择上就很自然了。

后来随着时间的推移,团队慢慢变大,就发现需要制定一些流程和和规范来约束一些行为,以此保障团队的协作关系的时候;这时候发现之前靠一己之力打拼下来的地盘在多人写作下变得脆弱不堪,尤其是另外一个 submodule 变成一个团队进行维护的时候,submodule 的版本管理几乎不可预期,而且他的接口变动和改动是完全不会理会被依赖方的感受的,因为他也不知道是否被依赖;久而久之,你就会明白什么叫做你的项目被__腐化__了。简单理解__腐化__这个词就是,你已经开始害怕你所做的一切改动,因为你不知道你的改动是否会引来额外的麻烦。从这个角度也可以去理解为什么一门语言设计出来为什么要有 __private__、__public__这些表示范围的修饰词。正因为有这些词的存在,才让你的业务代码的高内聚成为的有可能,小到设计一个方法一个类、再引申到一个接口一个服务、再到一个系统一个仓库,这个原则始终不变。

上述问题带来的解法很简单,就是变成显示依赖的关系,所谓显示依赖是指的两个依赖之间是确定的。什么是确定的?确定 == No Supprise !对,不管什么时候,线上还是线下,我依赖你测试环境的接口返回是一个整数,到了线上,返回的也必须是一个整数、不能变成浮点数。而让确定性变得可行的,不是君子协定;只能是一个版本依赖工具。比如说 Java 中的 Maven 正式的版本依赖。

结语

职责内聚、依赖确定,是我们的应用变得真正 Cloud Native 的前提。没有了这些基本的内功,懂的开源软件再多、对微服务栈再熟悉,也会有各种意想不到的事情出来,试想一下,如果应用的职责到处分散,那到时候扩容到底扩谁呢?如果依赖方变得及其不确定,谁又来为每次发版的不确定的成本买单?Be Cloud Native,请从应用代码托管的住所开始。

原文链接
本文为云栖社区原创内容,未经允许不得转载。

原文地址:https://www.cnblogs.com/yunqishequ/p/10196453.html

时间: 2024-10-11 02:14:08

微服务浪潮中,程序猿如何让自己 Be Cloud Native的相关文章

如何用微服务重构应用程序

在决定使用微服务之后,为了将微服务付诸实践,也许你已经开始重构你的应用程序或把重构工作列入了待办事项清单. 无论是哪种情况,如果这是你第一次重构应用程序,那么您和您的团队必将在某个时刻面临一个显而易见的问题:如何重构应用程序以实现微服务? 这也正是这篇文章要思考和探讨的. 重构基础 在讨论如何将重构转化为微服务之前,退后一步,仔细观察微服务的内容和时间是很重要的.以下两个要点将会对任何微服务重构策略产生重大影响. 重构=重新设计 将一个单体式的应用程序重构为微服务,与重新设计一个基于微服务的应用

微服务-分解应用程序从而实现更好的部署特性及可伸缩性

本文是我翻译INFQ上的一篇文章.作者Chris由简入深的讲解了微服务的来龙去脉.使用场景.优势劣势.以及现有技术栈向微服务架构的重构步骤.是一篇微服务主题的不可多得的好文. 原文地址:http://www.infoq.com/articles/microservices-intro?utm_source=infoq&utm_medium=popular_links_homepage#.U4-QbLLNKmI.gmail 微服务:分解应用程序从而实现更好的部署特性及可伸缩性 本文描述了越来越受欢

微服务开发中的数据架构设计

本文来自作者 陈伟荣 在 GitChat 分享的文章[微服务开发中的数据架构设计] 前言 微服务是当前非常流行的技术框架,通过服务的小型化.原子化以及分布式架构的弹性伸缩和高可用性,可以实现业务之间的松耦合.业务的灵活调整组合以及系统的高可用性.为业务创新和业务持续提供了一个良好的基础平台.本文分享在这种技术架构下的数据架构的设计思想以及设计要点,本文包括下面若干内容. 微服务技术框架中的多层数据架构设计 数据架构设计中的要点 要点1:数据易用性 要点2:主.副数据及数据解耦 要点3:分库分表

微服务架构中APIGateway原理

背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用. 但是在UI上进行展示的时候,我们通常需要在一个界面上展示很多数据,这些数据可能来自于不同的微服务中,举个例子. 在一个电商系统中,查看一个商品详情页,这个商品详情页包含商品的标题,价格,库存,评论等,这些数据对于后端

微服务系统中的认证策略

软件安全本身就是个很复杂的问题,由于微服务系统中的每个服务都要处理安全问题,所以在微服务场景下会更复杂.David Borsos在最近的伦敦微服务大会上作了相关内容的演讲,并评估了四种面向微服务系统的身份验证方案. 在传统的单体架构中,单个服务保存所有的用户数据,可以校验用户,并在认证成功后创建HTTP会话.在微服务架构中,用户是在和服务集合交互,每个服务都有可能需要知道请求的用户是谁.一种朴素的解决方案是在微服务系统中应用与单体系统中相同的模式,但是问题就在于如何让所有的服务访问用户的数据.解

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们应该如何进行网络请求的优化与处理呢? 到底有没有一些好的建议与方案呢? 下面这个文章将揭晓上面的问题,让你对SpringCloud微服务网络请求性能有一个全新的认识. 目录简介 01.网络请求异常分类 02.开发中注意问题 03.原始的处理方式 04.如何减少代码耦合性 05.异常统一处理步骤 06

微服务架构中整合网关、权限服务

前言:之前的文章有讲过微服务的权限系列和网关实现,都是孤立存在,本文将整合后端服务与网关.权限系统.安全权限部分的实现还讲解了基于前置验证的方式实现,但是由于与业务联系比较紧密,没有具体的示例.业务权限与业务联系非常密切,本次的整合项目将会把这部分的操作权限校验实现基于具体的业务服务. 1. 前文回顾与整合设计 在认证鉴权与API权限控制在微服务架构中的设计与实现系列文章中,讲解了在微服务架构中Auth系统的授权认证和鉴权.在微服务网关中,讲解了基于netflix-zuul组件实现的微服务网关.

微服务架构中的安全认证与鉴权

转载:http://www.bootdo.com/blog/open/post/125 从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断的经受考验.为了适应架构的变化.需求的变化,身份认证与鉴权方案也在不断的变革.面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证?面对外部的服务访问,该如何提供细粒度的鉴权方案?本文将会为大家阐述微服务架构下的安全认证与鉴权方案. 单体应用 VS 微服务 随着微服务架构的兴起,传统的单体应用场景下的身份认证和鉴权面临的挑战越来越大

微服务----微服务架构中的提取基础组件

一.前言 在第一家公司中,接触到了公司的项目代码,在代码中使用了微服务的功能,使用到了公司封装的xx架构服务,简称为B架构,在B架构中具有基础业务功能服务,比如组织架构服务,日志服务,权限服务. 然后我们在项目中使用B架构中的服务,能够很容器也能很快捷地进行项目的开发,从而避免其他的非核心业务的编写. 二.基础功能组件 这些组件肯定是每一个应用到可以需要使用到的,这些组件是可以提取出来的,比如日志服务.监控服.统计服务.权限服务.认证服务等等.通过微服务的注册发现.配置.网关等,从而搭建出基础功