如何实践Service Mesh微服务架构的基础部署

74次阅读
没有评论

共计 10939 个字符,预计需要花费 28 分钟才能阅读完成。

这篇文章将为大家详细讲解有关如何实践 Service Mesh 微服务架构的基础部署,文章内容质量较高,因此丸趣 TV 小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

当下,已经有很大一部分公司完成了单体架构向微服务架构的迁移改造,并在疲于应对大量微服务间通信问题时,开始考虑采用 Service Mesh 微服务架构作为服务与服务直接通信的透明化管理框架,以插件式的方式实现各种业务所需的高级管理功能。

而开源 PaaS Rainbond 提供了开箱即用的 Service Mesh 微服务架构,部署在 Rainbond 上的应用原生即是 Service Mesh 微服务架构应用。

接下来,我们将以 Rainbond v3.7.0 为基础平台,以开源商城项目 sockshop 为例,演示如何在源代码无入侵的情况下,将项目改造为具有服务注册与发现、分布式跟踪、A/ B 测试、灰度发布、限流、熔断、性能分析、高可用、日志分析等能力的高可靠性电商业务系统.

sockshop 是一个典型的微服务架构案例,具备用户管理、商品管理、购物车、订单流程、地址管理等完善的电商相关功能。sockshop 主要由 Spring boot、Golang、Nodejs 等多种语言开发,使用 MySQL 和 MongoDB 等多种数据库,原方案采用单机环境下的部署方式,缺乏服务治理能力和分布式能力。

sockshop 部署后的拓扑图总览

sockshop 商城首页预览图

sockshop 架构图

更多信息

源码地址

weavesocksdemo 样例

sockshop 在 Rainbond 的部署流程 STEP1 服务创建

Rainbond 支持从源码、镜像、应用市场等多种方式进行应用部署,这里我们采用 DockerCompose 配置文件的创建方式,批量创建 sockshop 中包含的所有服务。

docker-compose 创建

需要注意的是,在检测和创建过程中,获取大量镜像需要一定时间,请耐心等待完成!

docker-compose 源码: 下载

version:  2 
services:
 front-end:
 image: weaveworksdemos/front-end:0.3.12
 hostname: front-end
 restart: always
 cap_drop:
 - all
 ports:
 -  8079:8079 
 -  9001:9001 
 depends_on:
 - catalogue
 - carts
 - payment
 - user
 - orders
 edge-router:
 image: weaveworksdemos/edge-router:0.1.1
 ports:
 -  80:80 
 -  8080:8080 
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 - CHOWN
 - SETGID
 - SETUID
 - DAC_OVERRIDE
 tmpfs:
 - /var/run:rw,noexec,nosuid
 hostname: edge-router
 restart: always
 depends_on:
 - front-end
 catalogue:
 image: weaveworksdemos/catalogue:0.3.5
 hostname: catalogue
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 depends_on:
 - catalogue-db
 - zipkin
 catalogue-db:
 image: rilweic/catalog-db
 hostname: catalogue-db
 restart: always
 environment:
 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
 - MYSQL_ALLOW_EMPTY_PASSWORD=true
 - MYSQL_DATABASE=socksdb
 carts:
 image: weaveworksdemos/carts:0.4.8
 hostname: carts
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 tmpfs:
 - /tmp:rw,noexec,nosuid
 environment:
 - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false
 ports:
 -  80:80 
 depends_on:
 - carts-db
 - zipkin
 carts-db:
 image: mongo:3.4
 hostname: carts-db
 restart: always
 cap_drop:
 - all
 cap_add:
 - CHOWN
 - SETGID
 - SETUID
 tmpfs:
 - /tmp:rw,noexec,nosuid
 orders:
 image: rilweic/orders
 hostname: orders
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 tmpfs:
 - /tmp:rw,noexec,nosuid
 environment:
 - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false
 ports:
 -  8848:8848 
 depends_on:
 - orders-db
 - zipkin
 - shipping
 - carts
 - payment
 - user
 orders-db:
 image: mongo:3.4
 hostname: orders-db
 restart: always
 cap_drop:
 - all
 cap_add:
 - CHOWN
 - SETGID
 - SETUID
 tmpfs:
 - /tmp:rw,noexec,nosuid
 shipping:
 image: Rainbond/shipping:0.4.8
 hostname: shipping
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 tmpfs:
 - /tmp:rw,noexec,nosuid
 environment:
 - JAVA_OPTS=-Xms64m -Xmx128m -XX:+UseG1GC -Djava.security.egd=file:/dev/urandom -Dspring.zipkin.enabled=false
 ports:
 -  8080:8080 
 depends_on:
 - rabbitmq
 - zipkin
 queue-master:
 image: weaveworksdemos/queue-master:0.3.1
 hostname: queue-master
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 tmpfs:
 - /tmp:rw,noexec,nosuid
 depends_on:
 - rabbitmq
 rabbitmq:
 image: rabbitmq:3.6.8
 hostname: rabbitmq
 restart: always
 cap_drop:
 - all
 cap_add:
 - CHOWN
 - SETGID
 - SETUID
 - DAC_OVERRIDE
 payment:
 image: weaveworksdemos/payment:0.4.3
 hostname: payment
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 depends_on:
 - zipkin
 user:
 image: weaveworksdemos/user:0.4.4
 hostname: user
 restart: always
 cap_drop:
 - all
 cap_add:
 - NET_BIND_SERVICE
 environment:
 - MONGO_HOST=user-db:27017
 depends_on:
 - user-db
 - zipkin
 user-db:
 image: weaveworksdemos/user-db:0.4.0
 hostname: user-db
 restart: always
 cap_drop:
 - all
 cap_add:
 - CHOWN
 - SETGID
 - SETUID
 tmpfs:
 - /tmp:rw,noexec,nosuid
 zipkin:
 image: openzipkin/zipkin
 hostname: zipkin
 restart: always
 cap_drop:
 - all
 cap_add:
 - CHOWN
 - SETGID
 - SETUID
 tmpfs:
 - /tmp:rw,noexec,nosuid
 environment:
 - reschedule=on-node-failure
 ports:
 -  9411:9411

