分类目录归档:集群云平台

业务模型、数据模型、面向对象模型

1、首先提一个问题,什么是模型?
模型这个词频繁出现在我们平时的工作中、生活中、新闻里,但什么是模型呢,不同的学科有不同的定义。
在这里我不想列举学术上的定义,只谈一下我自己的理解:模型是为了模拟、演示、深入分析被研究对象而建造的任何形式的作品。
根据这一理解,我们想一下:
小时候折的纸飞机是不是模型呢?是的。
售楼处摆放的楼盘模型是不是模型呢?是的。
军事演练时使用的沙盘是不是模型呢?是的。
建筑物的设计蓝图是不是模型呢?是的。
所以说模型的概念没有什么神秘的,我们每个人日常工作生活中都会建造模型,都会使用模型。小到儿童玩具,大到三峡工程的模拟水纹实验,模型无处不在。建造模型的目的可以是简化现实世界、预研未来的产品、预测未知数据。

2、模型的表现形式又是什么样的呢?
我觉得模型的表现形式和风格没有限制也不应该有限制,所以图像、图画、声音、实物、表格、文字、数学公式都可以使用。能更好的达到建模目的就好。可以类比画家作画,不同的画家画同一幅风景可以使用古典派画法、抽象派画法、印象派画法、现代派画法,使用的材料可以是水、墨、粉、纸、布、玻璃等等。

3、下面解释一下我们工作中可能用到的模型

(1)业务模型:也称企业模型,它为企业提供一个框架结构,以确保企业的应用系统与企业经常改进的业务流程紧密匹配。可以说,也就是说业务建模主要是从业务的角度而非技术角度对企业进行建模。典型的建模方法包括Zachman框架、ARIS HOUSE模型等,业务模型一般包括下面一些视图:
• 组织视图:组织结构的静态模型。包括:层次组织结构的人员(people not human)资源,生产资源(比如,设备,运输等)以及计算机、通信网络结构等。
• 数据视图:业务信息的静态模型。包括:数据模型,知识结构,信息载体,技术术语和数据库模型等。
• 功能视图:业务流程任务的静态模型。包括:功能层次,业务对象,支持系统和应用软件等。
• 控制(业务)视图:动态模型,展示流程运转情况,并能够将业务流程与流程相关的资源、数据以及功能等联系起来。包括:事件驱动过程链、信息流、物流、通信图、产品定义、价值增值图等。
业务模型的画法可以用任何编辑工具如Visio、word完成,当然目前PowerDesigner、Erwin等专业工具也支持业务模型。

(2)数据模型
数据模型是对企业或信息系统种的数据特征的抽象,随着数据库技术的大量使用,主要指数据库模型。
数据模型所描述的内容包括三个部分:数据结构、作用于数据上的操作、数据约束。
1)数据结构:数据模型中的数据结构主要描述数据的类型、内容、性质以及数据间的联系等。数据结构是数据模型的基础,数据操作和约束都建立在数据结构上。不同的数据结构具有不同的操作和约束。
2)数据操作:数据模型中数据操作主要描述在相应的数据结构上的操作类型和操作方式。
3)数据约束:数据模型中的数据约束主要描述数据结构内数据间的语法、词义联系、他们之间的制约和依存关系,以及数据动态变化的规则,以保证数据的正确、有效和相容。
数据模型按不同的应用层次分成三种类型:分别是概念数据模型、逻辑数据模型、物理数据模型。
1)概念数据模型(Conceptual Data Model):简称概念模型,主要用来描述世界的概念化结构,与具体的数据库系统无关。概念数据模型必须换成逻辑或物理数据模型,才能在数据库系统中实现。概念数据模型中最常用的是E-R模型。
2)逻辑数据模型(Logical Data Model):简称数据模型,这是从数据库所看到的模型,是具体的数据库管理系统所支持的数据模型,如网状数据模型(Network Data Model)、层次数据模型(Hierarchical Data Model)等等。此模型既要面向用户,又要面向系统。
3)物理数据模型(Physical Data Model):简称物理模型,是面向计算机物理表示的模型,描述了数据在储存介质上的组织结构。物理数据模型的设计要考虑数据管理的性能问题,它不但与具体的数据库系统有关,而且还与操作系统和硬件有关。每一种逻辑数据模型在实现时都有起对应的物理数据模型。
可以利用PowerDesigner、Erwin、Oracle Data builder、Infosphere Data Architect、Rose等建模工具建立数据模型。

