标签 微服务 下的文章 - 酷游博客
首页
关于
友链
Search
1
阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?
45 阅读
2
Java中泛型的理解
40 阅读
3
Java 14 发布了,再也不怕 NullPointerException 了!
38 阅读
4
Java中的可变参数
37 阅读
5
该如何创建字符串,使用" "还是构造函数?
29 阅读
技术
登录
/
注册
找到
2
篇与
微服务
相关的结果
2025-01-22
组件化、模块化、集中式、分布式、服务化、面向服务的架构、微服务架构
最近最火的词是什么?那大概就是微服务(Microservice)了。最近也火的一踏糊涂的Docker、DevOps也都是围绕着微服务领域的。在微服务领域还有很多相关名词。这些名词有一个共同的特点那就是晦涩难懂。他们就像中国古代的道、气、八卦等词一样,一解释就懂,一问就不知,一讨论就打架。 本文主要来介绍几个和微服务相关的概念。这些概念的都是博主在浏览了大量资料之后总结出的个人见解,如有偏颇,请指正,共勉之。 组件化与模块化 首先来谈两个前端和移动端比较常见的词:组件化和模块化(后面我会说到为什么要先介绍组件化和模块化)。 首先,可以肯定的是,组件化和模块化的中心思想都是分而治之。目的都是将一个庞大的系统拆分成多个组件或者说是模块。 组件化 首先来看维基百科中关于组件化(Component-based software engineering)的介绍: Component-based software engineering (CBSE), also known as component-based development (CBD), is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software. 大概意思就是:组件化就是基于可重用的目的,将一个大的软件系统按照分离关注点的形式,拆分成多个独立的组件,主要目的就是减少耦合。 一个独立的组件可以是一个软件包、web服务、web资源或者是封装了一些函数的模块。这样,独立出来的组件可以单独维护和升级而不会影响到其他的组件。 模块化 维基百科中对模块化Modular Programming的定义如下: Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality. With modular programming, concerns are separated such that modules perform logically discrete functions, interacting through well-defined interfaces. 模块化的目的在于将一个程序按照其功能做拆分,分成相互独立的模块,以便于每个模块只包含与其功能相关的内容,模块之间通过接口调用。将一个大的系统模块化之后,每个模块都可以被高度复用。 模块化和组件化的区别 从上面的定义中可以看出,组件化和模块化的意思差不多,主要思想都是分而治之。只是一个把拆分之后的每个片段叫做组件、另一个把拆分之后的片段叫做模块。那么这两种拆分在拆分方式上是不是有什么不同的? 关于组件化和模块化的区别,我在网上看了好多资料,也没有人能给出准确的回答。其实没有准确回答的原因也比较明显,那就是大多数时候我们真的不需要严格的区分这两个名字。我们要学习的是其中的解耦和分治的思想和目的。 从另外一个角度来讲,如果真的要区分一下组件化和模块化的话,那么可以认为这两种分而治之的目的稍有区别: 模块化的目的是为了重用,模块化后可以方便重复使用和插拨到不同的平台,不同的业务逻辑过程中。 组件化的目的是为了解耦,把系统拆分成多个组件,分离组件边界和责任,便于独立升级和维护。 集中式与分布式 要谈微服务,那么必须建立在分布式的基础上,对于一个集中式系统也无需谈微服务。在我的另外一篇文章初识分布式系统中介绍过集中式系统和分布式系统的区别,这里再简单回顾一下: 集中式 集中式系统用一句话概括就是:一个主机带多个终端。终端没有数据处理能力,仅负责数据的录入和输出。而运算、存储等全部在主机上进行。 集中式系统的最大的特点就是部署结构非常简单,底层一般采用从IBM、HP等厂商购买到的昂贵的大型主机。因此无需考虑如何对服务进行多节点的部署,也就不用考虑各节点之间的分布式协作问题。但是,由于采用单机部署。很可能带来系统大而复杂、难于维护、发生单点故障(单个点发生故障的时候会波及到整个系统或者网络,从而导致整个系统或者网络的瘫痪)、扩展性差等问题。 分布式 分布式就是一群独立计算机集合共同对外提供服务,但是对于系统的用户来说,就像是一台计算机在提供服务一样。分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。计算机越多,CPU、内存、存储资源等也就越多,能够处理的并发访问量也就越大。 拿电商网站来说,我们一般把一个电商网站横向拆分成商品模块、订单模块、购物车模块、消息模块、支付模块等。然后我们把不同的模块部署到不同的机器上,各个模块之间通过远程服务调用(RPC)等方式进行通信。以一个分布式的系统对外提供服务。 服务化 提到分布式,一个不得不提的词就是服务化,服务化架构使搭建分布式系统成为了可能。 传统的软件开发面临着很多的问题,比如: 代码重复率高、代码庞大难以维护、无法快速迭代、测试成本高、可伸缩性差、可靠性差、模块间高度依赖。为了解决上面这些问题,我们一般采用拆分、解耦、分层、独立等方式来解决。有了服务化架构,我们就可以在很大程度上解决这些问题。 服务化是一种粗粒度、松耦合的以服务为中心的架构,服务之间通过定义明确的协议和接口进行通信。 这里说到的“服务”,本质上来说,就是指“RPC”。单纯的RPC功能实现,其实很简单,无非就是client发起调用,中间某个组件(甚至就是client本身)拦截调用信息,序列化后将信息传输到server端,server端收到调用请求后反序列化,根据请求详细发起实际调用后返回响应传输回给client端。这样的RPC很常见,比如常见的存储过程调用就是一例。但是在一个复杂的业务环境,如何管理和协同这些大量的RPC才是最麻烦的事情。所以,一般提到的“服务化”更多指的是对RPC的管理。服务化一般关注服务注册,服务协调,服务可用性,服务通讯协议和内容交换等。 面向服务的架构 面向服务架构(Service-Oriented Architecture,SOA)又称“面向服务的体系结构”,是Gartner于2O世纪9O年代中期提出的面向服务架构的概念。 面向服务架构,从语义上说,它与面向过程、面向对象、面向组件一样,是一种软件组建及开发的方式。与以往的软件开发、架构模式一样,SOA只是一种体系、一种思想,而不是某种具体的软件产品。 这里,我们通过一个例子来解释一下到底什么是SOA?如何做到SOA? 什么是SOA SOA也可以说是一种是设计原则(模式),那么它包含哪些内容呢?事实上,这方面并没有最标准的答案,多数是遵从著名SOA专家Thomas Erl的归纳: 标准化的服务契约 Standardized service contract 服务的松耦合 Service loose coupling 服务的抽象 Service abstraction 服务的可重用性 Service reusability 服务的自治性 Service autonomy 服务的无状态性 Service statelessness 服务的可发现性 Service discoverability 服务的可组合性 Service composability 这些原则总的来说要达到的目的是:提高软件的重用性,减少开发和维护的成本,最终增加一个公司业务的敏捷度。 既然是面向服务的架构,那么我们就先来定义一个服务, public interface Echo { String echo(String text); } public class EchoImpl implements Echo { public String echo(String text) { return text; } } 上面这段代码相信有过JavaWeb开发经验的人都不会陌生。就是定义了一个服务的接口和实现。 那么,定义了服务,我们就做到了SOA了么? 我们用Thomas Erl定义的原则来对比一下,用松耦合和可重用这几个原则来尝试分析一下上面Echo示例: Echo的服务契约是用Java接口定义,而不是一种与平台和语言无关的标准化协议,如WSDL,CORBA IDL。当然可以抬杠,Java也是行业标准,甚至全国牙防组一致认定的东西也是行业标准。 Java接口大大加重了与Service客户端的耦合度,即要求客户端必须也是Java,或者JVM上的动态语言(如Groovy、Jython)等等…… 同时,Echo是一个Java的本地接口,就要求调用者最好在同一个JVM进程之内…… Echo的业务逻辑虽然简单独立,但以上技术方面的局限就导致它无法以后在其他场合被轻易重用,比如分布式环境,异构平台等等 ESB是SCA思想实现的基础设施。ESB主要作用是集中注册发布服务,为服务与传输协议之间解耦。并不是所有的SOA架构都需要ESB,ESB是SCA特有的。当然任何符合ESB特征的解决方式都可以称之为ESB,也不仅仅是SCA内部的。 因此,我们可以认为Echo并不太符合SOA的基本设计原则。 实现SOA 修改一下上面的Echo,添加Java EE的@WebServices注解 @WebServices public class EchoImpl implements Echo { public String echo(String text) { return text; } } 现在将Echo发布为Java WebServices,并由底层框架自动生成WSDL来作为标准化的服务契约,这样就能与远程的各种语言和平台互操作了,较好的解决了上面提到的松耦合和可重用的问题。按照一般的理解,Echo似乎就成为比较理想的SOA service了。 使用WebServices只是一种相对简单的方案,SOA的最常见的解决方案是SCA,其次还有JBI,BPEL等。ESB是SCA思想实现的基础设施。ESB主要作用是集中注册发布服务,为服务与传输协议之间解耦。关于SCA和ESB并不是本文的重点,感兴趣的朋友可以从网络上获取更多资料。(可以从上图中看到ESB在整个SOA架构中所扮演的角色) 面向对象和面向服务的对比 面向对象(OO)和面向服务(SO)在基础理念上有大量共通之处,比如都尽可能追求抽象、封装和低耦合。 但SO相对于OO,又有非常不同的典型应用场景,比如: 多数OO接口(interface)都只被有限的人使用(比如团队和部门内),而SO接口(或者叫契约)一般来说都不应该对使用者的范围作出太多的限定和假设(可以是不同部门,不同企业,不同国家)。还记得贝佐斯原则吗?“团队必须做好规划与设计,以便未来把接口开放给全世界的程序员,没有任何例外”。 多数OO接口都只在进程内被访问,而SO接口通常都是被远程调用。 简单讲,就是SO接口使用范围比一般OO接口可能广泛得多。我们用网站打个比方:一个大型网站的web界面就是它整个系统入口点和边界,可能要面对全世界的访问者(所以经常会做国际化之类的工作),而系统内部传统的OO接口和程序则被隐藏在web界面之后,只被内部较小范围使用。而理想的SO接口和web界面一样,也是变成系统入口和边界,可能要对全世界开发者开放,因此SO在设计开发之中与OO相比其实会有很多不同。(微观SOA:服务设计原则及其实践方式(上篇)) 微服务架构 微服务架构(MicroService)是一种服务化架构风格,通过将功能分散到各个离散的服务中以实现对解决方案的解耦。微服务架构强调的第一个重点就是业务系统需要彻底的组件化和服务化(这也是我们为什么要先介绍组件化和服务化的原因)。微服务的诞生并非偶然。它是互联网高速发展,敏捷、精益、持续交付方法论的深入人心,虚拟化技术与DevOps文化的快速发展以及传统单块架构无法适应快速变化等多重因素的推动下所诞生的产物。 微服务的流行,Martin功不可没,先看看他是如何定义微服务的: The microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services , which may be written in different programming languages and use different data storage technologies. 总结起来大概以下四点: 一些列的独立的服务共同组成系统 单独部署,跑在自己的进程里 每个服务为独立的业务开发 分布式的管理 Martin自己也说了,每个人对微服务都可以有自己的理解,不过大概的标准还是有一些的。 分布式服务组成的系统 按照业务而不是技术来划分组织 做有生命的产品而不是项目 Smart endpoints and dumb pipes(我的理解是强服务个体和弱通信) 自动化运维(DevOps) 容错 快速演化 SOA和微服务 看了SOA和微服务,很多人会认为这不就是一回事儿么。其实SOA和微服务就是差不多的。 SOA关注的是服务重用,微服务在关注服务重用的同时,也同时关注快速交付; 微服务不再强调传统SOA架构里面比较重的ESB企业服务总线。微服务把所有的“思考”逻辑包括路由、消息解析等放在服务内部,去掉一个大一统的ESB,服务间轻通信,是比SOA更彻底的拆分。(微服务(Microservice)那点事) 关于微服务这里只是做一个简单的介绍,要想真正的了解微服务还有很多路要走,比如康威定律(我后面会专门写一篇文章介绍康威定律)、服务间通信、服务的注册与发现、服务治理与服务编排等。。。 总结 本文主要介绍了组件化、模块化、集中式、分布式、服务化、面向服务的架构、微服务架构等概念。但是,正所谓实践出真知。还是要在日常工作中实际运用才能真正的掌握。 推荐阅读 ESB和SOA到底是什么? 微观SOA:服务设计原则及其实践方式(上篇) 微观SOA:服务设计原则及其实践方式(下篇) 每天都在谈SOA和微服务,但你真的理解什么是服务吗? 微服务(Microservice)那点事 参考资料 对组件化与模块化的思考与总结 前端开发的模块化和组件化的定义,以及两者的关系? Module vs. component design 浅谈服务化架构 解析微服务架构(二)微服务架构综述 SOA、ESB、SCA之间的联系 微观SOA:服务设计原则及其实践方式(上篇) 微服务(Microservice)那点事
技术
# 微服务
酷游
1月22日
0
23
0
2025-01-22
面试官:你知道Dubbo怎么做优雅上下线的吗?你:优雅上下线是啥?
最近无论是校招还是社招,都进行的如火如荼,我也承担了很多的面试工作,在一次面试过程中,和候选人聊了一些关于Dubbo的知识。 Dubbo是一个比较著名的RPC框架,很多人对于他的一些网络通信、通信协议、动态代理等等都有一定的了解,这位候选人也一样。 但是,我接下来问了他一个问题:你们在使用Dubbo的时候,应用如果重启,怎么保证一个请求不会被中断处理的呢? 他没怎么说的上来,我以为他不理解我的问题,我接着问他:我就是想问下Dubbo是如何做优雅上下线的你知道吗? 接着他问我:优雅上下线是啥?? 好吧。 这篇文章,我来介绍一下这个知识点吧。 优雅上下线 关于”优雅上下线”这个词,我没找到官方的解释,我尝试解释一下这是什么。 首先,上线、下线大家一定都很清楚,比如我们一次应用发布过程中,就需要先将应用服务停掉,然后再把服务启动起来。这个过成就包含了一次下线和一次上线。 那么,”优雅”怎么理解呢? 先说什么情况我们认为不优雅: 1、服务停止时,没有关闭对应的监控,导致应用停止后发生大量报警。 2、应用停止时,没有通知外部调用方,很多请求还会过来,导致很多调用失败。 3、应用停止时,有线程正在执行中,执行了一半,JVM进程就被干掉了。 4、应用启动时,服务还没准备好,就开始对外提供服务,导致很多失败调用。 5、应用启动时,没有检查应用的健康状态,就开始对外提供服务,导致很多失败调用。 以上,都是我们认为的不优雅的情况,那么,反过来,优雅上下线就是一种避免上述情况发生的手段。 一个应用的优雅上下线涉及到的内容其实有很多,从底层的操作系统、容器层面,到编程语言、框架层面,再到应用架构层面,涉及到的知识很广泛。 其实,优雅上下线中,最重要的还是优雅下线。因为如果下线过程不优雅的话,就会发生很多调用失败了、服务找不到等问题。所以很多时候,大家也会提优雅停机这样的概念。 本文后面介绍的优雅上下线也重点关注优雅停机的过程。 操作系统&容器的优雅上下线 关于操作系统,我之前有一篇文章专门介绍过这个话题,可能大家没有注意到,那时候介绍的主题是为什么不能在线上机器中随便执行kill -9。 其实,这背后的思考就是优雅上下线。 我们知道,kill -9之所以不建议使用,是因为kill -9特别强硬,系统会发出SIGKILL信号,他要求接收到该信号的程序应该立即结束运行,不能被阻塞或者忽略。 这个过程显然是不优雅的,因为应用立刻停止的话,就没办法做收尾动作。而更优雅的方式是kill -15。 当使用kill -15时,系统会发送一个SIGTERM的信号给对应的程序。当程序接收到该信号后,具体要如何处理是自己可以决定的。 kill -15会通知到应用程序,这就是操作系统对于优雅上下线的最基本的支持。 以前,在操作系统之上就是应用程序了,但是,自从容器化技术推出之后,在操作系统和应用程序之间,多了一个容器层,而Docker、k8s等容器其实也是支持优雅上下线的。 如Docker中同样提供了两个命令, docker stop 和 docker kill docker stop就像kill -15一样,他会向容器内的进程发送SIGTERM信号,在10S之后(可通过参数指定)再发送SIGKILL信号。 而docker kill就像kill -9,直接发送SIGKILL信号。 JVM的优雅上下线 在操作系统、容器等对优雅上下线有了基本的支持之后,在接收到docker stop、kill -15等命令后,会通知应用进程进行进程关闭。 而Java应用在运行时就是一个独立运行的进程,这个进程是如何关闭的呢? Java程序的终止运行是基于JVM的关闭实现的,JVM关闭方式分为正常关闭、强制关闭和异常关闭3种。 这其中,正常关闭就是支持优雅上下线的。正常关闭过程中,JVM可以做一些清理动作,比如删除临时文件。 当然,开发者也是可以自定义做一些额外的事情的,比如通知应用框架优雅上下线操作。 而这种机制是通过JDK中提供的shutdown hook实现的。JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子。 例子如下: package com.hollis; public class ShutdownHookTest { public static void main(String[] args) { boolean flag = true; Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("hook execute..."); })); while (flag) { // app is runing } System.out.println("main thread execute end..."); } } 执行命令: jps 6520 ShutdownHookTest 6521 Jps kill 6520 控制台输出内容: hook execute... Process finished with exit code 143 (interrupted by signal 15: SIGTERM) 可以看到,当我们使用kill(默认kill -15)关闭进程的时候,程序会先执行我注册的shutdownHook,然后再退出,并且会给出一个提示:interrupted by signal 15: SIGTERM Spring的优雅上下线 有了JVM提供的shutdown hook之后,很多框架都可以通过这个机制来做优雅下线的支持。 比如Spring,他就会向JVM注册一个shutdown hook,在接收到关闭通知的时候,进行bean的销毁,容器的销毁处理等操作。 同时,作为一个成熟的框架,Spring也提供了事件机制,可以借助这个机制实现更多的优雅上下线功能。 ApplicationListener是Spring事件机制的一部分,与抽象类ApplicationEvent类配合来完成ApplicationContext的事件机制。 开发者可以实现ApplicationListener接口,监听到 Spring 容器的关闭事件(ContextClosedEvent),来做一些特殊的处理: @Component public class MyListener implements ApplicationListener { @Override public void onApplicationEvent(ContextClosedEvent event) { // 做容器关闭之前的清理工作 } } Dubbo的优雅上下线 因为Spring中提供了ApplicationListener接口,帮助我们来监听容器关闭事件,那么,很多web容器、框架等就可以借助这个机制来做自己的优雅上下线操作。 如tomcat、dubbo等都是这么做的。 这里简答说一下Dubbo的,在Dubbo的官网中,有关于优雅停机的介绍:  应用在停机时,接收到关闭通知时,会先把自己标记为不接受(发起)新请求,然后再等待10s(默认是10秒)的时候,等执行中的线程执行完。 那么,之所以他能做这些事,是因为从操作系统、到JVM、到Spring等都对优雅停机做了很好的支持。 关于Dubbo各个版本中具体是如何借助JVM的shutdown hook机制、或者说Spring的事件机制昨的优雅停机,我的一位同事的一篇文章介绍的很清晰,大家可以看下: https://www.cnkirito.moe/dubbo-gracefully-shutdown/ 在从Dubbo 2.5 到 Dubbo 2.7介绍了历史版本中,Dubbo为了解决优雅上下线问题所遇到的问题和方案。 目前,Dubbo中实现方式如下,同样是用到了Spring的事件机制: public class SpringExtensionFactory implements ExtensionFactory { public static void addApplicationContext(ApplicationContext context) { CONTEXTS.add(context); if (context instanceof ConfigurableApplicationContext) { ((ConfigurableApplicationContext) context).registerShutdownHook(); DubboShutdownHook.getDubboShutdownHook().unregister(); } BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER); } } 总结 本文从操作系统开始,分别介绍了Linux、Docker、JVM、Spring、Dubbo等对优雅停机的支持。 可以看到,一个简单的优雅停机功能,上下游需要这么多底层基础设施和上层应用的支持。 相信通过学习本文,你一定对优雅上下线有了更多的了解。 除此之外,我还希望你,通过本文以后,遇到一些实际问题的时候,可以想到文中提到的shutdown hook机制、Spring的event机制。很多时候,这些机制都能帮助我们解决很多问题。 我在工作中,就有很多次使用过这样的机制的实例,后面有机会给大家介绍几个实例。 参考 : https://zhuanlan.zhihu.com/p/29093407 https://www.cnkirito.moe/dubbo-gracefully-shutdown/
技术
# 微服务
酷游
1月22日
0
11
0
易航博客