微信群分享第一期 微服务 by 许晓斌

公开课 · hkliya · 于 发布 · 最后由 hkliya回复 · 2604 次阅读
1

日期:2015-12-30
主题:Microservices - A way to scale
简介:介绍微服务原理,能解决什么问题,以及基于 SpringBoot 的实现。
讲师许晓斌在 AliExpress 人事 Java 中间件开发和研发效率改进等工作。他是《Maven 实战》作者,《Maven 权威指南》译者,并合译有《Cucumber:行为驱动开发指南》,曾经负责维护 Maven 中央仓库,参与开发 Maven 仓库管理软件。

今天的主题叫做「Microservices - A way to scale」,翻译成中文就是微服务,主要是讲微服务是怎样帮你解决可伸缩性的问题。
那什么是可伸缩性呢?大家可能会有很多种想法,包括横向扩展,纵向扩展等等,实际上关于 Scalability 有很多种定义,除了上述之外,它还涉及怎么增加业务逻辑,怎么增加开发人员,以及怎么增加更多数据。


在这个图里面大家可以看到,技术人员最熟悉的基本上就是怎么样当用户量访问来更多的时候,我们怎么去支撑这个用户,典型的做法就是横向水平扩展来支撑。
传统的方法像换更好的机器,更大的数据库,这种叫做纵向扩展。
但实际上除此之外我们还关心我们的业务逻辑,越来越复杂的时候,像淘宝,天猫它们的业务越来越复杂,我们怎么能够保证我们开发效率不会变低,这也是一种扩展。
还有当开发者越来越多的时候,那我们的经理怎么去考虑人员怎么分工协作,这也是一种扩展。
最后当然也包括当数据越来越大的时候,MySQL 支持不住的时候,怎么处理这个问题。


关于扩展实际上业界有一种理论叫做 Scale Qube,大家可以看这本叫「THE ART OF SCALABILITY」,英文有第二版,中文可能只有第一版,核心理论是说扩展是分三个维度的,X 就是机器的水平扩展,Y 维度已经处理更多的业务逻辑,Z 维度就是怎么处理更多的数据。这个理论跟微服务什么关系呢?其实在今天的大型互联网公司,X 的问题已经解决了,Z 的问题呢今天我不讲,因为并不是我擅长的地方。我想重点关注的是 Y 这个维度,怎样把业务功能进行切分,通过把技术落从而保证开发效率,协作效率。


我们来看一下这张图,这里一个典型的一体化架构,也就是说当在开始创业的时候,当你第一天做一个软件的时候,你基本上会把所有的业务功能放到一个可运行包里面,以 Java 为例就是 WAR 包, 放在 Tomcat,JBoss,Jetty 里去运行,在这个图里可以看到它是一个类似滴滴,Uber 类似的打车应用,它包括司机管理,乘客管理,怎么发消息,怎么计费各种各样的系统,当你人很少的时候你会这么做,这是合理的,这个叫 Monolithic Application,翻译成巨型应用。

然而怎样去解释什么是一个「巨型应用」呢?相信如果你没有新手写过代码,没有在代码泥潭里接触过遗留系统的话,很难有直观体会,它恶心的地方就是牵一发而动全身,改一个业务逻辑一倒一大片,这种东西给人的第一感觉就是「一大坨」。就像下面这个图一样:

面对这样一种情况,我们接下来会怎么办呢?实际上大家都会想到去拆分,拆分的话,因为我比较熟悉 Maven,大家一开始会通过 Java 自带的 Package 来拆分,或者通过 Maven 的一个 module 来拆分,最终打在一起还是一个 War 包,它最终还是在一个 ClassLoader 里面,这就带来一个问题,它表面上它有拆分,但物理上它是没有隔离的,虽然看起来代码是独立了,但运行起来会互窜,因为开发人员在压力大的时候是不会考虑那么多模块的东西的,它会带来各种错综复杂的依赖关系,我以我们就希望换一种运行时的拆分方式。


