代码重新发布后docker服务会不会受影响_分享点经验 | 浅谈微服务架构

cde23999ce33046b8d8b728b8b30fef3.png

点击蓝字关注我们

AMP

9402ac8f5dbc84e1dd45ec01b6ce62fb.png cde23999ce33046b8d8b728b8b30fef3.png

背景简介

在最原始的系统设计中,我们通常使用单体架构。单体架构把所有的业务逻辑都写在一起,没有对业务场景进行划分。在规模比较小的情况下工作情况良好,但是随着系统规模的扩大,它暴露出来的问题也越来越多,比如高耦合,代码量大,维护困难,使用公用数据库,存储方式单一为解决这些问题,微服务架构应运而生。

cde23999ce33046b8d8b728b8b30fef3.png

什么是微服务架构

c6dc1d96b9936067cca71569c746ced6.png

微服务是一种用于构建应用的架构方案。微服务架构将应用拆分成多个核心功能。比如之前构建过一个基于SpringBoot的订餐系统,要实现用户和管理员的登陆注册,食单和订单的增删改查。

基于业务将应用拆分成3个微服务:

1、用户登陆注册微服务;

2、订单管理微服务;

3、食单管理微服务。

每个微服务单独构建和部署,并且各项服务在工作或者出现故障时不会相互影响。比如在订单管理微服务出现问题,它不会影响到用户和食单管理微服务。

微服务是低耦合,服务之间相互独立, 不同模块可使用不同数据库和存储方式,也可使用不同的开发技术。

cde23999ce33046b8d8b728b8b30fef3.png

微服务的优势与劣势

1、优势

1.1 易于开发和维护:

开发某个微服务我们就只需关心这个微服务的逻辑即可,代码量和逻辑复杂度都会降低,从而易于开发和维护。

1.2 局部修改容易部署:

在开发中发现了一个问题,如果是单体架构的话,我们就需要重新发布并启动整个项目,非常耗时间,但是微服务则不同,哪个模块出现了bug我们只需要解决那个模块的bug就可以了,解决完bug之后,我们只需要重启这个模块的服务即可,部署相对简单,不必重启整个项目从而大大节约时间。

1.3 按需伸缩:

单体架构在扩展某个模块的性能时不得不考虑到其它模块的性能会不会受影响,对于微服务来讲,某个模块通过什么方式来提升性能不必考虑其它模块的情况。

2、劣势

2.1 运维要求较高:

对于单体架构来讲,只需要维护好这一个项目就可以了,但是对于微服务架构来讲,由于项目是由多个微服务构成的,每个模块出现问题都会造成整个项目运行出现异常,这就对运维人员提出了很高的要求。

2.2 接口调整成本高:

比如,用户微服务是要被订单微服务和餐食微服务所调用的,一旦订单微服务的接口发生大的变动,那么所有依赖它的微服务,都要做相应的调整,由于微服务可能非常多,那么调整接口所造成的成本将会明显提高。

2.3 监控复杂度提升:

微服务的规模和动态性使得数据收集的成本大幅度提升,比如CPU,内存和网络传输的开销。大量的监控数据会对后台数据处理分析产生影响,这导致监控复杂度提升。

cde23999ce33046b8d8b728b8b30fef3.png

微服务的四个要素

1、小

微服务体积小。每个微服务只需要实现自己的业务逻辑,比如订单管理模块,它只需要处理订单的业务逻辑,其它的不必考虑。

2、独

能够独立的部署和运行。每个微服务从开发、测试、运维等都是独立的,包括存储的数据库也都是独立的,自己就有一套完整的流程,不依赖其他模块。

3、轻

使用轻量级的通信机制和架构。该通信方式需要是跨语言、跨平台的,可以让每个微服务都有足够的独立性,不受技术的钳制。例如REST API。

4、松

微服务之间是松耦合的。

cde23999ce33046b8d8b728b8b30fef3.png

微服务架构带来的挑战

1、应用高可用的问题