源码、应用市场等其他创建方式请参考 Rainbond 文档:创建一个应用

服务创建完成后,我们需要对批量创建的服务进行注册和对部署内存的调整,根据服务之间的调用关系,分析出哪些服务是作为内部服务供给其它服务调用、哪个服务是对用户提供访问的,并进行接下来的操作:

STEP2 服务注册

在 Rainbond 平台,我们可以通过在服务的端口页打开端口来进行服务的注册。关于服务注册的详细文档可参考 Rainbond 平台服务注册

各服务对应的端口和部署内存大小如下:

请注意,这里必须确定对每个服务组件的服务注册信息和资源分配信息设置正确。

STEP3 服务发现

sockshop 通过内部域名来进行服务调用,也就是说,在完成服务的注册后,调用服务需要发现被调用服务。

在 Rainbond 平台,我们可以通过服务依赖来实现(详情参考文档服务发现)。

各服务依赖的详情可参考上图商城在 Rainbond 平台的概览

如果使用上面的 docker-compose 文件创建应用,无需手动添加依赖,在创建应用时系统已根据 docker-compose 文件内容自动配置了服务发现

STEP4 服务 Mesh 治理

在 sockshop 案例中,front-end 为 nodejs 项目,该服务会调用其他 5 个服务来获取数据,如图所示:

front-end 在调用其他服务时,会使用域名 + 端口的调用方式(该项目所有调用均为此方式)如 front-end 调用 orders 时,内部访问地址为 http://orders/xxx.

Rainbond 平台在服务进行调用时,会默认将顶级域名解析到 127.0.0.1,如果调用的服务对应的端口都不冲突没有任何问题,而在此案例中,front-end 调用的其他 5 个服务的端口均为 80。因此这里需要第一个治理功能:端口复用。

在不安装 7 层网络治理插件的情况下,平台默认使用 4 层网络治理插件,无法提供端口复用的机制。因此,我们为服务 front-end orders 分别安装网络治理插件。

STEP5 安装网络治理插件

在我的插件中选择服务网络治理插件进行安装。

特别注意

工作在 7 层的 Mesh 插件默认会占用 80 端口,因此需要安装此插件的服务本身不能占用 80 端口。因此我们推荐服务尽量监听非 80 端口。插件内存使用量需要根据流量大小调节。

STEP6 应用安装插件

在应用详情页面选择插件标签,然后开通指定的插件。

Rainbond 默认提供的服务网络治理插件是基于 Envoy 制作,Rainbond ServiceMesh 架构为 Envoy 提供了标准的运行支持。安装插件后需重启应用生效。

STEP7 Mesh 插件配置