上面这个图就是微服务的方式,把代码依赖变成了运行时的依赖。每一个业务模块都是独立部署的一个系统,它们可以用不同的语言来开发,比如 Java,Ruby,Python,Golang等。
最重要的它们之间一定要有一个统一的通讯协议 - Restful API。像阿里、Google、Facebook 都有自己的开源的通讯协议,不管你用哪一个,必须得有一个。

拆分成微服务的好处主要有几点:

  • 每个模块都是一个简单的系统
  • 可以独立测试和部署,只要保证 API 稳定
  • 独立 Scale,在压力大的模块进行横向扩展就可以了
  • 性能优化,需要优化的点很少了
  • 独立选择自己的技术 Java,Scala,Golang等,保证 API 稳定的情况下,可以随时调整内部代码,随时用不同技术重写
  • 康威定律,组织结构决定代码结构。拆分成微服务后各个团队之间可以相对独立地工作,可以在异地,对沟通的要求没有那么高


既然拆分有这些好处,那下一个问题是,怎么拆?
传统的架构拆分方式有按技术拆,表现层,Service 层,Dao 层等。但实践证明,技术的变化高于领域的变化。从业务领域的维度来拆分会更加合理,因为每一个业务领域其实变化是很小的。比如打车,订餐,电子商务,它们的业务本身并不会有太大的变化。
所以现在有一种方式叫做「领域驱动设计」,大家可以看 Martin Fowler 的文章


关于领域驱动设计,只要读懂这三本书就差不多了,推荐先读第三本。
个人认为它是一个经典的理论,起码十年、二十年内不会衰老。


前边理论讲的比较多,接下来会讲一些具体的实践,我以 Java 为例。
第一,各个服务间的依赖如何管理?因为我们要避免重复代码。
上图的意思是各系统间只有 Service API 的依赖,不会依赖代码。
最多可能有一个 SDK 的依赖。


第二,一定要有一个一致的协议。就像人与人之间要讲普通话,如果都用自己的方言,就没办法愉快地玩耍了。


在微服务架构下面,还有一个重要的概念是:Service discovery。
各个服务可能都会有多个实例,它们之间不应该直接依赖。
我们会有一个注册中心,每个服务都会进行注册,其它依赖它的服务会去注册中心询问,并通过 Load balance 来决定由哪个实例提供服务。


推荐大家看一下这个开源的工具,用它可以快速搭建一个注册中心。


对于每一个系统,它们在不同的环境下有不同的配置,这就要求我们将系统进行标准化,把所有变化的东西放到一个统一的配置文件里。
这样就可以在不同的环境下加载不同的配置文件。

下面讲讲最有可能成为 Java 世界微服务框架的: Spring Boot。


它有很多特点。首先,它通过 main 函数启动应用。其次,它通过服务注册的方式使用第三方服务。


Microservices 和 SOA 有什么区别呢?
最大的不同是 Microservices 会重视 DevOps,会在开发中就会嵌入一些运维特性。
举个例子,这是我自己写的扩展,只要加入这个依赖,就能看到应用的所有依赖关系。当你进行安全分析,架构升级的时候就非常有用。


原来的 Monalithic 架构,服务挂掉的时候,就整个挂掉了。
而拆分成微服务后,比如京东或 Amazon,它的广告服务挂掉了,并不会影响搜索服务。
就是说微服务设计合理的时候,可以增强我们系统的可用性。
当然它也不是没有成本的,你得分析它们的依赖,哪些是强依赖,哪些不是。把弱的依赖进行自己的降值,当这个服务出问题的时候,不会拖垮你的进程。


这个开源框架会帮你把弱依赖隔离起来,把同步调用变成异步调用。有点像家里的断路器,当某个电器坏掉的时候,会把相应的电路断开,保证不会引起火灾。