随着业务的发展,流量的增大,若这台服务器挂掉或者性能不够,会带来单点风险,高可用性差,通过集群化的方式来实现应用高可用和水平扩展。原来是请求直接到服务端,现在是请求先到反向代理层,再到服务端。反向代理层对外只暴露一个地址,可以让应用系统内部的组成不被外界看到,也可实现路由转发,负载均衡的能力。比如在个人项目中,我有三个微服务,分别把每个微服务部署在两个节点上,如图一所示。前端静态页面访问nginx的地址,nginx实现路由转发和负载均衡,保证若有一个节点挂掉了,应用也能正常运行。

b6425958decc3237b27f45f389a42fb8.png

图一:订餐系统项目Nginx部署示意图

1.1 怎么进行负载分配:

常见的负载策略有以下几种:

随机:把来自网络的请求随机分配给内部中的多个服务器。

轮询:  每一个来自网络中的请求,轮流分配给内部的服务器。

静态权重:根据服务器的不同处理能力,比如CPU和内存配置,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。确保高性能的服务器得到更多的使用率,避免低性能的服务器负载过重。

一致性哈希:通过哈希算法使这个请求一直在某个节点上。

动态权重:根据服务的性能表现,比如通过响应时间来分配。

在个人项目中,我没有设置负载策略的方式,使用的是轮询。

在反向代理的过程中,它需要能够探测到节点是否正常,若不正常,响应就不再往那个节点发了。在四层探测中,是探测服务器的ip端口,在探测过程中,若响应超时就判断节点不可用,可能因为网络波动,使得某次探测失败,所以会设置一个不健康阈值,比如在几次探测均失败,才判断节点不可用。同样也会设置一个健康阈值,在几次探测均成功,会将之前不可用的节点复用。若在探测服务器的ip端口是成功,但程序假死,需要七层探测,需要调用它的健康探测服务,检查域名或者路径。

在个人项目中,通过nginx实现负载均衡,路由转发,nginx配置如下:

upstream users{

    server IP地址1:8080

    server IP地址2:8080

}

server {

    location /users/ {

    proxy_pass http://users/

    }

}

1.2 如何解决反向代理层成为单点:

增加资源,增加多个代理节点,引入Keepalived 使得两个节点之间相互通信,实现主备模式。两个节点提供一个Virtual IP。但是这时,每次只有一个节点提供服务,资源利用率只有50%,所以引入多级反向代理,在软负载层前增加硬负载层,比如F5。

2、运维部署复杂的问题

因为把应用拆分成了很多微服务,会对服务器的资源需求有高要求,也会有复杂的人工部署。所以容器作为自动化的流程可以帮助我们。容器是在同一个操作系统上共享和操作资源,操作系统将容器看成一个进程,空闲的时候,他是不占用资源的。所以会需要有个资源调度管理分配平台,比如我司的稻客云平台。当应用构建比较复杂时,引入Jenkins。Jenkins从git代码仓库拉取解耦代码,打包成docker镜像,推到镜像仓库,我们就可以从应用商店里选择相应的镜像,启动成容器并进行部署,完成CICD的过程,如图二所示。

f755f2fc742034638c404f3453e9e470.png

图二:Jenkins打包至Docker部署的流程图

Docker的运作:将你的项目和基础镜像打成一个带有启动指令的项目镜像,然后在服务器创建一个容器,让镜像在容器内运行,从而实现项目的部署。它不仅仅可以部署项目,还可以用于nginx服务搭建,redis搭建。比如在个人项目中,我们就应用到了nginx和redis。

镜像(Image):docker镜像是使用Dockerfile脚本,将你的应用以及应用的依赖包构建而成的一个应用包。

容器(Container):容器的主要作用就在于给镜像提供运行空间和环境,并执行镜像指令。

仓库(Repository):仓库是用来存东西的,但不是存容器,而是存储docker镜像。

镜像是基础,容器是镜像使用者,仓库是镜像的管理员。容器和仓库都是围绕着镜像来运作的,是对镜像的管理和使用。

3、服务注册发现的问题

3.1 为什么需要服务注册发现?

因为实现了应用高可用,所以一般每一个服务都是有多个拷贝,来做负载均衡。比如在个人项目中,每个微服务都是有两个节点,若其中一个食单管理微服务挂掉了,整个应用也可以正常运行。

