一、SOA和ESB一直是没有明确概念的两个缩略词
SOA----面向服务架构,实际上强调的是软件的一种架构,一种支撑软件运行的相对稳定的结构,表面含义如此,其实SOA是一种通过服务整合来解决系统集成的一种思想。不是具体的技术,本质上是一种策略、思想。
ESB----企业服务总线,像一根“聪明”的管道,用来连接各个“愚笨”的节点。为了集成不同系统,不同协议的服务,ESB做了消息的转换解释与路由等工作,让不同的服务互联互通。
可以明确的说SOA就是一种服务集成思想,它的不同实现方式可能差别很大,目前SOA最常见的实现方式是SCA和JBI。
二、ESB究竟是什么
IBM、Oracle等认为ESB是连接服务的一种模式,但一些开源组织和其他厂商认为ESB是一种产品,并且提供了ESB连接解决方案的实现,这种实现可以认为是中间件,也可以认为是组件工具。 
对此,我个人的观点更偏向前者,ESB是一种模式,ESB的实现方式也很多,可以称之为ESB产品。当然在不同场合ESB的含义也不同,需要鉴别。
三、为什么ESB总和SOA黏在一块
通常,这两个名词总不分家,谈论的话题中“你中有我,我中有你”。
 
为什么是这样的呢?
ESB是SOA吗?
两者之间究竟有什么微妙的关系呢?
带着疑问,继续往下看:
首先,ESB不是SOA。SOA的最常见的实现方式方式是SCA和JBI,而SCA的实现需要ESB,相反JBI则不需要ESB,可以参看本人对JBI和SCA分析解读的文章。
 
其次,因为IBM和Oracle(收购了BEA和SUN的牛X公司)都推崇SCA模式的SOA,因此SCA实际上已经成为SOA的事实标准,说道SOA,最先想到的就是SCA模式了。
最后,ESB是SCA架构实现不可缺少的一部分,ESB产品脱离了具体的应用外,没有任何意义。ESB的作用在于实现服务间智能化集成与管理的中介。通过ESB可以访问所集成系统的所有已注册服务。
四、ESB的特点
ESB是一种在松散耦合的服务和应用之间标准的集成方式。它可以作用于:
面向服务的架构 - 分布式的应用由可重用的服务组成
面向消息的架构 - 应用之间通过ESB发送和接受消息
事件驱动的架构 - 应用之间异步地产生和接收消息
ESB就是在SOA架构中实现服务间智能化集成与管理的中介。

谈及企业服务总线(ESB),在有面向服务的架构(SOA)实施经验的开发者眼中一定不会陌生。这些年,人们一直在谈论它,以至有些人认为“实施SOA一定需要ESB”,或“只要将ESB架起来了,我们就SOA了”。这些说法有可取之处,也存在片面之嫌,由于业界对于ESB没有统一、标准的定义,所以一千个人眼中有一千个“ESB”也就成了情理中的事情了。然而,怎么才能将ESB用好?我们需要清楚地认识ESB在SOA中所扮演的角色,理解哪些工作是ESB的职责之内,哪些却不是。只有正确地认识了ESB的职能,并委以恰当的任务,才能将它用在刀刃上、发挥其巨大的能量。

ESB的缺点

1、服务调用方式的不同带来业务的影响和扩展成本

  传统的ESB的服务调用方式是,每一次服务的调用者要向服务提供者进行服务交互请求时都必须通过中心的ESB来进行路由 ,如下图:

每一次服务交互的路线是:

服务调用者-->ESB(接收服务请求)-->服务提供者(服务处理)-->ESB(服务提供返回结果)-->服务调用者(服务返回)

经过服务总线路由过的服务交互,共出现4次网络会话创建和数据传输,而“去中心化”服务架构中服务交互,一次服务的调用只有2次网络会话创建和数据传输,在网络上的开销整整减少了一半,如下图:

