微服务实践 | 焱融云前端微服务架构的设计要点

2019-09-25 焱融云 | flagloads旗舰店

1

什么是微服务

微服务是一种开发软件的架构和组织方法,其中软件由通过明确定义的 API 进行通信的小型独立服务组成,这些服务由各个小型独立团队负责,每个服务可被独立部署,服务之间是松耦合的,每个服务仅关注于完成一件任务。微服务架构使应用程序更易于扩展和更快地开发,从而加速创新并缩短新功能的上线时间。

2

整体式架构与微服务架构

整体式架构,所有进程紧密耦合,并可作为单项服务运行。这意味着,如果应用程序的一个进程达到峰值,则必须扩展整个架构。随着代码库的增长,添加或改进整体式应用程序的功能变得更加复杂。这种复杂性限制了试验的可行性,并使实施新功能变得困难。整体式架构增加了应用程序可用性的风险,因为许多互相依赖、且紧密耦合的进程会扩大单个进程故障的影响。


微服务架构,应用程序通过多个独立运行的组件构成,每个组件作为一项服务运行。这些服务围绕业务功能进行构建,每项服务提供一项功能,彼此之间使用轻量级 API 通过明确定义的接口进行通信。由于各个服务独立运行,因此可以针对各项服务进行更新、部署和扩展,以满足对应用程序日常运行和更新的需求。


3

微服务的优势

灵活扩展

通过微服务,可以独立扩展各项服务以满足其整体应用程序功能的需求。这使团队能够适当调整基础设施需求,并在服务需求激增时保持整体应用的可用性。

轻松部署

微服务支持持续集成和持续交付,可以轻松尝试新想法,并可以在无法正常运行时回滚。由于故障成本较低,因此可以大胆试验,更轻松地更新代码,并缩短新功能的上线时间。

技术自由

微服务架构中,团队可以自由选择最佳工具来解决他们的具体问题。因此,构建微服务的团队可以为每项作业选择最佳工具。

弹性

服务独立性增加了应用程序应对故障的弹性。在整体式架构中,如果一个组件出现故障,可能导致整个应用程序无法运行。

4

焱融云前端微服务技术选型

框架选型

焱融云前端所有服务和组件均基于 NestJS 框架进行开发。NestJS 基于 Express 框架开发,相比于原生 Express 和 Koa 框架,NestJS 的优势在于: 

  1. 兼容所有 Express 中间件

  2. 完美支持 TypeScript

  3. 依赖注入以及模块化思想

  4. 大量使用装饰器和注解,能快速编写业务代码

服务发现和配置管理

我们选用 Consul 作为我们的服务注册中心,同时也作为动态配置中心。Consul 的优势:

  1. 使用 Raft 一致性算法,保证分布式集群各节点状态一致

  2. 提供服务注册,服务发现,主动服务状态检查

  3. 支持 HTTP、DNS 等协议

  4. 提供分布式一致性 KV 存储

焱融云前端微服务架构

在我们的微服务体系中,所有服务被划分了三个层次:

  1. 基础设施层,如 MySQL、Memcached、Consul 等第三方成熟组件组成,为业务提供基础服务。

  2. 业务服务层:根据业务不同拆分成不同的微服务。

  3. 接入层:对外提供服务,如网站,API 接口等。

其中,业务层的服务之间可互相调用且是无状态的;接入层服务之间不可互相调用,不包含业务代码。架构如图所示:

名称

描述

YRCloudFile Dashboard

控制台页面渲染服务

YRCloudFile Login

登录页面渲染服务

YRCloudFile Gateway

网关服务,前端所有请求经过网关进行权限认证后路由到后端服务

YRCloudFile Cluster

集群管理服务,对存储集群和 Kubernetes 集群进行管理

YRCloudFile User

用户服务

YRCloudFile Composer

聚合服务,主要对底层的接口进行二次封装和聚合

YRCloudFile Proxy

代理服务,所有底层接口调用均通过该服务进行转发,例如 YRCloudFile 存储集群,外部 Kubernetes 集群 和 YRCloudFile 监控服务。并且屏蔽底层服务 endpoint 和 鉴权的差异

