1.内部实现细节暴露:修改小心,大量的回归测试
2.与技术绑定在一起:关系型数据库,可能将来用nosql
3.行为:同一个修改逻辑变了,很多地方都得修改

跨服务共享代码,会引入耦合。在服务内部不要违反DRY,但跨服务的情况下可以适当的违反DRY。

按引用访问。如果持有本地副本,可能用的时候,信息已经过时了。



1.寻找理想的集成技术
	1.避免破坏性修改
		对某个服务的一些修改不能导致该服务的消费方也随着发生改变。
	2.保证api的技术无关性
	3.使你的服务易于消费方使用
		消费方应该能很容易的使用我们的服务
	4.因此内部实现细节
		我们不希望消费方与服务的内部实现细节绑定在一起,这会增加耦合。与细节绑定意味着,如果想要改变服务内部的一些实现,
	  消费方就需要跟着做出修改。这也会导致为了避免消费方的修改而尽量少的对服务本身进行修改,而这会导致服务内部技术债的增加。
	  所以,所有倾向于暴露内部实现细节的技术都不应该被采用。

2.为用户创建接口

3.共享数据库
	首先,这使得外部系统能够查看内部实现细节,并与其绑定在一起。存储在数据库中的数据结构对所有人来说是平等的,所有服务都可以完全
  访问该数据库。如果我决定为了更好的表示数据或者增加可维护性而修改表结构的话,我的消费方就无法进行工作了。数据库是一个很大的共享
  API,但同时也非常不稳定。为了不影响其他服务,我必须非常小心的避免修改与其他服务相关的表结构。这种情况下,通常需要做大量的回归
  测试来保证功能的正确性。
    其次,消费方与特定的技术选择绑定再了一起。可能现在看来,使用关系型数据库做存储是合理的,所以我的消费方会使用一个合适的驱动来
  与之一起工作。说不定过段时间之后我们意识到,使用非关系型数据库才是更好的选择。如果消费方和客户服务非常紧密的绑定在了一起,那么
  就不能轻易替换这个数据库。隐藏实现细节非常重要,因为它让我们的服务拥有一定的自治性,从而可以轻易的修改内部实现。
    最后,让我们考虑下行为。肯定会有一部分逻辑负责对客户端进行修改。那么这个逻辑应该放在哪里?如果消费方直接操作数据库,那么它都
  需要对这些逻辑负责。对数据库进行操作的相似逻辑可能会出现在很多服务中。如果修改参考,注册用户界面,呼叫中心都需要编辑客户的信息,
  那么当修复一个bug的时候,你需要修改3个地方,并且对这些修改分别部署。
  	好的微服务的核心是,高内聚和低耦合。但是使用数据库集成使得这两者都很难实现。服务之间很容易通过数据库集成来共享数据,但是无法共享
  行为。内部表示暴露给了我们的消费方,而且很难做到无破坏性的修改,进而不可避免的导致不敢做任何修改,所以无论如何都要避免这种情况。

4.同步与异步
	服务如何协同?服务之间的通信应该是同步还是异步的呢?这个基础性的选择会不可避免的引导我们使用不同的实现。
	如果使用同步通信,发起一个远程服务调用后,调用方会阻塞自己并等待整个操作的完成。如果使用异步通信,调用方不用等待操作完成就可以返回,
  甚至不需要关心这个操作完成与否。
    同步通信听起来合理,因为可以知道事情到底成功没有。异步通信对于运行时间长的任务来说比较有用,否则就需要在客户端和服务器之间开启一个
  长连接,这是非常不实际的。当你需要低延迟的时候,通常会使用异步通信,否则会由于阻塞而降低运行的速度。对于移动网络及设备而言,发送一个
  请求后假设一切工作正常,这种方式可以在很大程度上保证网络很卡的情况下用户界面依然流畅。另一方面,处理异步通信的技术相对比较复杂。
    这两种不同的通信方式有着各自的协作风格,即请求/响应或者基于事件。对于请求/响应来说,客户端发起一个请求,然后等待响应。这种模式能够
  与同步通信模式很好的匹配,但异步通信也可以使用这种模式。我发起一个请求,然后注册一个回调,当服务端操作结束之后,会调用该回调。
    对于基于事件的协作方式来说,情况会颠倒过来。客户端不是发起请求,而是发布一个事件,然后期待其他的协作者接收到该消息,并且知道怎么做。
  我们从来不会告知任何人去做任何事情。基于事件的系统天生就是异步的。整个系统都很聪明,也就是说,业务逻辑并非集中于某个大脑,而是平均的
  分布在不同的协作者中。基于事件的协作方式耦合性很低。客户端发布一个事件,但并不需要知道谁或者什么会对此做出响应,这也意味着,你可以在
  不影响客户端的情况下对该事件添加新的订阅者。
    哪些因素会影响对这2种风格的选择呢?一个重要的因素是这种风格是否能很好的解决负责问题,比如如何处理跨服务边界的流程,而且这种流程
  有可能会运行很长时间。