(3)面向对象模型
这个应该是软件开发者喜欢的模型,使用面向对象分析(OOA)和面向对象设计(OOD)过程中所建立模型,包括类图、对象图、状态图以及与之相关的活动图、顺序图、组件图等,可以利用UML建模工具,如Rose、Infosphere DataArchitect等工具以及软件
集成开发工具(Eclipse、Netbeans)建立面向对象模型。当然有些数据建模工具也支持面向对象模型。

(4)数据挖掘模型
数据挖掘模型的概念虽然重要,但没有比较权威的解释,我说一下自己的理解,使用数据挖掘算法建立的,描述数据之间的关系模型就叫数据挖掘模型。
数据挖掘模型的表现形式多种多样,跟数据挖掘算法有关,也跟我们要进行的后续操作有关。比如表现学生身高体重关系的函数(可以是直线、曲线、二次函数、多项式函数)是一个数据挖掘模型;表现超市商品关联关系的关联规则集合也是一个数据挖掘模型;表现银行客户分类情况的决策树也是一个数据挖掘模型。

Spring cloud 整体框架

研究了一段时间 spring boot 了准备向 spirng cloud 进发,公司架构和项目也全面拥抱了 Spring Cloud。在使用了一段时间后发现 Spring Cloud 从技术架构上降低了对大型系统构建的要求,使我们以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台,但 Spring Cloud 也不是没有缺点,小型独立的项目不适合使用,另外对分布式事物的支持暂时也没有。

Spring Cloud 是什么鬼?

Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。

微服务是可以独立部署、水平扩展、独立访问(或者有独立的数据库)的服务单元,springcloud 就是这些微服务的大管家,采用了微服务这种架构之后,项目的数量会非常多,springcloud 做为大管家需要管理好这些微服务,自然需要很多小弟来帮忙。

主要的小弟有:Spring Cloud Config、Spring Cloud Netflix(Eureka、Hystrix、Zuul、Archaius...)、Spring Cloud Bus、Spring Cloud for Cloud Foundry、Spring Cloud Cluster、Spring Cloud Consul、Spring Cloud Security、Spring Cloud Sleuth、Spring Cloud Data Flow、Spring Cloud Stream、Spring Cloud Task、Spring Cloud Zookeeper、Spring Cloud Connectors、Spring Cloud Starters、Spring Cloud CLI,每个小弟身怀独门绝技武功高强下面来做一一介绍。

核心成员

Spring Cloud Netflix

这可是个大 boss,地位仅次于老大,老大各项服务依赖与它,与各种 Netflix OSS 组件集成,组成微服务的核心,它的小弟主要有 Eureka, Hystrix, Zuul, Archaius... 太多了

Netflix Eureka

服务中心,云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。这个可是 springcloud 最牛鼻的小弟,服务中心,任何小弟需要其它小弟支持什么都需要从这里来拿,同样的你有什么独门武功的都赶紧过报道,方便以后其它小弟来调用;它的好处是你不需要直接找各种什么小弟支持,只需要到服务中心来领取,也不需要知道提供支持的其它小弟在哪里,还是几个小弟来支持的,反正拿来用就行,服务中心来保证稳定性和质量。

Netflix Hystrix

熔断器,容错管理工具,旨在通过熔断机制控制服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力。比如突然某个小弟生病了,但是你还需要它的支持,然后调用之后它半天没有响应,你却不知道,一直在等等这个响应;有可能别的小弟也正在调用你的武功绝技,那么当请求多之后,就会发生严重的阻塞影响老大的整体计划。这个时候 Hystrix 就派上用场了,当 Hystrix 发现某个小弟不在状态不稳定立马马上让它下线,让其它小弟来顶上来,或者给你说不用等了这个小弟今天肯定不行,该干嘛赶紧干嘛去别在这排队了。

Netflix Zuul

