本文希望从技术角度来探讨下微服务, 因此, 不会过多地谈及如何根据业务进行微服务划分, 更多是介绍微服务的相关技术, 微服务的业务划分方法可参考领域驱动设计相关方法论
微服务的两个程度
一服务化
复杂的单体架构会有以下的挑战:
(1)项目启动初期, 需要寻找一个能尽量涵盖所有需求的开发语言, 技术选型难度高;
(2)工程庞大, 组件中间件繁多, 编译时间长; 开发环境复杂, 需要安装大量的辅助软件, 环境准备时间长;
(3)团队无效沟通多, 沟通成本高;
(4)部署环境依赖大, 某个组件的问题可能导致整个系统无法运行;
(5)新功能添加或者 bug 修复的时候, 会影响现有功能, 引发新的 (未知) 问题, 添加单元测试难度大;
(6)版本回滚颗粒度大, 灵活性差
以上几点都是实际项目中遇到的问题, 如果你也遇到了同样的问题, 那么服务化是较好的解决方案
服务化解耦后:
(1)微服务可以根据自身业务特征选择合适的开发语言或数据库;
(2)微服务的开发者只需要安装该服务相关的辅助软件;
(3)沟通多集中在微服务团队中, 与周边 (或公共) 微服务有交集时才产生相应的沟通;
(4)部署环境依赖小, 某个微服务部署失败仅影响该微服务(或周边几个微服务);
(5)功能调整, 如果接口没有调整, 基本不会影响其它微服务, 添加单元测试接口测试难度低, 自动化 (回归) 测试覆盖率高;
(6)版本回归最小单位为某个微服务, 颗粒度小, 可更好地实现蓝绿部署 A/B 测试灰度 (金丝雀) 发布
二容器化
容器 (docker) 具有轻量环境依赖低启动速度快等特点;
虚拟化技术 (openstack) 负责 IaaS 层 (存储计算网络) 资源的调度;
容器治理平台 (Kubernetesdocker swarm) 配合资源监控对容器进行灵活调度;
以上 3 种技术极大地提高了微服务的横向 (弹性) 伸缩以及高可用的能力, 使微服务具备更好的高并发处理能力
配合 DevOps,CI/CD 等工具及技术提升了团队快速响应持续交付的能力
我认为, 团队应该基于产品或项目实际情况选择合适的微服务程度
微服务基础技术架构
我认为, 当前使用前后端分离的开发模式还是十分有好处的, 关于前后端分离的描述, 可参考我之前的浅谈开发模式及架构发展
web A/B/C/... 是几个纯前端项目, 可以根据实际情况在不同项目中使用 Angularjsvuejs 或 Reactjs 等框架进行开发;
API X/Y/Z/... 是几个 API 项目, 供 Web 或者 App 调用, 可以根据实际情况使用. Net CoreJava 或 python 等语言进行开发;
也可以根据带宽或性能需要, 让 Web 或 API 启动多份示例
基本交互:
浏览器经过网关从服务端获取网站的 html 及 js(橙色箭头);
Web 通过 url 或 ajax 经过网关访问服务端 API,App 通过类 Http Client 方式经过网关访问服务端 API(灰色箭头);
API X/Y/Z/... 注册到服务中心(蓝色箭头);
Web A/B/C/...API X/Y/Z/... 从配置中心读取各自的配置(紫色箭头);
API X 通过服务中心调用 API Z(绿色箭头)
因此, 微服务的三个基础组成部分分别是服务注册发现, 配置管理以及网关
服务注册发现
一最简单的服务注册发现
我认为最简单的服务注册发现是直接通过 IP 端口进行访问, 这种方式适用于单个实例的服务, 但如果 API Y 是多个实例, 那么需要借助类似虚拟 IP(VIP)等技术
二基于中间件的服务注册发现
API Y 实例 1/2/.../n 启动时, 会把自己的信息注册到服务中心 (自上报);API X 需要调用 API Y, 会先从服务中心中获取 API Y 服务实例的 IP 端口列表; 然后根据特定的策略(随机, 网络情况, 权重等) 筛选出一个实例进行调用, 负载均衡是在客户端 (调用方) 实现的
这种方式的典型代表是 Spring Cloud Eureka, 如果服务中心 down 掉了, 那么会影响整个系统, 因此, 要保证服务中心的高可用; 另外, 需要有特定的 jdk/sdk 和服务中心进行交互, 如 Java 的 FeignClient(集成了 ribbon 实现服务的负载均衡),steeltoe 的 DiscoveryHttpClientHandler(随机选择实现服务的负载均衡), 有一定的语言侵入性
三基于容器治理平台的服务注册发现
API Y 实例 1/2/.../n 部署启动时, 治理平台会给它们分配 IP 端口, 并记录在服务中心; API X 需要调用 API Y, 会基于 dns, 通过 API Y 的服务名或集群 IP(Cluster IP, 类似于 Virtual IP)加端口进行访问负载均衡由治理平台负责, 是在服务端 (平台) 实现的
这种方式的典型代表是 docker swarm 以及 Kubernetes, 服务注册发现的高可用由平台保证, 因为基于 dns, 普通的 http 客户端就可以进行 Api 访问, 如 java 的 restTemplate 或 C# 的 HttpClient, 无语言侵入性, 但负载均衡的灵活性比中间件的方式稍微低一些
配置管理
一最简单的配置管理
最简单的配置管理就是平时常用的配置管理, 如 java 的 application.properties.net 的 web.config.net core 的 appsettings.json 等, 基本是和应用程序一起, 能够兼容多个环境(开发测试生产)
但当我们的程序需要启用多份的时候, 这种简单的配置管理方式遇到了挑战, 配置的更新需要手动更新各个实例的配置文件, 繁琐且容易出错(遗漏修改错误或环境依赖)
这也是微服务中面临的一个主要挑战
二基于中间件的配置管理
这种方式的典型代表是 Spring Cloud Config Server
API XY... 会通过 Url 访问配置中心, 通过心跳 (2s) 来确认配置中心的健康以及检测配置内容的更新
其中, application.yaml 用于保存各个微服务的公共配置,{服务名}.yaml 用于保存微服务的私有配置
和 Eureka 一样, 使用者需要自己保证 Config Server 的高可用, 否则, 配置中心 down 掉的话, 整个系统的配置信息就会乱套; 另外, 也需要有特定的 jdk/sdk 和配置中心进行交互; 配置文件的格式基本也限制于 yaml 格式
三基于容器治理平台的配置管理
这种方式的典型代表是 Kubernetes ConfigMap
部署升级增加 API XY... 实例时, Kubernetes 会按照设置, 把对应的配置文件放置到容器 (docker) 指定的位置, 也可以是环境变量
配置中心的高可用由治理平台保证, 微服务不需要使用特定的 jdk/sdk 和配置中心交互, 只需要解析本地路径的某些文件, 文件格式可以根据需要选择(json,xml,yaml,properties)
微服务公共配置与私有配置也可以实现, 但需要语言支持, 比如. net core, 详细的可以参考我之前的文章你可能不知道的. Net Core Configuration
网关
网关作为微服务的统一出口, 一般需要完成以下任务: 反向代理, 跨域处理, 负载均衡, 流量控制, 缓存, 日志, 公共功能 (如认证) 等, 常用的网关中间件有 Nginx,Spring Cloud Zuul,Kong,Ocelot 等
或许有人会问, 像公共功能 (如认证) 这些, 在过滤器 (filter) 里做就好了啊, 为什么要在网关做, 没看出什么优势 I think it is a good call.
确实, 像认证这些功能的确可以在过滤器里做, 但是, 如果过滤器需要升级, 那么每个微服务都要进行升级; 另外一种情况是, 如果微服务是使用不同语言编写的, 那么还需要提供多个版本的 filter; 更为恶劣的可能是该语言不支持 filter, 或者像单点登录这些公共模块没有提供该语言的 jdk 或 sdk; 还有一种比较特殊的情况是, 可能在不同的环境系统需要有不同的认证机制, 如对接第三方的认证系统使用网关就能比较好的解决以上问题
下一代微服务
既然可以通过部署一个网关, 让所有请求都经过它来实现一些公共的功能, 那么有没有可能使微服务的请求经过一个特定的层, 来实现一些特定的功能 (如调用链熔断, 服务调用认证, 请求限制等) 呢? 答案是肯定的
我认为 Kubernetes 其中一个强大的设计是, 它的最小单位是 pod, 而不是容器(container); 一个 pod 里面可以有多个容器, 而且它们可以共享网络, 共享存储
可以通过在 pod 里面部署一个业务容器, 同时也部署一个小型的 sidecar 容器, 让请求到达业务容器之前, 先经过 sidecar 容器(起到了 filter 的作用), 在 sidecar 容器中实现调用链熔断, 服务调用认证, 请求限制等功能, 这样就可以通过基于部署的方式解决语言限制的问题
目前可以选择 Istio 或 Linkerd 来实现上述效果
简单总结
我认为, 从架构的层面来看微服务架构, 应该是这样的:
扩展性: 降低复杂系统的耦合度沟通成本以及系统复杂度, 需求快速响应;
伸缩性: 可以通过增加资源的方式来快速应对海量并发(仅仅是并发层面, 大数据量还是需要根据业务进行分片或分割);
稳定性: 微服务治理平台, PaaS 平台保证了系统的高可用性, 可以降低业务的中断时间;
安全性: 和传统架构的要求差别不大, 但是由于网关和网格 (Service Mesh) 的存在, 使得安全处理, APM 等的实现更加简单
另外, 我认为微服务可以通过部署的方式来实现功能或模块的复用, 一定程度上代替了过往通过 jdk/sdk 来实现共用的方式; 使得开发更加灵活, 也使得开发可以更加关注于业务, 而非各种边边角角的公共 (轮子) 功能
来源: https://www.cnblogs.com/Erik_Xu/p/8495939.html