5.编排与协同
	在开始对越来越复杂的逻辑进行建模的时候,我们需要处理跨服务业务流程问题,而使用微服务时这个问题会来的更快。
	当考虑具体实现时,有2种架构风格可以采用。使用编排的话,我们会依赖于某个中心大脑来指导并驱动整个流程。使用协同的话,我们仅仅会告诉
  系统中各个部分各自的责任,而把具体怎么做的细节留给它们自己。
    编排的解决方案:可能最简单的方式就是让客户服务作为大脑。在创建时它会跟积分账户,电子邮件服务以及邮政服务通过请求/响应的方式进行通信,
  客户服务本身可以对当前进行到了哪一步进行跟踪。它会检查客户账户是否创建成功,电子邮件是否发出去以及邮件包裹是否寄出。
    编排的缺点是:客户服务作为中心控制点承担了太多职责,它会成为网状结构的中心枢纽以及很多逻辑的起点。
    如果使用协同,可以仅仅从客户服务中使用一个异步的方式触发一个事件,该事件的名字可以叫做 '客户创建'。电子邮件服务,邮政服务以及积分账户
  可以简单的订阅这个事件并且做相应处理。这种方法能够显著的消除耦合。如果其他服务也关心客户创建这个事情,它可以简单的订阅该事件即可。
    缺点是没有很明显的业务流程。这意味着,需要做一些额外的工作来监控流程,以保证其正确执行。处理该问题的一种方法是,构建一个业务流程相匹配的
  监控系统。实际的监控活动是针对每个服务的,但最终需要把监控的结果映射到业务流程中。
    通常来说,使用协同的方式可以降低系统的耦合度,并且能更加灵活的对现有的系统进行修改。但是,确实需要额外的工作来对业务流程做跨服务的监控。
  大多数的编排方案都非常不稳定且修改代价很大。
    同步调用比较简单,而且很容易知道整个流程的工作是否正常。如果想要请求/相应风格的语义,又想避免在耗时业务上的困境,可以采用异步请求加回调
  的方式。另一方面,使用异步方式有利于协同方案的实施,从而大大减少服务间的耦合,这恰恰就是我们为了能够独立发布服务而追求的特性。 
    针对请求/相应方式,可以考虑两种技术:RPC,REST。