2、“雪崩”效应束缚了“中心化”服务框架的扩展能力

  传统企业服务总线的架构就暴露出“硬伤”,例如,10台ESB服务器有一台实例出现了问题,无法正常提供服务路由的能力,服务路由压力就落在了剩下的9台ESB服务器上,原本由出问题的那台服务器提供的服务路由职能就分摊到了剩下的9台上,每台的负载水位就超过88%,个别服务器可能更高,在服务器处于高水位运行的时候,出现问题的概率会大增。导致其他服务器也不堪重负而“罢工”。

  “雪崩”事故后,故障恢复的时间和成本非常高昂,因为传统的一台一台重启服务器已经不能进行故障的恢复,因为一旦服务启动起来,前端的访问洪流会立即再次压垮启动后的服务器,唯一正确的方式是先切断前端应用对企业服务总线的服务请求,让这10台服务器全部启动后,在开放服务请求,这样才能恢复系统的运行。

正确理解ESB在SOA中的作用

平心而论,ESB的确是SOA中一个非常重要的集成层组件(Integration Layer),不论是OpenGroup发布的SOA参考架构,还是几大主流SOA供应商(参考IBM通过参考架构实施SOA解决方案 ,Oracle与F5的SOA参考架构,Microsoft的BizTalk ESB Toolkit中对ESB的定义),都将ESB置于SOA架构的核心位置。

事实上,ESB在SOA中扮演着重要的角色,在技术层解决了SOA的整合问题,耦合了应用与应用之间的集成逻辑,使得SOA更灵活,更易于扩展,更敏捷。有了ESB,新建的服务消费者应用程序不需要关心服务的提供者在哪里,使用何种通讯协议,与其交互的数据是怎样的……,它只需向ESB发出请求,使用开放的、标准的通讯协议。相反,若某个可重用的价值较大的服务位于某一个遗留系统中,而由于种种原因,该遗留系统不能在短期内重写,此时ESB可以架起该服务与其使用者之间沟通的桥梁。当然,ESB的作用远不止这些,业内也有很多讨论,本文不再赘述。读者可在Google上搜索ESB Patterns获得相关资料。

然而,ESB并非“救世主”,它注定也不可能解决应用系统整合中出现的所有问题。道理很简单,计算机发展历史长从没有出现过一个产品/工具可以满足所有的应用需求,技术发展得很快,需求发展更快,所以技术永远跟不上需求。此外,ESB或ESB产品有其特定的适用范围,它是基础设施层的概念/产品,解决的是整合中的常见问题,比如服务连通、路由、消息丰富、服务的注册/查找/发布等服务的管理、服务监控和质量保证等。ESB不能解决的问题比其能解决的问题多很多。比如,让它去做人工流程的编排是不合适的,让它提供门户类产品那样的用户交互也是极其困难的……。

笔者支持过许多客户项目。在这些项目中,有的客户将ESB用的好,有的则勉强用上,用的功能很简单,有的则用ESB做一些原本不属于它该做的工作。在这里,笔者仅从个人的立场,分享自己这些年来积累的ESB实施经验。下面列出笔者常看到但不推荐的实施和笔者在实施ESB的过程中积累的一些较好的实践方式,供读者参考。同时欢迎批评指正。

不推荐实施