系统越来越多的时候,从本机调用变成远程调用时,性能怎么保证?
一种思路是把同步调用变成异步调用,从串行调用变成并行调用,从而极大提高性能。


这是一个代码的例子,这是一个叫 RxJava 的框架,它帮我们简单异步代码的调用。

前面都是一些技术相关的东西,但如果你的「文化」没跟上的话,也是搞不定的。
这就是 DevOps。开发人员要承担更多的运维职责,当一个服务挂掉的时候,应该首先要找开发人员。


软件产品的生命周期中,开发周期通常远远比运周期短。
所以希望开发人员能考虑运维特性,比如你没做过运维可能就不会在代码中写日志,但如果你自己运维自己的系统,半夜系统挂了,你爬起来一看没有日志,不知道怎么定位问题,下次你再写代码的时候就会考虑哪些地方要写日志了。

You build it, you run it.
这种做法有利于提高开发人员的运维意识,在开发过程中考虑运维特性,从而降低运维成本。


几十分钟的分享远远讲不清微服务的全部知识,推荐大家去学习这些工具和资料。

差不多就讲这么多,大家可以提一些问题。


Q1:不知道微服务的核心是否就是这个精神?
1、化整为零;
2、各自为战、各自负责;
3、标准统一(通讯协议统一、代码结构一致、发布构建一致、监控一致)。

Q2:最近在看spring data rest, 这个内置的restful api 直接暴露entity,但是没有我们的业务逻辑,这个东西怎么用
A2:@老猫 的问题,我是这样理解的,你的 entity 的所有内容,是不是包含了很多 client 不应该知道的信息?你是不是经常要修改这个 entity。 如果两个答案都是 no ,就没问题。

Q3:像一个服务的领域模型可以对其他服务暴露吗?比如用户统一认证服务的用户信息实体
A3:不能。

Q4:按功能划分微服务,会导致每个微服务都有相同的模型类定义吧?或者能不能再细讲一下按边界上下文划分和按模块划分的区别。
A4:微服务是根据领域来划分的,领域是业务概念,模块是技术概念,我们应该让技术结构契合业务结构

@D调的暖冬 你的问题和 @老猫 的问题是类似的,在不同上下文,同一个实体的意义是不一样的,例如“书”这个实体,商铺的意义是价格和封面,对物流的意义是重量和尺寸,你是否暴露,需要看用户的上下文。

Q5:你讲的微服务,更多是按领域拆分成微服务。想了解一下,在你具体的项目中,项目一般多大时候适合引入微服务概念
A5: 这个没有参考答案的,就我们团队来说,平均每个人维护2-3个服务
NO,不同服务的数据不能共享,我暴露的API,不该有我的数据库信息,明天也许我把 mysql 换成 hbase 了呢

Q6:还有一个问题,不同的限界上下文中的同名领域对象,对应同一张表吗?譬如,库存系统里的书的实体对象,电商系统里的书的实体对象?
Q6:库存系统里的书的实体对象,电商系统里的书的实体对象,表结构也是完全不同的,不应该公用一个表。

本文由志愿者根据群语音分享整理,如觉得有价值,可酌情打赏。


「软件匠艺社区」旨在传播匠艺精神,通过分享好的「工作方式」和「习惯」以帮助程序员更加快乐高效地编程。
共收到 4 条回复
96
jerry · #1 ·

许老师,你好,不同限界上下文中的同名领域对象分存不同的表,那么这两个领域对象如何关联,或者需要有相互冗余的属性吗

96
jerry · #2 ·

可不可以理解DDD中的限界上下文就是我们划分微服务的边界!

96
lancer · #3 ·

<dependency>
<groupId>com.aliexpress.boot</groupId>
<artifactId>spring-boot-starter-maven</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
这个maven的pom 已经不存在了吗,下载不下来哦

1
hkliya · #4 ·

#3楼 @lancer 有可能是公司内部的 Repository。

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。