6.远程过程调用
	远程过程调用允许你进行一个本地调用,但事实上结果是由某个远程服务器产生的。RPC的种类繁多,其中一些依赖接口定义(SOAP,Thrift,protocol buffers)
  等。不同的技术栈可以通过接口定义轻松生成客户端和服务端的桩代码。
    有很多技术本质上是二进制的,比如 Java RMI,Thrift,protoco buffers 等,而 SOAP 使用 XML 作为消息格式。有些RPC实现与特定的网络协议绑定(比如
  SOAP 名义上使用的就是 HTTP),当然不同的实现会使用不同的协议,不同的协议可以提供不同的额外特性。tcp 能够保证送达,udp 虽然不能保证送达,但协议开销
  比较小。
    那些 RPC 的实现会帮助你生成服务端和客户端的桩代码,从而让你快速开始编码。这也是 RPC 的卖点之一。

    1.技术的耦合
    	有些rpc机制,如 Java RMI 与特定的平台紧密绑定,这对于服务端和客户端的技术选型造成了一定的限制。Thrift 和 protocol buffers 对于不同的语言支持
      很好。但还是要注意,有时候rpc技术对于互操作性有一定的限制。从某种程度上来说,这种技术的耦合也是暴露内部实现细节的一种方式。

    2.本地调用和远程调用并不相同	
    	rpc 的核心想法是隐藏远程调用的复杂性。但是很多 rpc 的实现隐藏的有些过头了。使用本地调用不会引起性能问题,但是 rpc 会花费大量的时间对负荷进行封装和
      解封装,更别提网络通信所需要的时间。这意味着,要使用不同的思路来设计远程和本地API。

    3.脆弱性
    	对规格说明进行了修改,所以所有的客户端都需要重新生成桩,无论该客户端是否需要这个新方法。对每一个具体的点来说,这种修改还是可控的,但是事实上这种修改
      非常普遍。rpc 接口最后通常都会包含很多与对象进行交互或者创建对象的方法。造成这种后果的一部分原因就是,没有意识到现在是在做远程调用,而非本地调用。
        另外,比如在对象中的年龄字段完全没有任何消费者使用,你可能先删除。但如果单单从服务端实现删除年龄,而客户端没有相应修改的话,那么及时它们从来没有用过
      这个字段,客户端中的和 Customer 对象反序列化相关的代码还是会出问题。所以为了应用这些修改,需要同时对服务端和客户端进行部署。这就是任何使用二进制桩
      diamante生成机制的 rpc 所要面临的挑战:客户端和服务端的部署是无法分离的。调整字段也是。 

    4.RPC 很糟糕吗
    	如果使用 rpc 需要注意:不要对远程调用过度抽象,以至于网络因素完全被隐藏起来;确保你可以独立的升级服务端的接口而不用强迫客户端升级,所以在编写客户端代码
      时需要注意这方面的平衡;在客户端中一定不要隐藏我们是在做网络调用这个事实。在 rpc 的方式中经常会在客户端使用库,但是如果这些库在结构上组织的不够好,也可能带
      来一些问题。
        rpc 是请求/响应协作方式中的一种,相比使用数据库做集成,rpc 显然是一个巨大的进步。