Zuul 是在云平台上提供动态路由, 监控, 弹性, 安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。当其它门派来找大哥办事的时候一定要先经过 zuul, 看下有没有带刀子什么的给拦截回去,或者是需要找那个小弟的直接给带过去。

Netflix Archaius

配置管理 API,包含一系列配置管理 API,提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。可以实现动态获取配置,原理是每隔 60s(默认,可配置)从配置源读取一次内容,这样修改了配置文件后不需要重启服务就可以使修改后的内容生效,前提使用 archaius 的 API 来读取。

Spring Cloud Config

俗称的配置中心,配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储、Git 以及 Subversion。就是以后大家武器、枪火什么的东西都集中放到一起,别随便自己带,方便以后统一管理、升级装备。

Spring Cloud Bus

事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与 Spring Cloud Config 联合实现热部署。相当于水浒传中日行八百里的神行太保戴宗,确保各个小弟之间消息保持畅通。

Spring Cloud for Cloud Foundry

Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题

其实就是与 CloudFoundry 进行集成的一套解决方案,抱了 Cloud Foundry 的大腿。

Spring Cloud Cluster

Spring Cloud Cluster 将取代 Spring Integration。提供在分布式系统中的集群所需要的基础功能支持,如:选举、集群的状态一致性、全局锁、tokens 等常见状态模式的抽象和实现。

如果把不同的帮派组织成统一的整体,Spring Cloud Cluster 已经帮你提供了很多方便组织成统一的工具。

Spring Cloud Consul

Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件, 由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License 2.0 的协议进行开源. Consul 支持健康检查, 并允许 HTTP 和 DNS 协议调用 API 存储键值对.

Spring Cloud Consul 封装了 Consul 操作,consul 是一个服务发现与配置工具,与 Docker 容器可以无缝集成。

其它小弟

Spring Cloud Security

基于 spring security 的安全工具包,为你的应用程序添加安全控制。这个小弟很牛鼻专门负责整个帮派的安全问题,设置不同的门派访问特定的资源,不能把秘籍葵花宝典泄漏了。

Spring Cloud Sleuth

日志收集工具包,封装了 Dapper 和 log-based 追踪以及 Zipkin 和 HTrace 操作,为 SpringCloud 应用实现了一种分布式追踪解决方案。

Spring Cloud Data Flow

  • Data flow 是一个用于开发和执行大范围数据处理其模式包括 ETL,批量运算和持续运算的统一编程模型和托管服务。
  • 对于在现代运行环境中可组合的微服务程序来说,Spring Cloud data flow 是一个原生云可编配的服务。使用 Spring Cloud data flow,开发者可以为像数据抽取,实时分析,和数据导入 / 导出这种常见用例创建和编配数据通道 (data pipelines)。
  • Spring Cloud data flow 是基于原生云对 spring XD 的重新设计,该项目目标是简化大数据应用的开发。Spring XD 的流处理和批处理模块的重构分别是基于 spring boot 的 stream 和 task/batch 的微服务程序。这些程序现在都是自动部署单元而且他们原生的支持像 Cloud Foundry、Apache YARN、Apache Mesos 和 Kubernetes 等现代运行环境。
  • Spring Cloud data flow 为基于微服务的分布式流处理和批处理数据通道提供了一系列模型和最佳实践。

Spring Cloud Stream

Spring Cloud Stream 是创建消息驱动微服务应用的框架。Spring Cloud Stream 是基于 spring boot 创建,用来建立单独的/工业级 spring 应用,使用 spring integration 提供与消息代理之间的连接。数据流操作开发包,封装了与 Redis,Rabbit、Kafka 等发送接收消息。

一个业务会牵扯到多个任务,任务之间是通过事件触发的,这就是 Spring Cloud stream 要干的事了

Spring Cloud Task

Spring Cloud Task 主要解决短命微服务的任务管理,任务调度的工作,比如说某些定时任务晚上就跑一次,或者某项数据分析临时就跑几次。

Spring Cloud Zookeeper

ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 Hbase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper 的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

操作 Zookeeper 的工具包,用于使用 zookeeper 方式的服务发现和配置管理,抱了 Zookeeper 的大腿。

Spring Cloud Connectors