挟ESB以令外围应用

  • 现象:

    ESB的架构师在ESB上设计一套标准的数据接口(通用的XML格式),规定使用统一的协议(如Web Service/HTTP)。所有的ESB服务消费者和接入ESB的服务必须符合该标准。其目的是为了简化ESB上的开发工作。这就是一种“挟天子以令诸侯”的做法,因为在实际情况中,可能领导规定了“所有的服务必须要经过ESB,即便是透传”。

  • 分析:

    国内的ESB实施者大多数是一些SI/ISV,出于成本/人力或其他个方面的原因,总会有一些架构师希望达成这样一个目标:我能否设计/实现一个一劳永逸的ESB中间平台,将来不论哪种服务都可以方便地接入到ESB上?

    这是一个很浪漫很理想的目标,但这个目标是不可能实现的。原因有二:其一,仲裁逻辑一般是非常具体的,具体的服务有具体的整合需求。譬如,一个服务提供者基于HTTP提供了一个Web服务WS1,而我们希望将这个服务通过ESB暴露给两个客户端ClientA,Client B;Client A使用XML/HTTP访问服务,而Client B却使用SOAP/JMS访问该服务,如图1所示。有过ESB实施经验的人都能看出里面的仲裁逻辑是非常具体的,我们要考虑的不仅仅是协议之间的差别,还需要考虑消息格式的差别。其二,如果有这样的设计/实现存在,ESB产商为何不把这个特性直接实现了呢?你也许会说产商不理解具体的业务,而具体的业务是复杂的,SI/ISV却了解这些复杂业务。而事实上,ESB解决的更多是技术层面的工作,业务层面的工作大多数不属于ESB的范畴,复杂的业务逻辑不是在业务系统中实现,就是在其它SOA组件中实现,如流程管理引擎。

    图1. ESB的主要功能之一是连接异构协议和数据。

  • 原因及危害:

    该实践出现的根本原因是:没有认清ESB本身的作用,过分看重了ESB之上的设计能力。其实,ESB针对的是一个个功能各异的整合逻辑,服务之间的整合逻辑也是迥异的。所以,一劳永逸的ESB之上的架构是不存在的。

    其危害是:丢失了ESB本身最强大的连通性方面的功能,正式因为需要联通的应用之间的差异性,才逐渐发展出了ESB这样的组件。如果要求所有的外围应用的协议标准和数据标准都统一了(事实上,这是不可能实现的,特别在与第三方应用整合时),那么ESB的必要性就逊色不少。

  • 建议:

    不要试图实现一个一劳永逸的ESB之上的架构,这个架构不存在也没有其存在的必要性。不过,笔者并非反对设计。实际上,ESB上可以设计,也可以通过一定的设计实现某种程度的自动化,灵活性和通用性。举个例子,某一组功能类似的服务,对这一组服务的所有请求必须进行审计、安全加固等操作,对于这一类需求,我们可以事先在ESB上设计好相应的技术组件/服务,然后在ESB的仲裁流中间调用该组件/服务即可。

用ESB实现业务流程

  • 现象:

    有些架构师看到ESB支持服务组合(Service Composition)模式,进而认为可用该模式来实现业务流程。因此,ESB产品就演变成了BPM产品。

  • 分析:

    如果读者关心过ESB的通用使用模式,就会发现ESB的服务组合模式(Service Composition)与BPM中的服务编排(Service Cherography)非常相似,二者都是将细粒度的服务组合/组装起来,形成大粒度的服务,或者业务流程。

    事实上,二者有着本质的区别。其一:ESB是一个偏向技术层整合的组件,比如将“客户资料查询”服务与“日志”服务组装起来,得到的结果还是“客户资料查询”服务,只是在仲裁流中间插入了一个新的附加功能,即“日志”服务。BPM中的服务编排的含义很侧重于业务流转的概念。比如“项目立项审批流程”,该流程的实现可能需要来自几个相关系统中的服务的参与,它们可能是“立项申请”,接着是“一级职能经历审批”,然后是“部门经理审批”,“财务审批”等。这些服务流转起来形成的是一个完整的业务流程。其二:ESB上的服务组合是无状态的,ESB运行时会为每个请求建立一个实例来执行其仲裁逻辑,请求与请求之间没有时序关系,是互不相干的、各自独立的。相反,BPM上的服务编排这不一样,未完成的业务流程实例一直会存活在BPM运行时中,存活期可能为一天、一周、甚至1个月或更长;请求与请求之间可能存在着一定的关联性,比如对与一个项目(相同的项目ID)的立项审批流程,一级职能经理、部门经理和财务对流程发出的请求都是针对同一运行时实例的。

  • 原因及危害:

    除了其他非技术的因素外,导致该实践的一个重要原因是:混淆了ESB的服务组合与BPM的服务编排两个概念。

    危害:让ESB实现BPM,特别是长运行的流程时,虽然在技术上可以实现,但是这违背了ESB产品的设计理念,会大大影响其ESB运行时的整体运行效率。

  • 建议:

    认清技术上的服务组合与服务编排之间的差异,分析每个产品所属的概念范畴,选择合适的产品解决合适的问题。