7.REST
	rest 我受web 启发而产生的一种架构风格。rest 风格包含了很多原则和限制,但是这里我们仅仅专注于,如何在微服务的世界里使用 rest 更好的解决集成问题。rest
  是 rpc 的一种替代方案。
  	其中最重要的一点是资源的概念。一个资源的对外显示方式和内部尺寸方式之间没有什么耦合。
  	rest 本身并没有提到底层应该使用什么协议,尽管事实上都是http。http 的一些特性,比如动词,使得在 http 之上实现 rest 要简单的多。

  	1.rest 和 http
  		http 本身提供了很多功能,这些功能对于实现 rest 风格非常有用。比如 http 的动词(get,post,put)就能够很好地和资源一起使用。事实上,rest 架构风格声明
  	  了一组对所有资源的标准方法,而 http 恰好也定义了一组方法可供使用。get 使用幂等的方式获取资源,post 创建一个新资源。这就意味着,我们可以避免很多不同版本的
  	  createCustomer 和 editCustomer 方法。从概念上来说,对于一个 Customer 资源,访问接口只有一个,但是可以通过 http 协议的不同动词对其进行不同的操作。
  	    需要注意的是,http 也可以用来实现 rpc.比如 soap 就是基于 http 进行路由的,但不幸的是它只用到 http 很少的特性,而动词和 http 的错误码都被忽略了。

  	2.超媒体作为程序状态的引擎
  		rest 引入的用来避免客户端和服务端之间产生耦合的另外一个原则是 "HATEOAS"(超媒体作为程序状态的引擎)。
  		超媒体的概念是:有一块内容,该内容包含了指向其他内容的链接,而这些内容的格式可以不同(如文本,图像,声音等)。客户端应该与服务端通过那些指向其他资源的链接进行
  	  交互,而这些交互有可能造成状态转移。它不需要知道 Customer 在服务端的 URI,相反客户端根据链接导航到它想要的东西。
  	    考虑 Amazon.com 这个站点,随着时间的推移,购物车的位置,图像,链接都有可能发生变化,但是人类足够聪明,你还是能够找到它。无论确切的形式和底层使用的空间发生
  	  怎样的修改,我们仍然很清楚如果你想要浏览购物车的话,应该去点哪个按钮。这就是为什么在网页上可以做出一些增量修改,只要这些客户和站点之间的隐式约定仍然满足,这些
  	  修改就不会破坏站点的功能。

  	  	客户端也需要理解该 API 的语义。作为一个客户端,我不需要知道购买专辑的 URI,只需要访问专辑资源,找到其购买链接,然后访问它就可以了。购买链接的位置可能会发生改变,
  	  URI 也可能会变,该站点甚至会发生额外的信息,但是作为客户端不用在意这些。这就使得客户端和服务端之间实现了松耦合。
  	    这样底层细节就被很好的隐藏起来了。我们可以随意的改变链接的展现形式,只要客户端仍然能够通过特定的协议找到它即可。类似的,购物车也可以从一个简单的连接变成一个复杂的
  	  一些的 JS 控件。你也可以随意向文档中添加新的链接,从而给客户端提供对资源状态的额外操作。除非我们改变某个链接的语义或者删除该链接,否则客户端不会受到影响。
  	    使用这些链接来对客户端和服务端进行解耦,从长期看是有显著好处的,因为你不需要一再调整客户端代码来匹配服务端的修改。通过使用这些链接,客户端能够自行获取相关API,
  	  这对于实现新客户端来说非常方便。
  	    缺点是:客户端和服务端之间的通信次数比较多,因为客户端需要不断发现链接,请求,再发现链接,直到找到自己想要进行的那个操作。

  	3.JSON, XML 还是其他
  		由于服务端使用标准文本形式的响应,所以客户端可以很灵活的对资源进行使用,而基于 http 的 rest 能够提供多种不同的响应形式。
  		json 的内容更加紧凑。但也有缺点。xml 使用链接来进行超媒体控制,json 标准中并没有类似的东西,所以出现了很多不同的自定义的方式在 json 中进行超媒体控制。
  	  HAL(hypertext application language,超文本应用语言) 试图为 json 定义通用的超文本标准格式。如果你遵守 HAL 的标准,就可以使用基于 web 的 HAL 浏览器
  	  来使用超媒体控制,这会使得创建客户端简单很多.
  	    当然并不是说只有这2种形式。通过 http 我们可以发送任何格式,甚至二进制的。我们看到越来越多的人直接使用html,而非 xml。对于有些接口来说,htl 既可以做ui,
  	  也可以做 api。

  	4.留心过多的约定
  		 我们很容易把存储的数据直接暴露给消费者,那么如何避免?一个有效的模式是先设计外部接口,等到外部接口稳定之后再实现微服务内部的数据持久化。在此期间,可以简单
  	  的将实体持久化到本地磁盘的文件上。这样并非长久之计,这样做可以保证服务的接口是由消费者的需求驱动出来的,从而避免数据存储方式对外部接口的影响。其缺点是推迟了
  	  数据存储部分的集成。

  	5.基于 http 的 rest 的缺点
  		从易用性角度来看,基于http的rest无法帮助你生成客户端的桩代码,而 rpc 可以。没错,使用 http 意味着有很多很棒的http客户端可供使用,但是如果你想要在客户端中实现
  	  并使用超媒体控制的话,就基本靠自己了。库会增加复杂程度,在客户端和服务端之间共享代码是非常危险的。
  	    有些web框架无法很好的支持所有的 http 动词。所有框架选择上有所限制了。
  	    性能上也会遇到问题。基于 http 的rest 支持不同的格式,比如 json或者二进制,所以负载相对SOAP来说更加紧凑,当然和 Thrift 这样的二进制协议是无法比的。在要求低延迟
  	  的场景下,每个http请求的封装开销可能是个问题。
  	    虽然http可以用于大流量的通信场景,但对于低延迟的通信来说并不是很好的选择。相比之下,有一些构建于 TCP或者其他网络技术之上的协议更加高效。比如 websockets。在初始
  	  的 http 握手之后,客户端和服务端之间仅仅通过 tcp 链接了。
  	  	对于服务和服务之间的通信来说,如果低延迟和较小的消息尺寸对你来说很重要,那么http不是一个好主意。你可能需要选择一个不同的底层协议,比如 udp来满足你的性能要求。很多
  	  rpc 框架都可以很好的运行在除了tcp之外的其他网络协议上。
  	    有些 rpc的实现支持高级的序列化和反序列化的机制,然后对于 rest 而言,这部分工作要自己做了。这部分工作可能会成为服务端和客户端之间的一个耦合点,因为实现一个具有容错性
  	  的读取器不是一件容易的事情,但是从快速启动的角度来看,它们还是有吸引力的。