Spring Cloud Connectors 简化了连接到服务的过程和从云平台获取操作的过程,有很强的扩展性,可以利用 Spring Cloud Connectors 来构建你自己的云平台。

便于云端应用程序在各种 PaaS 平台连接到后端,如:数据库和消息代理服务。

Spring Cloud Starters

Spring Boot 式的启动项目,为 Spring Cloud 提供开箱即用的依赖管理。

Spring Cloud CLI

基于 Spring Boot CLI,可以让你以命令行方式快速建立云组件。

和 Spring boot 是什么关系

Spring boot 是 Spring 的一套快速配置脚手架,可以基于 spring boot 快速开发单个微服务,Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具;Spring boot 专注于快速、方便集成的单个个体,Spring Cloud 是关注全局的服务治理框架;spring boot 使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud 很大的一部分是基于 Spring boot 来实现, 可以不基于 Spring boot 吗?不可以。

Spring boot 可以离开 Spring Cloud 独立使用开发项目,但是 Spring Cloud 离不开 Spring boot,属于依赖的关系。

spring -> spring booot > spring cloud 这样的关系。

Spring Cloud 的优势

微服务的框架那么多比如:dubbo、Kubernetes,为什么就要使用 Spring Cloud 的呢?

  • 产出于 spring 大家族,spring 在企业级开发框架中无人能敌,来头很大,可以保证后续的更新、完善。比如 dubbo 现在就差不多死了
  • 有 spring Boot 这个独立干将可以省很多事,大大小小的活 spring boot 都搞的挺不错。
  • 作为一个微服务治理的大家伙,考虑的很全面,几乎服务治理的方方面面都考虑到了,方便开发开箱即用。
  • Spring Cloud 活跃度很高,教程很丰富,遇到问题很容易找到解决方案
  • 轻轻松松几行代码就完成了熔断、均衡负责、服务中心的各种平台功能

Spring Cloud 也有一个缺点,只能使用 Java 开发, 不适合小型独立的项目。

Spring Cloud Config

现今这个时候,微服务大行其道,互联网应用遍地都是,随便开发个什么应用首要考虑的都是要可伸缩,扩展性要好。当我们的后台服务一点点增多,各个服务的配置也越来越多,随之而来的就是一个配置管理问题,各自管各自的开发时没什么问题,到了线上之后管理就会很头疼,到了要大规模更新就更烦了。我们的后台服务就是如此,各种语言开发的都有,在慢慢的迭代过程的我们发现配置中心是一个比较好的解决方案,作为 Spring 的拥趸我们自然就看中了 Spring Cloud Config。

一般服务器的应用都有以下几种类型,
图片

其中当属业务部分最多也最繁杂。
当应用越来越庞大和复杂时,单机就肯定不能满足需求了,然后就要考虑分布式了,接下可能会应用不同的语言来开发应用。

比如 nginx 毫无疑问的是用的最多的反向代理组件,使用 OpenResty 便要用到 lua,再比如前端要 seo ,一个解决办法就是使用 nodejs,到了后端分布式,那就更繁多了,可能会需要把业务一个个拆分成不同的服务单独运行…

图片

然后就发现散落一地的配置文件:***properties***、***yml***、***json*** …

为了解决这个问题,我们采取了这么一种模式,通过 etcd 我们的项目就是这样,来收集所有的配置,然后统一的写到一个文件中去,任何应用都来访问这一个文件来找到自己的配置并应用。
图片

这很好的解决了配置散落的问题,可以集中管理了,但是又存在另一个问题,各种类型的配置在一个文件里看起来好乱,而且在初始化时必须要完成这个文件才能启动应用。

所以下一个解决方案便想到用一个配置中心来解决问题。

图片

Spring Cloud Config 项目

  • 提供 服务端客户端 支持
  • 集中式 管理分布式环境下的应用配置
  • 基于 Spring 环境,无缝 与 Spring 应用集成
  • 可用于 任何 语言开发的程序
  • 默认实现基于 git 仓库,可以进行 版本管理
  • 可替换 自定义实现

