请选择 进入手机版 | 继续访问电脑版

ITIL,DevOps,ITSS,ITSM,IT运维管理-ITIL先锋论坛

 找回密码
 立即注册

扫描二维码登录本站

QQ登录

只需一步,快速开始

查看: 1753|回复: 0

一个运维老鸟经验中的DevOps和微服务

[复制链接]
发表于 2018-10-7 09:59:20 | 显示全部楼层 |阅读模式
本帖最后由 adminlily 于 2018-10-7 10:02 编辑
5 ?2 @+ G3 ~! L. V
& W; D$ Y' b3 j单体应用 VS 微服务
. \- p* ?$ C  c* w9 h4 h& V
让我们先从运维的真实场景出发,来看一下单体应用存在的问题。这里先分享两个真实的生产案例:

" x% J9 x2 M; t" \  C" S

! B; a% v+ o) h8 r! |# \( Z
案例一是某核心业务系统,所有的业务逻辑代码都打包在同一个WAR包里部署,运行了将近几百个同构的实例在虚拟机上。某次因为应用包中的一个功能模块出现异常,导致实例挂起,整个应用都不能用了。因为它是一个单体,所以尽管有几百个实例在运行,但是这几百个实例都是异常的。业务系统是经过多年建设起来的,排查起来也很复杂,最终整个业务系统瘫痪了近六个小时才恢复。同时,因为有多个前台系统也调用了这个后台系统,导致所有要调用的前台系统也都全部瘫痪了。设想一下,如果这个场景使用的是微服务架构,每个微服务都是独立部署的,那影响的也只是有异常的微服务和其他相关联的服务,而不会导致整个业务系统都不能使用。

, Q- b0 V8 S+ c% S$ k: Y# t
+ z% h$ G7 v( V( ~: N

! d, i1 ~  h8 s+ Z6 I( c
另外的案例是一个客服系统,这个系统有一个特点,早上八点的时候会有大量的客服登录。这个登录点是全天中业务并发量最高的时间点,登录时系统需要读取一些客户信息,加载到内存。后来一到早上客服登录时,系统经常出现内存溢出,进而导致整个客服系统都用不了。当时系统应对这种场景做架构冗余时,并不是根据单独的业务按需进行扩展,而是按照单体应用的长板进行冗余。比如说早上八点并发量最高,单点登陆模块业务需求非常大,为适应这个时间点这个模块的业务压力,系统会由原来的八个实例扩展到十六个实例,这时的扩展是基于整个系统的。但事实上,在其他时间段,这个单点登陆模块基本不使用,且监控的数据显示,主机的资源使用情况基本在40%以下,造成了很大的资源浪费。所以在一个大型的业务系统中,每个服务的并发压力不一样,如果都按压力最大的模块进行整体扩展,就会造成资源的浪费,而在微服务的模式下,每个服务都是按自身压力进行扩展的,就可以有效的提高资源利用率。
! W: g/ g/ |. T; ]. [7 C1 L
9 N+ X! D. \8 Q! B) B8 M0 \

1 }1 ]8 W, Q' a$ b
从这两个例子中,我们可以看出,单体应用存在如下两个问题:一个是横向扩展时需要整体扩展,资源分配最大化,不能按需扩展和分配资源;另一个是如果单体中有一个业务模块出现问题,就会是全局性灾难,因为所有业务跑在同一个实例中,发生异常时不具备故障隔离性,会影响整个业务系统,整个入口都会存在问题。