配置域名路由,实现端口复用。为了 front-end 服务能根据代码已有的域名调用选择对应的服务提供方,我们需要根据其调用的域名来进行配置。将应用进行依赖后,服务网络治理插件能够自动识别出其依赖的应用。我们只需在插件的配置的域名项中进行域名配置即可。如下图:

详细配置

更新插件相关的配置后进行保存并重启相关应用即可。此处暂时先只用到基于域名的路由配置,关于网络治理插件的更对详情可参考 服务路由,灰度发布,A/B 测试

STEP8 服务性能分析

微服务是一个分布式的架构模式,它一直以来都会有一些自身的问题。当一个应用的运行状态出现异常时,对于运维和开发人员来说,即时发现应用的状态异常并解决是非常有必要的。我们可以通过监控手段对服务进行衡量,或者做一个数据支撑。

Rainbond 平台为我们提供了服务监控与性能监控,可以简单直观的了解服务当前的状态和信息。

目前支持 HTTP 与 mysql 协议的应用

安装插件

应用安装插件

同上应用网络治理插件安装

安装完成效果图

安装完成性能分析插件,可以在安装该插件的应用概览页面查看应用的平均响应时间和吞吐率。

除此以外,我们也可以在该组应用的组概览中看到应用的访问情况。

案例上的性能测试工具服务

sockshop 商城案例自带性能测试的服务,但是与该项目不是持续运行,而是运行一次后程序便会退出。在这里,我们根据源码进行了一点小的修改。主要是将程序变为不退出运行。源码地址

我们可以通过源码方式来创建项目——

创建完成后,我们需要在 sockshop 商城创建一个账号为 user、密码为 password 的用户,负载测试需要使用该用户名来和密码进行模拟请求。

完成以上步骤,接下来我们对 sockshop 的分布式跟踪进行处理。

微服务分布式跟踪 zipkin 简介

随着业务越来越复杂,系统也随之进行各种拆分,特别是随着微服务架构和容器技术的兴起,看似简单的一个应用,后台可能有几十个甚至几百个服务在支撑;一个前端的请求可能需要多次的服务调用最后才能完成;当请求变慢或者不可用时,我们无法得知是哪个后台服务引起的,这时就需要解决如何快速定位服务故障点,Zipkin 分布式跟踪系统就能很好的解决这样的问题。

Zipkin 分布式跟踪系统;它可以帮助收集时间数据,解决在 microservice 架构下的延迟问题;它管理这些数据的收集和查找;Zipkin 的设计是基于谷歌的 Google Dapper 论文。每个应用程序向 Zipkin 报告定时数据,Zipkin UI 呈现了一个依赖图表来展示多少跟踪请求经过了每个应用程序;如果想解决延迟问题,可以过滤或者排序所有的跟踪请求,并且可以查看每个跟踪请求占总跟踪时间的百分比。

zipkin 架构

装配了 zipkin 跟踪器的服务可以将服务的每次调用(可以是 http 或者 rpc 或数据库调用等)延时通过 Transport(目前有 4 总共发送方式,http,kafka,scribe,rabbitmq)发送给 zipkin 服务。

zipkin 主要包含 4 个模块

collector:接收或收集各应用传输的数据。storage:存储接受或收集过来的数据,当前支持 Memory,MySQL,Cassandra,ElasticSearch 等,默认存储在内存中。API(Query):负责查询 Storage 中存储的数据,提供简单的 JSON API 获取数据,主要提供给 web UI 使用 Web:提供简单的 web 界面

zipkin 服务追踪流程

从上图可以简单概括为一次请求调用,zipkin 会在请求中加入跟踪的头部信息和相应的注释,并记录调用的时间并将数据返回给 zipkin 的收集器 collector。

zipkin 安装

在 Rinbond 平台,我们可以直接通过 docker run 方式运行 zipkin.

注意开启对外访问端口和调整应用内存大小

此时创建的 zipkin 的数据存在于内存中,服务关闭或重启数据都会丢失。因此在生产环境中,我们需要将数据存入存储。

zipkin 支持 MySQL,Cassandra,ElasticSearch 三种存储。我们以 Mysql 为例说明。目前 zipkin 至此的 mysql 版本为 5.6 和 5.7 版本。

在 Rainbond 平台应用市场创建版本为 5.7 的 mysql 应用,如图。

创建完成 mysql 以后,我们需要进行数据库的初始化操作,zipkin 需要使用到 zipkin 数据和相应的表结构,需要我们自行创建。

在应用的详情页面,我们可以选择管理容器进入到容器进行操作,如图。

进入容器后,使用命令登录 mysql 命令行。