服务之间需要创建一种服务发现机制,用于帮助服务之间互相感知彼此的存在。每个微服务都会有自己的ip以及端口号,若在代码中直接写上依赖的服务的ip和port来调用服务,维护成本太高,而且通过Jenkins和Docker对服务进行容器化部署后,每次重新启动Docker都会发现服务的IP发生变化,无法对IP进行固定。

并且服务注册与发现可以实现对服务的管理,它可以将挂掉的服务去除,保留好的服务。

3.2 实现过程:

在个人项目中,通过zookeeper实现服务注册发现。当服务上线时,服务提供者将自己的服务信息注册到ZK,并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法,找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。简单来讲,zookeeper可以充当一个服务注册表,让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(ip+端口)去访问具体的服务提供者。

具体来说,zookeeper就是个分布式文件系统,每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /{service}/{version}/{ip:port}, 比如个人项目中订单管理微服务orderfood部署到两个容器中,那么zookeeper上就会创建两条目录,分别为:

/orderfood/1.0.0/IP地址1:8070

/orderfood/1.0.0/IP地址2:8070

zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除,比如IP地址1这台机器如果宕机了,那么zookeeper上的路径就会只剩 /orderfood/1.0.0/IP地址2:8070。

服务消费者会去监听相应路径(/orderfood/1.0.0),一旦路径上的数据有任务变化(增加或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。

4、全链路监控的问题

随着项目的扩展,微服务数量逐渐增加,服务按照不同的维度进行拆分,服务间的调用也越来越复杂,一次请求往往需要涉及到多个服务。这些服务可能由不同编程语言开发,不同团队开发,可能部署了很多副本。因此,就需要一个可以监控各个服务的性能及对服务间的调用进行跟踪的工具,以便发生故障的时候,能够快速定位和解决问题。全链路监控就在这样的背景下产生了。在个人项目中我们利用Pinpoint解决监控问题,Pinpoint是一款全链路分析工具,提供了无侵入式的调用链监控、方法执行详情查看、应用状态信息监控等功能。

Pinpoint支持的功能:

ServerMap:通过可视化它们的组件是如何互连的,了解任何分布式系统的拓扑结构。单击一个节点将显示关于组件的详细信息,例如其当前状态和事务计数

Realtime Active Thread Chart(实时活动线程图):实时监控应用程序内部的活动线程

Request/Response Scatter Chart(请求/响应散点图):随时间可视化请求计数和响应模式以识别潜在问题。可以通过拖动图表来选择其他细节

CallStack(调用堆栈):对分布式环境中的每个事务增加代码级可见性,在单个视图中识别瓶颈和故障点

Inspector(检查工具):查看应用程序的其他细节,如CPU使用、内存/垃圾收集、TPS和JVM参数。

另外因为微服务数量的增加,日志比较分散,想要检查各个微服务是否有报错信息,需要挨个服务去排查,比较麻烦。所以希望对日志进行聚合,然后通过监控,能够快速的找到各个微服务的报错信息,快速的排查,还需要日志收集存储的组件。比如用ELK来采集,集中处理和展示数据。

cde23999ce33046b8d8b728b8b30fef3.png

总结与展望

通过集群化,容器化的演进和增加资源,解耦拆分的设计思路,在个人项目中,也是通过这样的方式,将应用拆分成三个微服务,通过增加节点的方式来实现集群化部署。微服务虽然有很多优点,但是有很多约束,比如对开发团队的技术要求门槛高,对老旧系统改造困难等缺点。服务网格(Service Mesh)作为下一代微服务技术的代名词应运而生,它是解决服务间通讯的基础设施,集中控制的网关将会分散在每个节点处以分布式的形态存在,不需要侵入。所以微服务未来发展趋势将是集Spring Boot等微服务框架,Docker容器管理,Service Mesh服务网格等技术协同配合的发展趋势。

1b67fc675292b8e211a0f74b283daeac.png 92d5c7df368d9cdddd1a8e33f02576b6.png

记得关注我哦~
点击下方

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值