+ z( m  n; M5 e
: m% L1 W$ o$ F8 I$ M3 d5 F# e

& m8 \( L. z, T; ]; e* r2 T
因此,我们当时考虑把综合业务拆分,进行更好的资源分配和故障隔离。
1.png
图 1
5 ^# @5 h& q$ w  @
( ~, t0 ~0 \& U& N: y" ?
% i2 @2 ^3 m* \& w# X- r: |
下面我们看一下单体应用和微服务的对比,如图1所示。这里从微服务带来的好处和额外的复杂性来讲。

8 D( {0 b. [$ Q) y; e4 j

8 y8 |$ A9 P2 P
) [: \+ a% g* s6 b+ G6 H$ B
微服务的好处:
1 E+ ^: @6 m* A  F! Y
% A( [0 m8 o* o. r/ S

' Z* F0 {6 X/ h4 l! _, F
1.局部修改,局部更新。当运维对一个单体应用进行修改时,可能要先把整个包给停了,然后再去修改,而微服务只需逐步修改和更新即可;' N& x7 w/ {- T) y) v& P7 R' U0 U' K
& X# k' [7 U6 r, [3 @
3 f$ ]; ?3 N1 m  T
2.故障隔离,非全局。单体应用是跑在一起,所以只要一个模块有问题,其他就都会有问题。而微服务的故障隔离性、业务可持续性都非常高;5 E7 Z* z/ U/ y1 X
) S$ y; g- n3 l6 ?

9 |4 }8 @& X4 C& D* I' c
3.资源利用率高。单体应用的资源利用率低,而使用微服务,可以按需分配资源,资源利用率会非常高。
6 {, K; Q  n. f) _$ u) y2 i* o
  k3 `2 h" ], Z7 G0 [& p, {' e

+ n2 J' u% o  ?3 }. Z6 e
微服务带来的复杂性:

* j- B0 c% u, |1 n) W$ E$ [! u
# ^( k: A, {4 Y9 N9 q1 p! S
; K! Z3 ~# v" K. R
微服务间较强的依赖关系管理。以前单体应用是跑在一起,无依赖关系管理,如果拆成微服务依赖关系该如何处理,比如说某个微服务更新了会不会对整个系统造成影响。

* G$ }- U) `& X8 ?1 M5 v
' c  Y: c$ c& b" H8 i3 q6 p
. W; M4 [2 U; C/ }) I: F# s
部署复杂。单体应用是集中式的,就一个单体跑在一起,部署和管理的时候非常简单,而微服务是一个网状分布的,有很多服务需要维护和管理,对它进行部署和维护的时候则比较复杂。
6 L0 v, H) i# F8 H6 `

/ Q2 v% L6 A: o$ t! `- A; _) W# L& J6 k% K. h2 B( l3 }
如何更好地利用资源。单体应用在资源分配时是整体分配,扩展时也是整体扩展,数量可控,而在使用微服务的情况下,需要为每一个微服务按需分配资源,那么该为每个微服务分配多少资源,启动多少个实例呢,这也是非常大的问题。
  w5 p% a) A. k! N* ~

$ t4 [3 }/ L' c* X% H0 P! Q$ _7 X  k) {7 N5 [8 L( t8 P2 ?
监控管理难。以前我们用Java,就是一个单体应用,监控和管理非常简单,因为它就是一个1,但是使用微服务它就是N个,监控管理变得非常复杂。另外是微服务之间还有一个协作的问题。

1 {: H( z: Y7 l( x' J8 J
- {1 r7 U/ K+ `" o! T! K

$ K! A. }" q! [: I4 K, G, w3 s* q基于容器构建微服务架构
7 `4 B  K1 d1 b$ R9 ?2 l- Y

7 a$ }* o1 Y% d5 T: `/ K
使用微服务,第一步是要构建一个一体化的ITILxf.com" target="_blank" class="relatedlink">DevOps平台,如图2。如果你不使用DevOps做微服务的话,整个环境会变得非常的乱、非常的糟糕。它会给你的整个开发、测试和运维增加很多成本,所以第一步我们是提高DevOps的能力,能够把它的开发、部署和维护进行很完美的结合,才可以说我们真正能够享受到微服务架构的福利。
1.png
图 2
4 O7 N+ Q4 `) r& C( q

* ?* @! Y8 s& N3 ]4 a8 ^6 X
% {4 Y2 j' e. G3 c+ m
容器的出现给微服务提供了一个完美的环境,因为我们可以:

, R$ h6 Z* B# K9 ?. y' X2 w

- J, Z9 `" H0 H
1.基于容器做标准化构建和持续集成、持续交付等。9 S9 ~& |7 J- S+ Q