用ESB实现大数据传输

  • 现象:

    将ESB用于在两个系统间传输大量数据,比如传输视频文件、大文档等。在这些场景中传输的信息/文件/消息有一个共同的特点:只使用了ESB提供的连通性功能,而没有使用其他功能,如消息解析,转换,路由等。

  • 分析:

    为了在ESB市场上抢占有利位置,各大厂商提供的ESB产品的能力越来越强。ESB产品的设计是支持消息从一个系统传到另一个或几个系统的。所以,一些架构师利用ESB产品本身提供的此项功能架设了一个数据传输总线。

    可是ESB并不适合完成该项功能,虽然它可以实现这一功能,但这并非最佳实践。ESB作为企业级的服务联通、管理平台,需要穿透ESB的服务应该是企业内重用可能最大、价值最大的那些服务,应用程序对这类服务的访问应该非常频繁,因此同一时刻需要ESB支撑的业务可能非常繁重。所以,ESB产品的设计初衷是实现一个无状态、高吞吐的服务总线,为企业内重要的业务服务提供透明、标准、开放的接入能力。

  • 原因及危害:

    这种实践的原因是过分放大了ESB对数据的传输能力,如果在ESB传输巨大的信息,可能会导致ESB整体性能的下降,损害其他重要服务的QoS。

  • 建议:

    如果需要传输的数据有解析或转换的需求、或者需要根据数据里的信息进行某种路由或其他仲裁逻辑需求时,则建议使用ESB;但如果同时消息体又过与庞大,可以考虑将需要解析的消息与不需解析的数据部分进行拆分,通过其他专门的数据传输平台去传输不需解析的部分,如FTP,数据库备份机制等,而在ESB中实现该传输任务的控制流。

推荐实施

服务要管理起来

ESB的一个重要功能是将企业内/合作伙伴处的服务以开放的、标准的服务方式暴露出来,使得服务消费者能够便利地查找到服务,以促进服务的重用、管理。而许多ESB产品不包含服务的注册、存储、发布、订阅等功能,这些功能包含UDDI库中。所以,ESB一般需要一个服务注册/存储库与之协作。ESB执行各种仲裁逻辑,而注册库为ESB提供必要的元数据信息。

服务注册库可以存储服务的元数据,包括服务的描述、功能、版本、输入/输出消息的模式、服务端点、SLA、安全策略等内容,这些信息可被ESB用来进行消息格式验证、服务的动态路由、执行安全策略和SLA保证等。

ESB可以多级实施,可以实现整个企业级/全国级的ESB,也可以实现部门级/地市级的ESB。服务消费者应该能在注册库中找到自己所需要的服务,获得调用该服务所需的位置、服务的描述文件、请求/相应消息格式等信息。若是没有注册库,则随着ESB接入的服务越来越多,仲裁逻辑不断增加,必将造成服务管理的混乱。最后抵消了ESB带来的价值。

复杂的动态路由规则应服务化

路由是ESB中非常重要的仲裁逻辑之一。路由场景是非常普遍的。譬如,针对不同的客户提供不同QoS的场景,执行时需根据客户的类型将其路由到不同执行能力的服务提供者;再比如当响应消息到达ESB时,总是需要将该响应消息送回最初的服务请求者处。

路由可分为静态路由和动态路由。静态路由指得是设计时已经明确路由分支的情况,而动态路由的路由分支选择是在运行时动态确定的。不论是静态路由还是动态路由,路由分支的选择一定伴随着一个或一系列决策依据。决策依据可简单如一个If-Else语句,也可以复杂到需要通过多维决策表并通过多次判断才能得到最后的路由分支。

对于复杂的路由,推荐将路由规则的逻辑外部化,并将它服务化,如图2所示。如此,仲裁逻辑在分发消息前可先访问该路由规则服务,从而得到明确的路由结果。至此,可能有人会问到,“复杂”与“简单”如何界定。这个问题没有统一的规定,根据笔者以往的实施经验,如果符合以下条件之一,就可以认为是复杂的路由规则:

  1. 判断维度大于等于2
  2. 连续决策节点大于等于3
  3. 路由分支可能随时增加或减少

图2. 动态路由规则服务化。

将复杂的动态路由规则服务化的好处简单明了。首先,让复杂的规则服务化,可以降低仲裁逻辑的变化性。当规则发生改变时,不需要修改仲裁逻辑,而只需更改规则服务即可。进一步,如果该规则服务是由某种专业的规则引擎实现的,更改起来将更加简单。其二,由于ESB产品的实现与设计并无业界的标准,所以基于ESB产品的配置开发无法在不同产品间互相移植。将规则服务化之后,还可减少仲裁逻辑在不同的ESB产品间移植时所需的工作量。最后,规则的服务化符合SOA原则,企业内业务规则应该以服务的形式管理起来,以促进规则的重用。

转换逻辑的实现尽量选用XSLT

