本文给大家介绍的内容是微服务容错与隔离:隔离机制。
容错与隔离微服务需要具备应对分布式环境的可容错性。在构建软件的开始阶段,就应该认识到网络和信息传递的不可靠性。我们需要对可能发生的故障设计出相应的软件隔离机制和措施,制定相应的容错策略,这个基本原则就是“Design for Failure”:为失败而设计。微服务架构可以在发生故障时通过合理的行为快速做出错误隔离和恢复机制,提供高可用性的服务。
在构建可容错软件系统的过程中要解决的本质问题就是故障隔离。在传统的单体架构下一旦应用出现故障,整个服务的可用性都会受到影响,因为所有模块都耦合在一个大的单体进程中,所以发生故障的位置很难确定,应用也很难从故障中恢复过来,这也是单体架构广遭诟病的一大原因。所以,我们需要将单体应用拆分成功能独立、相互隔离的微服务应用。
对于微服务架构而言,最关键的一个原则就是将系统划分成一个个相互隔离、自治的微服务,这些微服务通过定义良好的协议进行通信。我们希望存在隐患或者缺陷的服务不会对正常运行的模块或者服务产生不利的影响。
造船行业有一个专业术语叫作“舱壁隔离”,利用舱壁将不同的船舱隔离开来,如果某一个船舱进了水,那么就可以立即封闭舱门,形成舱壁隔离,其他船舱不受影响,船还可以正常航行。Docker通过“舱壁隔离”实现了进程的隔离,使得容器与容器之间不会互相影响。Spring Cloud Hystrix则实现了进程内部线程池的隔离,通过给每个依赖服务分配独立的线程池进行资源隔离,从而避免服务雪崩。
进程隔离机制
进程是传统操作系统中的重要隔离机制,每一个进程拥有独立的地址空间,提供操作系统级别的保护区。一个进程出现问题不会影响其他进程的正常运行,一个应用出错也不会对其他应用产生副作用。
随着微服务和容器技术的发展,我们说微服务的最佳载体正是容器。容器的本质就是一个进程,Docker鼓励一个容器只运行一个进程。这种方式非常适合以进程为粒度的微服务架构。也有人利用Docker容器作为轻量级的虚拟化方案,在单个容器中同时运行多个进程,这种使用方式往往会给应用带来隔离性问题和运行隐患。
进程与进程之间的互相隔离实现了容器之间互不影响的特性。在启动一个容器时,本质上就是启动了一个进程,Linux通过Namespace技术实现容器之间的隔离,通过Cgroups来实现容器的资源控制。用户的应用进程实际上就是容器里PID=1的进程,也是其他后续创建的所有进程的父进程,这意味着没有办法同时运行两个不同的应用,除非你能事先找到一个公共的PID=1的程序来充当两个不同应用的父进程。
容器作为一种沙箱技术,提供了类似集装箱的功能,把应用封装起来,这样被装进集装箱的应用就可以方便地被复制和移动。容器具备了天然的“不共享任何资源”的特性,所以可以认为容器是独立的服务主体。容器在与其他容器交互时,需要使用基于网络的消息通信机制,摆脱了模块之间的强依赖耦合。我们在本书后面的内容中会进一步介绍容器隔离机制的细节。
线程隔离机制
进程虽然具有较好的隔离性,但是进程之间交互需要跨进程边界,进程在数据共享方面存在数据传输的开销。而多线程并发编程模式可以最大限度地提高程序的并行度,线程作为操作系统最小的调度单元可以更好地利用多处理器的优势,恰当地使用线程可以降低开发和维护的开销,并且可以提高复杂应用的性能,当前在软件系统中大量使用了多线程编程模型。
线程隔离主要指线程池的隔离,在应用系统内部,将不同请求分类发送给不同的线程池,当某个服务出现故障时,可以根据预先设定的熔断策略阻断线程的继续执行。来看如下图所示的案例。
在Consumer模块中,接口A和接口C共用相同的线程池,当接口A的访问量激增时,接口A因为与接口C共用相同的线程池,所以势必影响接口C的效率,进而可能产生雪崩效应。如果我们使用线程隔离机制,那么可以将接口A和接口C做一个很好的隔离,如下图所示。
使用线程隔离机制将使线程池内可能出现问题的线程和其他线程隔离运行在一个独立的线程池中,一旦此线程出现问题,不会影响其他线程的运行,防止雪崩效应的产生。
信号量隔离机制
信号量semaphore是一个并发工具类,用来控制可同时并发的线程数。其内部维护了一组虚拟许可,通过构造器指定许可的数量,每次线程执行操作时先通过acquire方法获得许可,执行完毕再通过release方法释放许可。如果无可用许可,那么acquire方法将一直阻塞,直到其他线程释放许可。在信号量隔离机制下,接收请求和执行下游依赖在同一个线程内完成,不存在线程上下文切换所带来的性能开销。
信号量的资源隔离只是起到开关的作用,比如,服务A的信号量大小为10,那么就是说它同时只允许有10个Tomcat线程来访问服务A,其他请求都会被拒绝,从而达到资源隔离和限流保护的作用。
本文就是愿天堂没有BUG给大家分享的内容,大家有收获的话可以分享下,想学习更多的话可以到微信公众号里找我,我等你哦。