Spring Cloud Config Server 作为配置中心服务端

  • 拉取配置时更新 git 仓库副本,保证是最新结果
  • 支持数据结构丰富,yml, json, properties 等
  • 配合 eureke 可实现服务发现,配合 cloud bus 可实现配置推送更新
  • 配置存储基于 git 仓库,可进行版本管理
  • 简单可靠,有丰富的配套方案

Spring Cloud Config Client 默认客户端实现

  • SpringBoot 项目不需要改动任何代码,加入一个启动配置文件指明使用 ConfigServer 上哪个配置文件即可

简单使用示例

新建一个 git 仓库,添加一个配置文件。例如想要一个 billing的服务,性质是开发,运行环境是测试环境。

那么就新建一个 testing 的分支,然后提交一个 billing-dev.properties 的文件

devMode = true
spring.application.name = billing
spring.jdbc.host = localhost
spring.jdbc.port = 3306
spring.jdbc.user = root
spring.jdbc.password = 123qwe
loging.file = demo

然后新建一个标准 maven 项目

图片

ConfigServer.java
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServer.class, args);
    }
}
application.yml
server:
  port: 8888
spring:
  cloud:
    config:
      server:
        git:
          uri:https://git.coding.net/tiangao/demo-config-server.git
          clone-on-start: true
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-demo</artifactId>
        <groupId>xyz.stg.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>config-server</artifactId>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.1.RELEASE</version>
    </parent>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>1.2.1.RELEASE</version>
        </dependency>
    </dependencies>
</project>

好了,配置中心已经可以启动了,配最简单的可以用浏览器来访问。
图片

想要 json 格式的怎么办呢?
图片

还有 yml, properties
图片

图片

OK, 就是这样简单。不过直接就能通过 url 得到,是不是有点不安全,这也不难,加上依赖。
java <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency>

然后在 application.yml 配置用户名和密码,user 便是用户名。
security:
  user:
    password: db1ab002-1fba-476d-a421-22113355

再访问就能看到如下的效果

图片

这是 ConfigSever 默认实现的基本的 HttpBasic 的认证。

服务端好了现在来看看 SpringBoot 客户端
只需要添加一个启动配置文件:
java cloud: config: uri: http://127.0.0.1:8888 profile: dev label: testing name: billing password: db1ab002-1fba-476d-a421-22113355 username: user

当启动时看到下面标示的内容是即表示加载成功。
图片

简单示例就这样,下面便是 Config 的使用示意图。
图片

呐,就是这样,所有的配置都通过仓库来管理,应用启动时访问配置中心能拿到自己的配置就OK,再接下来就是各自的事情了。

仓库也不仅仅只能用 git, 还有 svn 和本地目录可以选择

  • svn://\${user.home}/config-repo
  • file://${user.home}/config-repo

从简单的示例里可以看出,我们只要提交一种格式的配置文件,通过不同的方式访问即可得到不同格式的配置文件,这在ConfigServer里是如何实现的呢?

先看一共有多少种访问方式

  • /{name}/{profiles:.*[^-].*}
  • /{name}/{profiles}/{label:.*}
  • /{name}-{profiles}.properties
  • /{label}/{name}
  • /{profiles}.properties
  • /{name}-{profiles}.json
  • /{label}/{name}-{profiles}.json

然后就能发现有这么一个类,里面有各种资源类型的转换操作。EnvironmentController 的所有方法如下所示:

图片

原来内部只存在一种资源抽象,所有的资源对象都是由这种类型转换而来。
图片

一个应用的配置只需要应用名、属性和标签就可以定位到。嗯,原来这么简单,那 EnvironmentReposiroty 又是哪里实现呢?
图片

findOne 方式在 AbstractScmEnvironmentRepository 中可以找到。
java @Override public synchronized Environment findOne(String application, String profile, String label) { NativeEnvironmentRepository delegate = new NativeEnvironmentRepository( getEnvironment()); Locations locations = getLocations(application, profile, label); delegate.setSearchLocations(locations.getLocations()); Environment result = delegate.findOne(application, profile, ""); result.setVersion(locations.getVersion()); result.setLabel(label); return this.cleaner.clean(result, getWorkingDirectory().toURI().toString(), getUri()); }
这其中又由 SearcPathLocator 接口的 getLocations() 来实际加载内容,这个方法就由具体的实现类来完成。

