内容不断完善中,访问 文档查看最新更新
当下,已经有很大一部分公司完成了单体架构向微服务架构的迁移改造,并在疲于应对大量微服务间通讯问题时,开始考虑采用Service Mesh微服务架构做为服务与服务直接通讯的透明化管理框架,以插件式的方式实现各类业务所需的高级管理功能。html
而开源PaaS Rainbond提供了开箱即用的Service Mesh微服务架构,部署在Rainbond上的应用原生便是Service Mesh微服务架构应用。前端
接下来,咱们将以 Rainbond v3.7.0 为基础平台,以开源商城项目 sockshop 为例,演示如何在源代码无入侵的状况下,将项目改造为具备服务注册与发现
、分布式跟踪
、A/B测试
、灰度发布
、限流
、熔断
、 性能分析
、高可用
、日志分析
等能力的高可靠性电商业务系统。java
一键部署Rainbond请查看 快速开始。sockshop是一个典型的微服务架构案例,具有用户管理、商品管理、购物车、订单流程、地址管理等完善的电商相关功能。sockshop主要由
Spring boot
、Golang
、Nodejs
等多种语言开发,使用MySQL
和MongoDB
等多种数据库,原方案采用单机环境下的部署方式,缺少服务治理能力和分布式能力。node
sockshop部署后的拓扑图总览mysql
sockshop商城首页预览图git
sockshop架构图github
更多信息golang
Rainbond支持从源码、镜像、应用市场等多种方式进行应用部署,这里咱们采用DockerCompose配置文件
的建立方式,批量建立 sockshop 中包含的全部服务。web
须要注意的是,在检测和建立过程当中,获取大量镜像须要必定时间,请耐心等待完成!
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文档: 建立一个应用
服务建立完成后,咱们须要对批量建立的服务进行注册和对部署内存的调整,根据服务之间的调用关系,分析出哪些服务是做为内部服务供给其它服务调用、哪一个服务是对用户提供访问的,并进行接下来的操做:spring
在 Rainbond 平台,咱们能够经过在服务的端口页打开端口来进行服务的注册。关于服务注册的详细文档可参考Rainbond 平台服务注册
各服务对应的端口和部署内存大小以下:
请注意,这里必须肯定对每一个服务组件的服务注册信息和资源分配信息设置正确。
sockshop经过内部域名来进行服务调用,也就是说,在完成服务的注册后,调用服务须要发现被调用服务。
在 Rainbond 平台,咱们能够经过服务依赖来实现(详情参考文档服务发现)。
各服务依赖的详情可参考上图商城在Rainbond平台的概览
若是使用上面的 docker-compose 文件建立应用,无需手动添加依赖,在建立应用时系统已根据 docker-compose 文件内容自动配置了服务发现
在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
分别安装网络治理插件。
在个人插件
中选择服务网络治理插件
进行安装。
特别注意
工做在 7 层的 Mesh 插件默认会占用 80 端口,所以须要安装此插件的服务自己不能占用 80 端口。所以咱们推荐服务尽可能监听非 80 端口。插件内存使用量须要根据流量大小调节。
在应用详情页面选择插件
标签,而后开通指定的插件。
Rainbond默认提供的服务网络治理插件是基于 Envoy制做,Rainbond ServiceMesh架构为Envoy提供了标准的运行支持。安装插件后需重启应用生效。
配置域名路由,实现端口复用。为了front-end
服务能根据代码已有的域名调用选择对应的服务提供方,咱们须要根据其调用的域名来进行配置。将应用进行依赖后,服务网络治理插件
可以自动识别出其依赖的应用。咱们只需在插件的配置的域名项中进行域名配置便可。以下图:
详细配置
更新插件相关的配置后进行保存并重启相关应用便可。此处暂时先只用到基于域名的路由配置,关于网络治理插件的更对详情可参考 服务路由,灰度发布,A/B 测试
微服务是一个分布式的架构模式,它一直以来都会有一些自身的问题。当一个应用的运行状态出现异常时,对于运维和开发人员来讲,即时发现应用的状态异常并解决是很是有必要的。咱们能够经过监控手段对服务进行衡量,或者作一个数据支撑。
Rainbond 平台为咱们提供了服务监控与性能监控,能够简单直观的了解服务当前的状态和信息。
目前支持 HTTP 与 mysql 协议的应用
同上应用网络治理插件安装
安装完成性能分析插件,能够在安装该插件的应用概览页面查看应用的平均响应时间
和吞吐率
。
除此之外,咱们也能够在该组应用的组概览中看到应用的访问状况。
sockshop 商城案例自带性能测试的服务,可是与该项目不是持续运行,而是运行一次后程序便会退出。在这里,咱们根据源码进行了一点小的修改。主要是将程序变为不退出运行。源码地址
咱们能够经过源码方式来建立项目——
建立完成后,咱们须要在 sockshop 商城建立一个帐号为user
、密码为password
的用户,负载测试须要使用该用户名来和密码进行模拟请求。
完成以上步骤,接下来咱们对sockshop的分布式跟踪进行处理。
随着业务愈来愈复杂,系统也随之进行各类拆分,特别是随着微服务架构和容器技术的兴起,看似简单的一个应用,后台可能有几十个甚至几百个服务在支撑;一个前端的请求可能须要屡次的服务调用最后才能完成;当请求变慢或者不可用时,咱们没法得知是哪一个后台服务引发的,这时就须要解决如何快速定位服务故障点,Zipkin 分布式跟踪系统就能很好的解决这样的问题。
Zipkin 分布式跟踪系统;它能够帮助收集时间数据,解决在 microservice 架构下的延迟问题;它管理这些数据的收集和查找;Zipkin 的设计是基于谷歌的 Google Dapper 论文。
每一个应用程序向 Zipkin 报告定时数据,Zipkin UI 呈现了一个依赖图表来展现多少跟踪请求通过了每一个应用程序;若是想解决延迟问题,能够过滤或者排序全部的跟踪请求,而且能够查看每一个跟踪请求占总跟踪时间的百分比。
装配了 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 的收集器 collector。
在 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
作分布式跟踪。集成的组件为 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也已经能够正常工做了。绝不夸张得说,项目与实际电商系统也只是差一些业务逻辑了:)
接下来的进阶部分,咱们会完成每个服务的水平伸缩
、持续集成与部署
、数据备份
、灰度发布
等,敬请关注。
Rainbond是一款以应用为中心的开源PaaS,由好雨基于Docker、Kubernetes等容器技术自主研发,可做为公有云或私有云环境下的应用交付平台、DevOps平台、自动化运维平台和行业云平台,或做为企业级的混合云多云管理工具、Kubernetes容器管理工具或Service Mesh微服务架构治理工具。