数据转换也是仲裁逻辑中非常常见并且重要的功能。同一数据在不同的业务系统中表现方式可能不一样,如上文例子中的Client A访问服务WS1的情况,仲裁逻辑需要将XML消息转换为调用服务A的SOAP消息。

一般而言,大多数ESB产品都提供了多种数据转换的方式,很多产商宣传中力推的都是“拖拽式”可视化映射的转换方式。该功能听起来的确很酷,看上去很直观。但是正如我们前面所说的,ESB是一个偏向技术层整合的组件,业务人员一般不会关心XML是如何转换成SOAP的。所以,对于开发者来说,这种“炫”功能并无太大吸引力。更重要的是,他们可能非常习惯于自己的编程语言,如Java、XSLT、ESQL和PHP等,这些语言操作起来要简单很多。笔者本人就不太喜欢使用可视化隐射的方式去实现数据转换的需求,尤其碰到需要循环运行、复杂计算等转换逻辑时,在可视化映射上实现起来更加不容易。

在此,笔者推荐的方式是使用XSLT实现数据转换的功能,如图3所示。原因如下:首先,XSLT是一个标准的XML转换语言,使用XSLT实现的转换逻辑可很轻易地在不同ESB产品间移植。据笔者调查,几乎所有主流商业ESB产品都支持XSLT的转换机制。其二,选择XSLT还可增加ESB之上的架构灵活性。因为仲裁逻辑中的转换逻辑是最计算密集型的逻辑,它最消耗CPU,影响整体性能。在这种架构中,我们很容易地将此转换逻辑剥离出仲裁逻辑,由一些专门的XML转换加速软件/硬件(如IBM WebSphere DataPower)来完成这一工作。这样的设计可提高架构的灵活性,通过分布式计算的方式提高整体计算性能。

图3. XSLT实现数据转换逻辑及架构扩展

展望

在SOA架构中,ESB扮演的重要角色是毋庸置疑的。随着企业架构的不断演变和进化,ESB也不能一层不变。它只有与时俱进,才能顺应技术和思想的发展和进步。随着RESTful Web服务的兴起,SOAP服务不再是最受宠爱的标准;SOA架构也在不断突破企业防火墙,延伸到云计算的世界里。在这样的历史大环境下,ESB至少要需要以下向两个方向发展,才能在竞争中立于不败之地,否则就可能被新产品所替代。

首先,ESB需加强对RESTful Web服务的整合支持。RESTFul Web服务相比于SOAP服务有着简单、易学、易扩展等方面的优势。将RESTFul Web服务作为SOA的基础构建元素的呼声非常高。虽然不通过HTTP传输的服务无法转变成RESTFul服务,但是这种对RESTFul服务的呼声至少代表了人们向往简单的愿望。笔者认为这种趋势不可逆转,ESB产品必须加强对RESTFul服务的整合支持。譬如,可通过ESB将后台遗留的MQ应用的功能转变成一个RESTFul的服务,供RESTFul客户端访问。

其次,ESB需加强与SaaS云应用的整合支持。随着云计算的铺天盖地席卷而来,人们对云的认识越来越清晰,对云计算经济越来越认可,云端应用变得炙手可热。在SaaS应用越来越受到热门的欢迎同时,出于安全、性能、已投资资产等方面的原因,企业不可能将所有的数据/应用部署在云端,所以本地应用与云端SaaS应用之间的整合必将成为未来几年最热的集成需求,这就催生了笔者对ESB第二个方面的展望。