Spring Cloud Config Server 内部除了 JGitEnvironmentRepository 实现外还有另外三种实现。

  • SvnKitEnvironmentRepository
  • NativeEnvironmentRepository
  • MultipleJGitEnvironmentRepository

见名知其意,分别是 svn 本地目录以及多 git 仓库的实现。

来到客户端这边,SpringBoot

项目只需要加载依赖就可以使用到远程配置,现有项目迁移过去也不用改动任何代码,感觉好神奇。
达到这样的效果依赖于 springMVC 的抽象以及 springboot 的自动配置类加载。
“`java
@Configuration
public class ConfigClientAutoConfiguration {

@Bean
public ConfigClientProperties configClientProperties(
       Environment environment,
       ApplicationContext context) {...}
...
@Bean
public ConfigServerHealthIndicator configServerHealthIndicator(
       ConfigServicePropertySourceLocator locator,
       ConfigClientHealthProperties properties, Environment environment) {
    return new ConfigServerHealthIndicator(locator, environment, properties);
}
...

}
**ConfigClientAutoConfiguration** 这个是 ConfigClient 的自动配置类,加载时触发新建一个 ConfigServicePropertySourceLocator 的 bean, java
@Order (0)
public class ConfigServicePropertySourceLocator
implements PropertySourceLocator {

private RestTemplate restTemplate;
private ConfigClientProperties defaultProperties;
...
@Override
@Retryable(interceptor = "configServerRetryInterceptor")
public org.springframework.core.env.PropertySource<?> locate(
       org.springframework.core.env.Environment environment) {
    ...
       // Try all the labels until one works
       for (String label : labels) {
         Environment result = getRemoteEnvironment(restTemplate,
              properties, label.trim(), state);
              ...

}
“`

然后在 ApplicationContextInitializer 的 initialize 方法中被调用 locate 方法从 ConfigServer 拉取配置文件,注入到 ConfigurableEnvironment 中,

@Configuration
@EnableConfigurationProperties(PropertySourceBootstrapProperties.class)
public class PropertySourceBootstrapConfiguration implements
        ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    ...
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ...
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        for (PropertySourceLocator locator : this.propertySourceLocators) {
            PropertySource<?> source = null;
            source = locator.locate(environment);
            if (source == null) {
                continue;
            }
            ...
        }
        ...
    }
}

接着才是应用的初始化过程。
从这个过程可以看到,其他任何应用需要使用 ConfigServer 时只需要在应用初始化之前通过 http 拉取到配置文件即可。

了解了大致原理,便可以看到集中式管理的优点。

图片

  • 没有记忆负担:大家都使用一个仓库保存所有配置文件,方便查看。
  • 降低冲突沟通成本:开发新功能是凡是有配置变动均向仓库的提交,在合并后其他人碰到配置问题时也不用到处找人问,看看仓库历史就知道什么发生了变化。
  • 方便测试:测试环境下,测试人员也不用老是问开发环境配置的问题了,所有配置一目了然,更改配置也有记录,有问题向开发反馈也能帮助快速定位问题范围。
  • 方便管理: 在模拟环境和生产环境下,通过分支保护和权限管理管理线上配置文件,由运维人员来管理。

微服务开发的软件过程

在介绍这个过程之前,先强调一个观点:

  • 人管代码,代码管机器
  • 人管代码,代码管机器
  • 人管代码,代码管机器

 

一、软件过程

Jira原是设计来进行Bug跟踪的系统,后来系统功能逐步完善后,被广泛适用于软件过程管理。Jira优势在于简单,好用。 这里就不介绍Jira的具体使用。 使用Jira进行软件项目管理,首先需要定义任务的处理流程。 以下是一个参考流程:

01.png

在这个流程中,需要区分两个概念:任务和子任务。 每个任务对应一个完整的业务需求,比如对账、对接工行借记卡、获取个人优惠券列表接口。这些业务需求每个都是可以独立测试的。子任务设置相对比较简单,每个子任务对应这在本次任务执行中需要修改的开发项目。 比如对接工行借记卡,会涉及到:

  1. 支付网关项目调整;
  2. 支付路由项目中增加路由选项;
  3. 工行借记卡通道对接。