配置管理

在微服务分布式环境下,一个系统拆分成很多个微服务,需要告别手工修改配置的方式,采用集中配置管理的方式提升运维效率。


配置文件主要有运行前的静态配置和运行期间的动态配置两种。静态配置在部署的时候就设置好,动态配置则是在服务运行中调整的系统变量或者业务参数。


我们采用 Consul 的 KV 存储来做动态配置中心,配置修改同步流程如下:

配置修改后,通过定时拉取或者服务监听的方式更新并缓存到本地内存中,供服务使用。

服务集成

在服务集成方面我们开发了 NodeJS 的声明式 Web Service 客户端,方便开发人员在服务之间快速集成。


服务端,我们声明一个 Restful 服务接口:

import { Controller, Get, Param } from '@nestjs/common';

@Controller('/users')
export class UserController {
    @Get('/:userId')
    getUser(@Param('userId') userId: string) {
        return {id: 1, name: 'yanrong'};
    }
}

客户端使用一个微服务接口:

import { Injectable } from '@nestjs/common';

import { Post, Loadbalanced, Param } from '@nestcloud/feign';

@Injectable()
@Loadbalanced('yrcloudfile-user-service')
export class UserClient {
    @Get('/users/:userId')
    getUser(@Param('userId') userId: string): any {
    }
}


服务质量

在服务质量方面,由于服务间调用是跨系统调用,各服务独立运行,所以必须考虑服务的伸缩性和容错性,主要包括以下几点要求:


1. 服务可以平滑的加入和移除,并且可以平滑升级

当服务启动完成的时候通过 Consul 接口注册服务,并将 /health 作为健康检查地址,Consul 每隔 5s 访问 /health,检查服务状态,如果状态是 UP,则 Consul 将服务标记为可用,否则标记为不可用。


当服务关闭的时候,先从 Consul 取消服务注册,再关闭服务。


2. 流量均匀分布在不同的实例上

微服务的基础能力之一就是支持负载均衡,而我们通常所说的负载均衡都是指服务端负载均衡,但是这里指的是客户端负载均衡,我们针对 Consul ,有针对性地开发了一个客户端负载均衡器模块,使之能很好地和我们的声明式客户端结合起来。


和服务端负载均衡不同的是,在客户端负载均衡中,所有的客户端节点都要维护自己要访问的服务端列表,而这些服务端的列表来自注册中心,通过心跳检测来保证列表中的服务节点都是可用的,从而剔除故障的服务节点。当负载均衡收到请求后会按照某种算法(随机,轮询和加权等)从可用的服务列表中取出一台服务端的地址,然后进行转发,如图所示:


3. 能支持接口降级并隔离故障节点

通过封装第三方断路器组件实现接口降级并隔离故障。根据请求的成功数、失败数、超时数、被拒数,其中当失败请求的比例高于某一值时,将会触发断路器工作,请求将会快速失败,不再向后发送,直接调用 fallback 函数返回,避免集群雪崩,之后会开放部分请求进行自我检查,如果服务恢复正常,则断路器会关闭。断路器工作流程如图所示:

5

总结

以上就是焱融云前端微服务实施的一些实践,充分满足了当前阶段开发需求。我们秉承拥抱变化的态度,对整个体系结构也在持续进行改善和优化,积极推动前端架构的演进,希望能更好地支持YRCloudFile等产品对前端的业务需求。


推荐阅读

最新全球IO500名单出炉,焱融云跻身存储厂商Top10

如何评估Kubernetes持久化存储方案


关于焱融云

焱融云是一家以软件定义存储技术为核心竞争力的高新技术企业,在分布式存储等关键技术上拥有自主知识产权,是容器存储的领导者。焱融云针对各行业业务特性,打造个性化行业解决方案,提供一站式的产品与服务。焱融云系列产品已服务于金融、政府、制造业、互联网等行业的众多客户。了解更多焱融科技信息,请访问官网www.yanrongyun.com。


推荐店铺


相关文章