8.实现基于事件的异步协作方式
	1.技术选择
		主要有2个部分需要考虑:微服务发布事件机制和消费者接收事件机制。
		传统上来说,像 rabbitMQ 这样的消息代理能够处理上述2个问题。生产者使用 api 向带来发布事件,带来也可以向消费者提供订阅服务,并且在事件发生时通知消费者。这种带来甚至可以
	  追踪消费者的状态,比如标记哪些消息是该消费者已经消费国的。这样的系统具有较好的可伸缩性和弹性。但是这么做也是有代价的,它会增加开发流程的复杂度,因为你需要一个额外的系统才能
	  开发和测试服务。你也需要额外的机器和专业的知识维护这些基础设施。一旦做好了,它会是实现松耦合。
	    不过需要注意的是,消息代理仅仅是中间件世界中的一小部分。队列本身很合理有用,但是中间件厂商通常倾向于把很多软件打包进去,比如企业级服务总线。谨记一个原则:尽量让中间件
	  保持简单,而把业务逻辑放在自己的服务中。
	  	另外一种方法是使用 http 来传播事件。ATOM 是一个符合 rest 规范的协议,可以通过它提供资源聚合(feed)的发布服务,而且有很多现场的客户端库可以用来消费
	  该聚合。这样当客户端发生改变时,只需要简单的向该聚合发布一个事件即可。消费者会轮询该聚合以查看变化。另外一方面,现成的 ATOM 规范和与之相关的库用起来非常
	  方便,而且 http 能够很好的处理伸缩性。正如前面提到的,http 不擅长处理低延迟的场景,而且使用 ATOM 的话,用户还需要自己追踪消息是否送达以及管理轮询的工作。

	2.异步架构的复杂性
		复杂性并不仅仅包括对消息的发布订阅操作,对于习惯了进程间同步调用的程序员来说,使用异步模式也需要思维上的转换。
		事件驱动架构和异步编程会带来一定的复杂性,你需要确保各个流程有很好的监控机制,并考虑关联的ID,这种机制可以帮助你对跨进程请求进行追踪。

9.服务即状态机
	当消费者想要对客户做修改的时候,它会向客户服务发送一个合适的请求。客户服务根据自己的逻辑决定是否接受该请求。客户服务控制了所有与客户生命周期相关的事件。
  把关键领域的生命周期显式建模出来非常有用。

10.响应式扩展
	响应式扩展提供了一种机制,在此之上,你可以把多个调用的结果组装起来并在此基础上执行操作。调用本身可以是阻塞或者非阻塞的。

11.微服务世界中的DRY和代码重用的危险
	DRY : Don't Repeat Yourself,避免系统行为和知识重复。一般来讲这是合理的建议。如果有相同的代码来做同样的事情,代码规模就会变大,从而降低可维护性。
	但是这个方法在微服务的架构中可能是危险的。我们想要避免微服务和消费者之间的过度耦合,否则对微服务的任何小的改动都会引起消费方的改动。而共享代码就可能
  会导致这种耦合。当任何地方对共享库修改时,都会引起其他部分的重新部署。
    跨服务共享代码很可能会引入耦合。不在服务之间公用代码,而是把这些代码复制到每个服务中,以防止耦合发生。
    在微服务内部不要违反 DRY,但在跨服务的情况下可以适当违反 DRY。服务之间引入大量耦合会比重复代码带来更糟糕的问题。

    客户端库:
    	如果你想要使用客户端库,一定要保证其中只包含处理底层传输协议的代码,比如服务发现和故障处理等。千万不要把与目标服务相关的
      逻辑放到客户端库中。最后,确保由客户端来负责何时进行客户端库的升级,这样才能保证每个服务可以独立于其他服务进行发布。