三个项目的修改,那会对应在这个任务下建立三个子任务。

  • 任务是用来追踪项目过程的,这是项目经理和产品经理关注的层次。
  • 子任务是用来支持开发自动化的,这是开发人员关注的层次。

这样,针对任务和子任务,会设置不同的属性:

02.png

 

1.1 需求管理

Jira也是一个不错的需求管理工具。产品经理可以通过Jira来执行需求管理,相对开发来说,需求管理流程会比较简单,一般是开发需求、审核需求、关闭需求三个环节即可。 需要注意的地方是:

  1. 需求管理流程需要和开发流程分离,毕竟这是不同的团队做的事情。
  2. 开发任务可以和需求任务相关联。Jira通过复制任务来提供这个支持。

一个需求任务可以对应多个开发任务,这在实际操作中是很常见的:

  1. 为了满足上线要求,一个需求任务会被拆分成多个开发任务,先完成核心功能开发并上线,再完成外围功能开发。这两次独立上线的工作,会被拆分为2个或者更多的开发任务;
  2. 如果对不同平台,比如Android、IOS、PCweb有不同的上线时间要求和技术需求,也需要将当前需求按照目标平台来拆分成开发任务。

 

1.2 创建任务

如上所述,开发任务的来源有两个:

  • 需求任务,即对应产品经理提的需求;
  • 优化任务,这一般是开发团队内部进行重构或者性能优化来提的开发任务。

那任务的粒度如何把握? 每个开发任务是一个完整的需求,是可以独立执行测试和验证的。 每个任务开发周期控制在1个月以内。

1.3 创建子任务

在接收到开发任务后,开发人员需要对系统实现进行设计和分解,确定需要新开发的内容以及需要改进的工作。 在微服务架构中,一次任务开发会涉及到多个系统的变更。这样就需要为每个系统建立一个独立的子任务,以后,我们将按照这个子任务的设置来驱动开发流程。 每个子任务开发周期尽量限制2天以内,不能超过一周。

1.4 启动主任务开发

主任务启动开发流程比较简单,主要是邮件通知到各相关人员,可以启动该任务。

1.5 启动子任务开发

子任务的启动和执行,是整个流程的核心工作。

03.png

这里如果是使用git/gitlab来做版本控制,整个流程的要点在于:

  1. 如果需要新建项目来开发,则由开发人员填写新项目的名称、类型(Web、RPC、工具类等),在Git上创建一个项目框架,包含必要的基础文件;
  2. 邮件通知开发人员需要下载的项目代码库地址;
  3. 开发人员签出代码到本地,执行开发工作;
  4. 开发人员随时可以签入代码到服务器上,发出Merge Request;
  5. GitLab在接受签入前,执行静态代码检查。静态代码检查的工具有FindBugs、PMD、Sonar等。 开发人员在开发时也必须自我进行静态检查,这里执行检查是避免开发人员漏查;
  6. 执行单元测试;
  7. 通知相关人员进行代码审核;
  8. 执行代码审核;
  9. 符合审核条件(如至少有2个人同意),审核通过, 代码被自动合并到主干版本。
  10. 通知子任务可以提测。 当然,是否提测,是由开发人员来决定。

 

1.6 子任务和任务提测

子任务开发完成后,即可提测。子任务提测时,将触发Jenkins进行测试环境部署。

测试有两种方式:自动测试和人工测试。尽量采用自动测试,使得开发人员能够及时发现问题。

所有子任务完成后,主任务可以提测。主任务提测后,如果是人工测试,则测试人员介入开始执行测试任务;如果是自动测试,则开始运行集成测试脚本。

04.png

测试通过后, 既可以准备上线。

1.7 预部署和全部署

一般上线会分为两步,预部署和全部署。预部署的目的是先验证系统在线上环境运行是否正常,减少回滚成本。特别是在部署服务器特别多的情况下,先部署1-2台机器,可以在线上验证本次上线是否可以。 验证通过后,既可以执行全部署。

注意,预部署和全部署都是针对子任务而言。

05.png