微服务理论之六:ESB与SOA的关系的更多相关文章

  1. 分析解剖微服务系列(二)-SOA和微服务异同

    微服务架构模式成熟之前,软件领域讨论的比较多的是SOA的架构模式.SOA早在1996年就由Gartner提出,作为面向服务的架构模式,SOA的理念是对于复杂的企业IT系统,按照不同的.可重用的粒度划分 ...

  2. ESB与SOA的关系

    ESB与SOA的关系 一.SOA和ESB一直是没有明确概念的两个缩略词 SOA----面向服务架构,实际上强调的是软件的一种架构,一种支撑软件运行的相对稳定的结构,表面含义如此,其实SOA是一种通过服 ...

  3. 微服务理论之五:微服务架构 vs. SOA架构

    一.面向服务的架构SOA 面向服务的架构是一种软件体系结构,应用程序的不同组件通过网络上的通信协议向其他组件提供服务.通信可以是简单的数据传递,也可以是两个或多个服务彼此协调连接.这些独特的服务执行一 ...

  4. 微服务理论之二:面向微服务架构与传统架构、SOA对比,以及云化对比

    一.Monolith 网上对Microservice进行介绍的文章常常以Monolith作为开头,我也不会例外.原因是,知道了Monolith的不便之后才能更容易地理解Microservice架构模式 ...

  5. 微服务理论之四:SOA

    1.什么是SOA? SOA代表了面向服务的架构. SOA是一种使用松耦合的黑盒子服务构建业务应用的体系架构,这些服务可以通过编排连接在一起以实现特定的功能. 2.SOA特点 以下是服务的SOA的主要特 ...

  6. 【微服务】之六:轻松搞定SpringCloud微服务-API网关zuul

    通过前面几篇文章的介绍,我们可以轻松搭建起来微服务体系中比较重要的几个基础构建服务.那么,在本篇博文中,我们重点讲解一下,如何将所有微服务的API同意对外暴露,这个就设计API网关的概念. 本系列教程 ...

  7. 【微服务理论】API + BFF

    对于微服务,常见的架构模型就是API网关+服务. API网关实现鉴权.负载均衡.中间件等公共入口逻辑. 服务实现具体的业务功能. 那么,API网关设计中又有什么坑呢? 1.0版本 直接将服务穿透到外网 ...

  8. 深入解读ESB与SOA的关系

    时至今日,SOA的概念渐渐清晰了.   有关ESB的概念,已经吵了好多年了,还是没有定论. 我个人认为,ESB本来就是抽象的概念,而且内涵丰富,在不同的场合含义不同.因此应该从不同的角度来认识.   ...

  9. 微服务下 Spring Boot Maven 工程依赖关系管理

    单体 Spring Boot Maven 工程 最基本的 pom.xml 包含工程信息.Spring Boot 父工程.属性配置.依赖包.构建插件 <?xml version="1.0 ...

随机推荐

  1. Django 之Ajax&Json&CORS&同源策略&Jsonp用法

    什么是Json 定义: JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式.它基于 ECMAScript (w3c制定的js规范)的一个子集 ...

  2. 基于flask的web微信

    web微信 1.扫码获取头像 当你打开web微信的时候,因为http是无状态的,web微信如何实时的获取用户的扫码动作? 那么这里用到的是长轮询的方式. from flask import Flask ...

  3. Linux安装Nginx使用负载均衡

    1.实验准备准备三台计算机 nginx1 192.168.13.121 作为nginx负载均衡器nginx2 192.168.13.24  web服务,提供一个页面        nginx3 192 ...

  4. table control里面各种属性和事件

    [转自]http://blog.csdn.net/hackai886/article/details/7935366 SAP中,Table Control是在Screen中用的最广泛的控件之一了,可以 ...

  5. 路由helper

    root_url http://192.168.1.110:3000/users/sign_up?inviter=14658733081530 root_path /users/sign_up?inv ...

  6. iOS tabbar 上面更换任意图

    tabbar 对add 上面的图片 有一层默认虚化 对于这种系统高度继承后的 控件 处理办法就是自定义 解决方案 1.放在tabbar 上的图片 不能太小 不然裁剪后 会很模糊 2 .通过裁剪 压缩的 ...

  7. 【转】kalman滤波

    Kalman Filter是一个高效的递归滤波器,它可以实现从一系列的噪声测量中,估 计动态系统的状态.广泛应用于包含Radar.计算机视觉在内的等工程应用领域,在控制理论和控制系统工程中也是一个非常 ...

  8. 每天一个Linux命令(36)ps命令

          Linux中的ps命令是Process Status的缩写.       ps命令用于报告当前系统的进程状态.可以搭配kill指令随时中断.删除不必要的程序.       (1)用法:   ...

  9. python中的id

    python对象都有三个特性分别是身份.类型.值,身份指该对象内存地址,内建函数id()可获得身份,类似于指针的地址,但不能控制这个值,类型决定对象可以保存什么类型的值,值是对象表示的数据项,pyth ...

  10. 【leetcode刷题笔记】Next Permutation

    Implement next permutation, which rearranges numbers into the lexicographically next greater permuta ...