12.按引用访问
	微服务应该包含核心领域实体(比如客户)全生命周期的相关操作。如果想要做任何与客户相关的改动,就必须向客户服务发起请求。它遵守了一个原则,即客户服务应该是
  关于客户信息的唯一可靠来源。
  	有时候使用本地副本没什么问题,但在其他场景下你需要知道该副本是否已经失效了。所以当你持有一个本地副本时,请确保同时有一个指向原始资源的引用。
  	举个例子:发货后需要请求邮件服务发送一封邮件。一种做法是,把客户的邮件地址,姓名,订单信息等发送到邮件服务器。但是邮件服务器可能将这个请求放到队列中,
  然后在将来的某个时刻再取出来。在这个时间差中,客户和订单信息可能发生了变化。更合理的方式是,仅仅发送表示客户资源和订单资源的URI,然后等邮件服务器就绪时
  再回过头来查询这些信息。

13.版本管理
	1.尽可能推迟
		减小破坏性修改影响的最好办法就是尽量不要这样做这样的修改。数据库集成很容易引入破坏性的修改,然后 rest 就好很多,因为对于内部实现的修改不太容易引起服务接口的变化。
		另外一个延迟破坏性修改的关键是鼓励客户端的正确行为,避免过早的将客户端和服务端紧密绑定在一起。
		鲁棒性原则:系统中的每个模块都应该 '宽进严出',即对自己发送的东西要严格,对接收的东西要宽容。
	2.及早发现破坏性修改
		及早发现会对消费者产生破坏性的修改非常重要。强烈建议使用消费者驱动的契约来及早定位这些问题。
	3.使用语义化的版本管理
		如果一个客户端能够仅仅通过查看服务的版本号,就知道它是否能够与之进行集成,那就太好了。语义化版本管理就是一种能够支持这种方式的规格说明。
		语义化版本管理的每一个版本号都遵循这样的格式: major.minor.patch。其中,major 的改变意味着其中包含向后不兼容的修改;minor 的修改
	  意味着有新功能的增加,但应该是向后兼容的;最后,patch 的改变以文化则对已有功能的缺陷修复。
	4.不同的接口共存
		如果已经做了所有事情来避免对接口的修改,那么下一步的任务就是限制其影响。我们不想强迫客户端跟随服务端一起升级,因为希望微服务可以独立于彼此进行发布。
	  可以在同一个服务商使用新老接口同时存在。所以在发布一个破坏性修改时,可以部署一个同时包含新老接口的版本。
	  	对于使用 http 的系统,可以在请求中添加版本信息,也可以将其添加在 URI 中,比如 /v1/constomer 和 /v2/customer
	5.同时使用多个版本的服务
		另外一种版本管理的方法是,同时运行不同版本的服务,然后把老用户路由到老版本服务,而新用户可以看到新版本的服务。

14.用户界面
	1.走向数字化
		很多组织认为,不应该对网页端和移动端区别对待,相反应该对数字化策略做全局考虑。
	2.约束
		在用户与系统之间,需要考虑不同的交互形式中存在的一些约束。
	3.API 组合
	4.UI 片段的组合
		相比UI主动访问所有的 api,然后再将状态同步到UI控件,另外一种选择是让服务直接暴露一部分UI,然后只需要简单的把这些片段组合一起就可以创建出整体UI。
	  这种方式有一个工作的很好的变种,即将一系列粗粒度的UI部分组装起来。也就是说不创建小部件,而是对胖客户端应用的所有内容或一个网站的所有页面进行组装。
	    这些粗粒度的片段由服务端程序提供,而这些程序又会去调用相关的api。这种方式的一个关键优势是,修改服务团队的同时可以维护这些UI片段。
	    但保证用户体验的一致性很重要。
	    原生应用和胖客户端无法消费服务端提供的UI组件。一种解决方法是,使用混合方式在原生应用中嵌入html来重用一些服务端组件,但这种方式会使用户体验欠佳。
	  如果你需要的是原生应用的体验,就必须自己对 API 进行请求,然后在本地创建和管理UI。
	5.为前端服务的后端
		对与后端交互比较频繁的界面以及需要给不同设备提供不同内容的界面来说,一个场景的解决方案是,使用服务端的聚合接口或api入口。该入口可以对多个后端进行
	  调用编排,并为不同的设备提供定制化的内容。
	    最好一个后端职位一个应用或者用户界面服务。这种模式也叫做BFF(backends for frontedns,为前端服务的后端)。
	6.一种混合的方式
		一些组织会选择基于片段组装的方式来构建网站,但对于移动端来说,BFF可能是更好的方式。关键是要保持底层服务能力的内聚性。