. ~# M) m' x. b* e- ?/ `
% u( z5 g9 F$ r! M

+ h  O. r. h% P
2.基于标准工具对部署在微服务里面的容器做服务发现和管理。
3 d! W; [) q- \+ m$ A" w" N' f& o: T7 _9 l3 U

1 f! P1 X/ |1 ?; x9 n* b) i$ k5 [
3.透过容器的编排工具对容器进行自动化的伸缩管理、自动化的运维管理。% Q0 I5 [- b( j8 H( G3 u

7 U9 [' L# H) s0 y* `9 v/ D+ v$ e: P) N8 E: Q7 C5 F
所以说,容器的出现和微服务的发展是非常相关的,它们共同发展,形成了一个非常好的生态圈。下面详细讲下DevOps的各个模块。

- d# I0 A  {3 s# k
. C% `& _% t; a8 i; s) e
4 Y. x4 n6 \, Q  ~
持续集成与持续发布
$ z( T, i2 D3 Z% ^+ Z9 \/ M; e
* _5 G9 E# o4 L. x( k5 O

! p. {7 P" E# w9 z9 X" D
持续集成的关键是完全的自动化,读取源代码、编译、连接、测试,整个创建过程自动完成。我们来看一下如何用Docker、Maven、Jenkins完成持续集成。
1.png
图 3
9 O5 d& S6 Y8 b# N) w* |

/ m% s" M5 m: R2 B6 n) {0 P  H7 ?

& o5 G0 o; R9 x4 o. s
如图3所示。首先是开发人员把程序代码更新后上传到Git,然后其他的事情都将由Jenkins自动完成。那Jenkins这边发生什么了呢?Git在接收到用户更新的代码后,会把消息和任务传递给Jenkins,然后Jenkins会自动构建一个任务,下载Maven相关的软件包。下载完成后,就开始利用Maven Build新的项目包,然后重建Maven容器,构建新的Image并Push到Docker私有库中。然后删除正在运行的Docker容器,再基于新的镜像重新把Docker容器拉起来,自动完成集成测试。整个过程都是自动的,这样就简化了原本复杂的集成工作,一天可以集成一次,甚至是多次。

$ S$ V. z( }) }2 M% E! Z; M* {

/ z5 @$ W0 ?6 y( G+ I/ Q, k- I, w+ o6 h7 I# x* |) v6 }
依赖关系管理

$ ]3 L0 o/ r/ ~3 s# c6 N* I

, X& c2 t* V* `/ n2 w3 ]
& M+ U. F/ w! m; y  X
前面讲到,当微服务多的时候,依赖关系管理也会比较复杂,现在比较流行的是基于消费者驱动的契约管理。在开发一个微服务时,并不需要另外一个微服务开发完后再做集成测试,而是使用契约的方式。契约通过提供标准化的输出,说明请求的内容、回复的内容、交换的数据,开发微服务时符合契约里这些条件即可。
1.png
图 4
9 @' ?+ P8 a1 ~8 p

* o5 q1 g  [7 z1 R+ y
1 m0 G! ~8 H, m1 o- v
如图4所示,微服务A通过模拟与微服务B的交互,将交互内容保存在契约里,而微服务B开发时需满足这个契约里的条件,这样就不需要A和B完全完成了才能做测试。当很多微服务与微服务B关联时,每个微服务通过契约告诉微服务B请求的内容、正确的响应和请示的数据,然后微服务B通过契约模拟这个测试过程,而其他的微服务则需要满足这个契约。当微服务进行升级时,也是要先满足所有契约,这样微服务间的关系就可以更好的进行管理。

: R3 P  S, U8 x7 A2 {

, Y4 ~4 b6 H1 ]3 m
: q: i0 _1 f/ ?  b$ a* q
典型的微服务架构

0 y) }" K; h; o9 E
; D' z' N  J# X3 v
1 n4 n! r' f$ X& B% v/ N# h0 D
图5是典型的微服务架构模型,采用的是Kubernetes框架。把业务系统拆分成很多的微服务,然后通过服务注册的方式去发现整个生产环境中所有的微服务,通过负载均衡组件进行分发,再用服务调度去进行弹性伸缩,而客户端则只需要通过API网关访问微服务。除此之外,微服务的运维也很重要。开发是实现功能性需求,而在实际的生产环境中,我们更应该关心非功能性的需求。因为即使功能实现了,跑到生产上却不能用,功能开发再完美也没有用。
1.png
图 5
; m; z9 j5 W0 W
服务发现与负载均衡

* m' P1 H' [' Q" |
+ i, v) L8 c8 n  F
2 f; \) ^) s' }2 `# ]' @5 q# t
服务发现与负载均衡使用的是Kubernetes的架构,如图6。每一个微服务都有一个IP和PORT,当调用一个微服务时,只需要知道微服务的IP,而不需要关心容器的IP,也不需要关心pod的IP。虽然每个pod也有IP和PORT,但当一个pod启动时,就会把pod的IP和PORT注册到服务发现模块,再进行负载均衡。所以当多个pod启动时,对于用户来说还是只需要知道service的IP,不需要知道后端启动了多少pod、IP是多少,这就解决了网络的问题。
1.png
图 6
+ B5 s. u9 Q7 i- q. H7 o. G; K
日志集中式管理
1.png
图 7
" ?0 f) D# J. y1 }3 @2 o, {2 o8 r0 P

2 c( C1 i9 t7 S$ d* z

1 R, Y! M4 O8 a* C
以前单体的情况下,单体的数量少,日志数量也相应比较少,而在微服务架构下,因为拆分成了很多微服务,相应的日志会非常多且散,这种情况下需要对日志进行集中的管理。我们可以在每个容器里跑日志监控,把所有日志采集进行集中管理和存储,再通过简易操作的UI界面进行索引和查询。
, z* W; d, f  j! g' ~$ A

& o7 c6 A% n4 R, K8 Y; a- O7 \& X0 ?2 U: k
监控管理
1.png
图 8
6 q" _5 v$ ?( l' N$ e; b1 v- m

* |; \0 z2 R% h7 x) Z  s6 O
/ {7 K" ?$ U3 i/ _1 ~
然后就是监控方面了。微服务的量是非常大的,这个时候如何有效地监控是极其重要的。我们刚开始做监控的时候,有几百个实例对同一个关键字进行监控,出故障后会收到几百条短信,因为每一个实例都会发一条短信。这时候严重的致命性的报警就会看不到,因为手机信息已经爆炸了,所以要对报警进行分级,精确告警,最重要的是尽量让故障在发生之前灭亡。因此,在做监控时要对故障提前进行判断,先自动化处理,再看是否需要人为处理,然后通过人为的干预,有效的把故障在发生之前进行灭亡。

$ G4 v5 y8 y+ w! f& u1 l

  _- W4 ^1 ?( G) U; L4 Z" ]) {4 v; [. J& f
但如果所有事情都靠人为去处理,这个量也是非常大的,所以对故障进行自动化隔离和自动化处理也很重要。我们在写自动化故障处理的时候研究了很多常见的故障,写了很多算法去判断,精确到所有的故障,这样基本的常见的故障和可以策划处理的故障都可以自动化处理掉。之前没有出现的故障,出现之后我们就会去研究是否可以做成自动化处理。如果生产上做的不精确,对生产会是灾难性的,所以我们对生产的故障自动化处理也做了很多研究。
. W  e! n) U1 [! z% e
( N- n; c. G$ f7 q% z- S* _

9 q8 n8 Y$ C: |+ H3 T七牛的微服务架构实践
' E3 i7 r. n  x: _; }# T. s

1 ^0 c% Z' E# U0 e  }
前面讲了很多运维,下面来了解一下Docker和微服务在七牛云中的实践,以七牛的文件处理服务架构演变为例。
9 \$ ?- C9 a8 D# u+ Y

7 a( Y9 T# N, _2 l( H+ f  B  _
( r$ z1 R5 Z; j
文件处理服务是指,用户把原图存到七牛的云存储之后,然后使用文件处理服务,就可以把它变成自己想要的服务,比如剪裁、缩放和旋转等,如图9。
1.png
图 9
' R( c4 f, E- g0 U5 S  T  P
- U+ F1 [9 o" M) T- I6 V9 d: l* B
: s; z7 Y1 g; `5 h1 `3 R
过去为适应不同的场景,用户需要针对同一图片自行处理后上传所有版本,但如果使用七牛的文件处理服务,则只需提供原图就可以了,其他版本的图片都可以通过七牛进行处理。如图10所示,我们把一张原图放进去之后,只需要在原图后面加一个问号和参数,就可以呈现出想要的方式,比如说加水印、旋转、缩放和剪裁。
1.png
图 10
/ f  V# U6 L( `. [  v+ P! B  t& A

( t! S7 t- W; z

7 g& t! U' A2 F: u0 H  |3 k  O  I
文件处理服务的架构在早期是非常笨拙的,如图11所示。FopGate是业务的入口,通过work config静态配置实际进行计算的各种worker集群的信息,里面包含了图片处理、视频处理、文档处理等各种处理实例。集群信息在入口配置中写死了,后端配置变更会很不灵活,因为是静态配置,突发请求情况下,应对可能不及时,且FopGate成为流量穿透的组件(业务的指令流与数据流混杂在一起),比如说要读一张图片,这张图片会经过FopGate导过来。
1.png
图 11
3 L" t: @3 V1 N. l1 j, W9 X; M
' X4 W% J- X* D4 \

. K6 K1 f& |( _# |+ W: A. H3 Y3 \
于是,我们自己组建了一个叫Discovery的服务,由它进行负载均衡和服务发现,用于集群中worker信息的自动发现,每个worker被添加进集群都会主动注册自己,FopGate从Discovery获取集群信息,完成对请求的负载均衡。同时在每个计算节点上新增Agent组件,用于向Discovery组件上报心跳和节点信息,并缓存处理后的结果数据(将数据流从入口分离),另外也负责节点内的请求负载均衡(实例可能会有多个)。此时业务入口只需负责分发指令流,但仍然需要对请求做节点级别的负载均衡。这是第二个阶段,如图12。
1.png
图 12
2 r! ~! c, ?7 P- a4 l& e: s3 h3 H, M
+ Z7 ]4 ~  G- o1 [

1 P! X7 {. ?" {0 m9 ]! t; ?1 ]
在第三个阶段,我们把文件处理架构迁移到了容器平台上,取消了业务的Discovery服务,转由平台自身的服务发现功能。每个Agent无需和Discovery维护心跳,也不再需要上报节点信息,每个Agent对应一个计算worker,并按工种独立成Service,比如ImageService、VideoService,由于后端只有一个worker,因此也不需要有节点内的负载均衡逻辑,业务入口无需负载均衡,只需请求容器平台提供的入口地址即可,如图13所示。
( Z0 l) ]: h0 V& P9 s
1.png
图 13
# C6 {( ?$ _: ~6 Z6 U) T. {) k8 R; F9 ]

# }  M  A  d2 a8 C2 y1 B

. a: q: ]. r, o- U$ M5 L; e
上一个阶段中,每个Agent仍然和计算实例绑定在一起,而这么做其实只是为了方便业务的无痛迁移,因为Agent本身的代码会有一些逻辑上的假设。在第四阶段中,如图14,我们进一步分离了Agent和worker,Agent独立成一个Service,所有的worker按工种独立成Service。这么分离的目的在于,Agent可能会有文件内容缓存,属于有状态的服务,而所有的worker是真正干活、无状态的服务。分离之后的好处在于,worker的数量可以随时调整和伸缩,而不影响Agent中携带的状态。可以看到,相比于最早的架构,业务方只需集中精力开发业务本身,而无需重复造轮子,实现各种复杂的服务发现和各种负载均衡的代码。另外,自从部署到容器平台之后,平台的调度器会自动根据节点的资源消耗状况做实例的迁移,这样使得计算集群中每个节点的资源消耗更加均衡。
1.png
图 14

4 R9 ?" Q: M0 y6 A3 L& f1 C$ \" Q
踩过的那些坑
  • 数据库连接风暴
    . T; }; z# N' s. p& v
    . {3 t) n2 R2 R
1.png
图 15
  e8 F. u+ f1 |  W4 {/ k
$ M, |: z: J9 A# K1 u' a
% M5 W% c' c# H4 y: R/ @7 P1 r
图15所示的是单体应用访问后端数据库使用的数据库连接池,连接池里的连接是可以复用的,而单体中所有的业务模块都可以调用同一个池里的连接。这个数据库连接池可以进行动态的伸缩,但它连接到后端数据库的连接是有上限的。拆分成微服务之后,可能每一个微服务都要创建一个数据库连接池,微服务间的数据库连接池并不能共享。当对微服务进行弹性伸缩时,并不知道它会弹性到什么程度,这时就可能会对后端数据库造成连接风暴,比如原本只有五千个长连接,但是由于弹性伸缩(可能根据前台业务情况进行了非常大的伸缩),会对数据库发生连接风暴,对数据库造成非常大的压力。

/ J; O7 c3 O& l: A' w1 F

' i1 p! ?7 y/ o& b" F: A7 _
为了确保不会因某个服务的连接风暴把数据库拖垮,对其他服务造成影响,我们做了一些优化。首先是优化了我们的一些弹性算法,其次是限定了容器弹性伸缩的范围,因为没有限制的伸缩,可能会对后端数据库造成压力。另外一个是降低连接池初始化的大小,比如初始化设定为10,它往数据库里面的长连接就是100个,如果设定为1,往数据库里面长连接就只有10个,如果太多则可能会对数据库造成压力。还有就是数据库端进行一些限定,当连接达到一定数量就进行预警,限制弹性扩展。
' X1 |( t* I0 v. X
$ p3 W; c1 A) U7 q5 Z3 j$ y* U. E( ^
  • 单体应用如何改造成微服务?

      \# m$ N5 H+ w- s) |
    2 ]: l/ U8 B& N- v. [

0 [( Z0 L2 a$ v
2 V* \9 ^5 s# l% H# d9 P" W
我在传统企业工作了七八年,我们一直在探讨单体应用如何拆分成微服务。其实对传统企业来讲,他们的单体是非常大的,而且内部的耦合性是非常强的,内部调用非常多。如果我们冒冒失失地将单体拆分成微服务,会占用非常大的网络传输。如果在拆成微服务的时候,没有进行很好的架构设计,拆成微服务并不是享受它带来的好处,而是灾难。所以在拆的时候,比如说前端、后端的拆分、耦合性不是特别强的拆分,我们提倡先跑到容器里面,看一下运维容器的时候有什么坑,然后解决这些坑,然后不断完善。我们可以把耦合性不是那么高的拆成大的块,然后把信息密集型的进行拆分,慢慢拆分成我们理想的架构。这是一个循序渐进的过程,不可一蹴而就。
1.png
图 16

) M+ _! O9 h5 M8 Q
图16是微服务的一些设计准则,例如设计提倡最小化功能,小到不能再小。这时需要每一个服务标准化的提供出来,有一个标准化的接口和其他微服务进行通信。还需要是异步通信,如果是同步会造成堵塞。每个微服务都要有独立的数据存储。此外,服务还需要是无状态的,因为如果有状态,弹性伸缩时可能会有数据丢失,可以用一些其他的方法处理这些有状态的数据。

+ O; Z6 j, |# x+ N+ K5 E; F
; T6 U$ x! M3 J9 M: `
原创:PPPCloud
) j1 [! w; y% z/ j8 r& i# t

" D% I  R3 s4 i1 E2 h* V
" K) m6 {) o) O: E/ Y5 _9 E5 v. G. L




上一篇:看京东金融:以应用为中心的DevOps平台建设
下一篇:DevOps最后一棒是有效构建海量运营的持续反馈能力
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

参加 ITIL 4 基础和专家认证、长河ITIL实战沙盘、DevOps基础级认证、ITSS服务经理认证报名

QQ|ITIL先锋论坛 ( 粤ICP备11099876号 )|appname

Baidu

GMT+8, 2022-6-28 10:51 , Processed in 0.140337 second(s), 32 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表