mysql -uusername -ppassword

mysql 的用户和密码可以在应用的依赖里看到 如图

进入 mysql 命令行后,创建数据库 zipkin

CREATE DATABASE zipkin ;

创建 zipkin 相关的表:下载

CREATE TABLE IF NOT EXISTS zipkin_spans (
 `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT  If non zero, this means the trace uses 128 bit traceIds instead of 64 bit ,
 `trace_id` BIGINT NOT NULL,
 `id` BIGINT NOT NULL,
 `name` VARCHAR(255) NOT NULL,
 `parent_id` BIGINT,
 `debug` BIT(1),
 `start_ts` BIGINT COMMENT  Span.timestamp(): epoch micros used for endTs query and to implement TTL ,
 `duration` BIGINT COMMENT  Span.duration(): micros used for minDuration and maxDuration query) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT  ignore insert on duplicate 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT  for joining with zipkin_annotations 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT  for getTracesByIds 
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT  for getTraces and getSpanNames 
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT  for getTraces ordering and range 
CREATE TABLE IF NOT EXISTS zipkin_annotations (
 `trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT  If non zero, this means the trace uses 128 bit traceIds instead of 64 bit ,
 `trace_id` BIGINT NOT NULL COMMENT  coincides with zipkin_spans.trace_id ,
 `span_id` BIGINT NOT NULL COMMENT  coincides with zipkin_spans.id ,
 `a_key` VARCHAR(255) NOT NULL COMMENT  BinaryAnnotation.key or Annotation.value if type == -1 ,
 `a_value` BLOB COMMENT  BinaryAnnotation.value(), which must be smaller than 64KB ,
 `a_type` INT NOT NULL COMMENT  BinaryAnnotation.type() or -1 if Annotation ,
 `a_timestamp` BIGINT COMMENT  Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp ,
 `endpoint_ipv4` INT COMMENT  Null when Binary/Annotation.endpoint is null ,
 `endpoint_ipv6` BINARY(16) COMMENT  Null when Binary/Annotation.endpoint is null, or no IPv6 address ,
 `endpoint_port` SMALLINT COMMENT  Null when Binary/Annotation.endpoint is null ,
 `endpoint_service_name` VARCHAR(255) COMMENT  Null when Binary/Annotation.endpoint is null 
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT  Ignore insert on duplicate 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT  for joining with zipkin_spans 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT  for getTraces/ByIds 
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT  for getTraces and getServiceNames 
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT  for getTraces 
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT  for getTraces 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT  for dependencies job 
CREATE TABLE IF NOT EXISTS zipkin_dependencies (
 `day` DATE NOT NULL,
 `parent` VARCHAR(255) NOT NULL,
 `child` VARCHAR(255) NOT NULL,
 `call_count` BIGINT,
 `error_count` BIGINT
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

在 zipkin 服务中添加环境变量 STORAGE_TYPE 为 mysql, 此变量标志 zipkin 使用的存储方式。可选择值为 mysql,elasticsearch、cassandra

将 zipkin 与 mysql 建立依赖关系后,zipkin 服务便安装完成。

zipkin 内部会默认调用环境变量 MYSQL_USER(用户名),MYSQL_PASS(密码),MYSQL_HOST(连接地址),MYSQL_PORT(端口)。刚好与 Rainbond 平台默认设置的变量一致,所以无需做任何修改。

其他服务如果连接的变量与 Rainbond 平台默认提供的不一致,我们可以在应用的设置也添加相应的环境变量来达到访问的目的。

sockshop 中的 zipkin 案例

sockshop 案例集成了 zipkin 做分布式跟踪。集成的组件为 users、carts、orders、payment、catalogue、shipping。

其中 carts、orders、shipping 为 spring-boot 项目,只需在设置中将环境变量 JAVA_OPTS 的 -Dspring.zipkin.enabled 改为 true 即可。

如图

payment、catalogue、users 为 golang 项目,项目已在内部集成了 zipkin 组件,我们需要添加环境变量 ZIPKIN 为 http://zipkin:9411/api/v1/spans 来明确服务调用 zipkin 的地址。

如图

设置完成后,可以做直接访问 zipkin 应用对外提供的访问地址。访问详情如图

我们可以在该图中查看各个服务调用的延时详情。

至此,我们已经完成了基础部署,可以看到完整的业务拓扑图,sockshop 也已经可以正常工作了。

关于如何实践 Service Mesh 微服务架构的基础部署就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计10939字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)