15.与第三方软件集成

 

集成 :

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile

微服务集成dockerfile 微服务集成方案_服务端_02

微服务集成dockerfile 微服务集成方案_客户端_03

微服务集成dockerfile 微服务集成方案_微服务_04

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_05

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_06

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_07

微服务集成dockerfile 微服务集成方案_服务端_08

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_09

微服务集成dockerfile 微服务集成方案_客户端_10

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_11

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_12

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_13

微服务集成dockerfile 微服务集成方案_客户端_14

微服务集成dockerfile 微服务集成方案_服务端_15

 

微服务集成dockerfile 微服务集成方案_客户端_16

微服务集成dockerfile 微服务集成方案_客户端_17

微服务集成dockerfile 微服务集成方案_服务端_18

微服务集成dockerfile 微服务集成方案_服务端_19

微服务集成dockerfile 微服务集成方案_服务端_20

微服务集成dockerfile 微服务集成方案_客户端_21

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_22

微服务集成dockerfile 微服务集成方案_服务端_23

微服务集成dockerfile 微服务集成方案_微服务_24

微服务集成dockerfile 微服务集成方案_客户端_25

微服务集成dockerfile 微服务集成方案_微服务_26

微服务集成dockerfile 微服务集成方案_微服务_27

微服务集成dockerfile 微服务集成方案_服务端_28

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_29

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_30

微服务集成dockerfile 微服务集成方案_服务端_31

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_32

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_33

微服务集成dockerfile 微服务集成方案_客户端_34

微服务集成dockerfile 微服务集成方案_微服务_35

微服务集成dockerfile 微服务集成方案_服务端_36

微服务集成dockerfile 微服务集成方案_客户端_37

微服务集成dockerfile 微服务集成方案_客户端_38

微服务集成dockerfile 微服务集成方案_客户端_39

微服务集成dockerfile 微服务集成方案_客户端_40

微服务集成dockerfile 微服务集成方案_客户端_41

微服务集成dockerfile 微服务集成方案_客户端_42

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_43

微服务集成dockerfile 微服务集成方案_客户端_44

微服务集成dockerfile 微服务集成方案_微服务_45

微服务集成dockerfile 微服务集成方案_客户端_46

微服务集成dockerfile 微服务集成方案_客户端_47

微服务集成dockerfile 微服务集成方案_微服务_48

微服务集成dockerfile 微服务集成方案_客户端_49

微服务集成dockerfile 微服务集成方案_客户端_50

微服务集成dockerfile 微服务集成方案_服务端_51

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_52

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_53

微服务集成dockerfile 微服务集成方案_客户端_54

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_55

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_56

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_57

微服务集成dockerfile 微服务集成方案_服务端_58

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_59

微服务集成dockerfile 微服务集成方案_微服务_60

微服务集成dockerfile 微服务集成方案_服务端_61

微服务集成dockerfile 微服务集成方案_客户端_62

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_63

微服务集成dockerfile 微服务集成方案_微服务_64

微服务集成dockerfile 微服务集成方案_微服务_65

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_66

微服务集成dockerfile 微服务集成方案_客户端_67

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_68

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_69

微服务集成dockerfile 微服务集成方案_服务端_70

 

微服务集成dockerfile 微服务集成方案_客户端_71

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_72

微服务集成dockerfile 微服务集成方案_客户端_73

微服务集成dockerfile 微服务集成方案_微服务_74

微服务集成dockerfile 微服务集成方案_服务端_75

微服务集成dockerfile 微服务集成方案_客户端_76

微服务集成dockerfile 微服务集成方案_客户端_77

微服务集成dockerfile 微服务集成方案_客户端_78

微服务集成dockerfile 微服务集成方案_微服务集成dockerfile_79

微服务集成dockerfile 微服务集成方案_服务端_80