少数公司会要求上线前进行审批,但这样做是不利于流程自动化的。 一天几十次上线,谁能知道这是不是可以上。 但有一点很重要,系统上线前,必须通知到相关的使用方。如果出现问题,使用方可以尽快知悉。

二、项目文件结构

开发参考目录结构:

06.jpg

从这个目录里面我们可以看到,和项目相关的部署用脚本,需要由项目开发人员自己来维护,用以保证部署工作能够自动执行。包括验证项目部署成功的脚本。

验证项目是否部署成功,一种方式是在日志中打桩,grep到这个日志,即意味着系统成功启动;一种方式是调用接口来验证是否成功。

部署目录参考:

07.png

总之,微服务项目的管理核心理念在于“自动化”,消除人为因素。人管代码,代码管机器,最终目标是要实现自动上线。 消除人工测试,取代以自动化测试;消除人工验证,取代以自动验证;消除人工部署,取代以自动化部署。 这样,再多的项目,也能够很好的进行管理。

消息最终一致性处理分布式事务的理解

前言

消息最终一致性是用于处理分布式事务解决方案之一,其中主要保证的目的是为了消息的可靠性,最终一致性,而可靠消息并不可靠,由于其它未知原因(如网络、宕机等),依然可能会造成消息的中断,发不出去的情况,就需要人工介入处理或者有一定的处理机制,所以在一定角度上来说,可靠消息在某一程度上,只是最大保障了消息的最终一致性,以为称“消息最终一致性”会更为合理。

以下为分析消息最终一致性,其中按的思路为ACID,即事务的主要特性。

传统事务处理

举例一个场景,以CURD事务举例,一个事务中有添加、删除、修改三个操作,这里我们且称添加为A,删除为B,修改为C,设置A,B,C为同步操作,则一个事务表示为(序号表示执行顺序):

在这一事务中,可以用传统的处理方案处理,保证事务的一致性。

分布式事务处理

由于业务的发展,业务独立在一定程度上更好有效的解决了耦合,达到可扩展,组件化,高性能等,在服务化之后,我们继续使用上面的A、B、C来说明,假设已经分为A服务,B服务,C服务,实际的业务场景则为:

为了保证ACID,在A完成之后,一定要操作B服务,在B完成之后,一定要操作C,但实际中,网络、应用稳定性、异步调用等的不确定性,容易造成事务不统一,如A完成,在调用B时,由于网络或者其它原因,B并没有完成业务操作,同样,C 也没有完成,如下图:

以上的情况,这个事务并不统一,服务是独立的,要实现A回滚的操作,需要做更多的额外工作来处理。所以,为了确定B一定执行,在已完成的事务(如A)需要重复去调用或者有一种验证机制去确定B一定执行。

以上只是一种情况,可能出现多种情况。总之,打破了事务的ACID原则,而我们要做的就是尽最大努力确保这个ACID原则,即事务性。消息最终一致性的方案,为保持这个原则,做了一个保障方案。

消息最终一致性方案

注:可靠消息是一种基于消息中间件的包装,确保消息一致性的服务或者组件。

此方案中引入了可靠消息做为媒介,如图(序号表示执行顺序):

在A完成之后,会一定去调用B服务,B服务一定会去调用C服务,确保一定会完成ACID的操作。

如果说事务失败,即在A失败,这部分可以在A服务内自己控制事务,包括异常处理等,就不会去调用B,此时,整个事务就不会进行。

回到之前的事务讨论

前面提过,添加为A,删除为B,修改为C,其中A,B成功,C操作失败,要不要做A、B回滚的处理?这个之前很多同事都有提问到。事务具有ACID特性,即整个事务来说,对消费方来说是透明的,要么成功,要么失败,A、B属于事务中的一部分,不会有回滚的操作,因为它会确保C一定去执行。

如果需要添加回滚,在程序上处理可实现,考虑到开发成本上,不太建议。如有更好的办法,也希望学习。

可靠消息对业务有一定的入侵性,并不能完全解耦,如在做幂等处理时,需要跟具体业务结合判断。

总结

针对以上可靠消息的特性及使用场景,在划分服务颗粒度上需按实际业务场景划分,以最简单的成本,解决最实际的问题。