面试——一个你必须知道和知道的微服面试问题

SOA和微服务有什么区别?

SOA是在企业计算领域提出的,就是将紧耦合的系统划分为面向业务的、粗粒度的、松耦合的、无状态的服务。服务发布出来供其他服务调用,一组相互依赖的服务构成了SOA架构下的系统。

基于这些基础服务,可以采用类似BPEL流程的方式安排业务流程,BPEL体现了业务处理的流程,比硬编码的代码更直观,更容易调整。

当然,企业还需要管理服务,比如服务注册、监控和管理。

我们知道在企业计算领域,如果不是交易系统,并发不是很大,所以大多数情况下,一个服务器会容纳很多服务,这些服务采用统一的基础架构,可能都运行在一个应用服务器的进程中。虽然它是面向服务的,但它仍然是一个单一的系统。

微服务架构一般兴起于互联网企业。由于用户规模大,对分布式系统的要求非常高。如果像企业计算这样的系统是可伸缩的,那么它需要容纳大量服务的多个系统实例。在它面前,多个系统通过负载均衡成为一个集群。但是,这样很不方便。互联网企业的迭代周期很短。可能每周发布一个版本,甚至每天发布一个版本,不同子系统的发布周期不一样。而且不同的子系统不像原来的企业计算那样使用集中存储,使用昂贵的Oracle来存储整个系统的数据。第二,他们使用MongoDB、HBase、Cassandra等NOSQL数据库和Redis、memcache等分布式缓存。然后倾向于分成子系统,不同的子系统采用各自的架构。那么当每个服务运行在自己的Web容器中,需要增加计算能力的时候,只需要增加这个子系统或者服务的实例,升级的时候可以不影响其他子系统。这种组织一般称为微服务架构。

与SOA相比,微服务更强调分布式系统的特性,如横向可扩展性、服务发现、负载均衡、故障转移和高可用性。互联网发展对服务治理提出了更多的要求,比如多版本,比如灰度升级,比如服务降级,比如分布式跟踪,这些在SOA实践中都没有得到足够的重视。

Docker容器技术的出现为微服务提供了更便利的条件,比如更小的部署单元,每个服务都可以通过Node.js或者Spring Boot这样的技术在自己的进程中运行。可能有数千个Docker容器在几十台计算机上运行,每个容器运行一个服务实例。您可以随时增加服务实例的数量,或者在实例崩溃后在其他计算机上创建新的服务实例。

如何拆分服务?

对业务模块进行拆分,拆分的粒度要保证微服务具有业务的独立性和完整性,服务依赖和链调用尽量少。但是在实际的开发过程中,有时候单一的架构更适合当前的项目。其实微服务的设计不是一蹴而就的,是一个设计和反馈的过程。因此,在设计之初,我们可以将服务的粒度设计得更大,并考虑其可扩展性。随着业务的发展,动态拆分也是不错的选择。

以休息为名,省略主语。“表示层”其实指的是“资源”的“表示层”。

所谓“资源”就是网络上的一个实体,或者说是网络上的一个具体信息。可以是一段文字,一张图片,一首歌,一项服务,总之是具体的现实。你可以用一个URI(统一资源定位符)指向它,每个资源对应一个特定的URI。要获得这个资源,只需访问它的URI,这样URI就成为每个资源的地址或唯一标识符。

客户端使用的手段只能是HTTP协议。具体来说,在HTTP协议中,有四个动词表示操作模式:GET、POST、PUT和DELETE。它们对应四种基本操作:GET用于获取资源,POST用于创建新资源(或更新资源),PUT用于更新资源,DELETE用于删除资源。

事实上,并不是所有的东西都是“资源”,尤其是在商业系统中。缺点如下:

有一个更新订单状态的界面。上面用的是哪个?好像应该放,但是路径是PUT /tickets/12。

我有时会有多个界面来更新订单收款状态、订单付款状态和订单结算状态;

Restful的路径明显不友好,不够;

再举个例子,如果要传递一个DELETE/tickets/12 # DELETE tice kt 12形式的数组怎么办?是网址不够友好吗?

再比如,Resuful需要GET /tickets #来获取票单。我们曾经有一个需求,对方发给我们的订单id不超过1000,我们的系统过滤了一些特殊订单;这也是一个查询服务。以GET /tickets #的形式获取票单,1000的订单id明显超过了GET url的长度,这里不合适。再者,我想开发多个条件查询列表服务,这么浅的路径显然不合适;

在实际业务中,我们的webapi的路径如下:systemAlias/controller/action。

总结规则:

简单查询尽量用GET,好处是可以直接带查询参数复制api路径;

POST用于复杂的查询和更新,使用最多;

不要使用PUT和DELETE,因为它增加了复杂性,没有带来任何好处。

看BAT的很多openapi,上面也说restful,但是没有严格遵守。都是get和post,这也是很多人不知道put和delete的原因。

比如:

//根据订单id获取订单。

获取oms/order/queryOrderById?id=value1。param2 =值2

//根据订单id列表获取订单。

发布OMS/订单/queryOrderByIdList

//根据条件查询订单,带分页参数。

过帐OMS/订单/查询订单条件

//更新订单收款状态

发布OMS/order/updateOrderCollectionStatus

//批量更新订单收款状态

发布OMS/order/updateOrderCollectionStatusInBatch

//批量更新订单收款状态

发布OMS/order/updateOrderCollectionStatusInBatch

//批量删除有工序来源的订单。

发布oms/order/deleteOrderInBatch

微服务如何管理数据库?

上限原理(上限定理)

在足球比赛中,一名球员在一场比赛中进三个球,这被称为帽子戏法。在分布式数据系统中,也有一个帽子定理,但这个帽子不是另一个帽子。CAP原则有三个要素:

CAP原则是指这三个要素最多只能同时做到两点,不可能三者兼顾。

因此,在设计分布式架构时,必须进行权衡。对于分布式数据系统来说,分区容忍度是基本要求,否则就会失去价值,所以分布式数据系统的设计就是要在一致性和可用性之间取得平衡。

对于大多数WEB应用来说,一致性不是必须的,所以牺牲一致性换取高可用性是目前大多数分布式数据库产品的方向。

当然,牺牲一致性并不是完全忽略数据的一致性,否则数据就是混乱的,然后系统可用性再高再分布式。

牺牲一致性意味着不再需要关系数据库中的强一致性,只要系统能够达到最终的一致性即可。考虑到客户体验,这个最终一致的时间窗口要尽可能对用户透明,也就是要保证“用户感知的一致性”。

通常,系统的高可用性和数据的最终一致性是通过数据的多个异步副本来实现的,而“用户感知的一致性”的时间窗口取决于数据被复制到一致状态的时间。

最终一致

一致性可以分为两个不同的角度:客户端和服务器端。

从客户端的角度来看,一致性主要是指在多个并发访问时如何获取更新数据的问题。

从服务器的角度来说,就是更新如何复制分发到整个系统,保证数据最终的一致性。

一致性是因为并发读写而产生的问题,所以在理解一致性的问题时,一定要注意考虑并发读写的场景。

从客户端的角度来看,当多个进程并发访问时,不同进程如何获取更新数据的不同策略决定了不同的一致性。

对于关系数据库,要求更新后的数据能被后续访问看到,这是强一致性;如果你能容忍部分或全部后续访问不可用,那就是弱一致性;如果一段时间后需要访问更新的数据,这就是最终一致性。

从服务器的角度来看,如何将更新后的数据尽快分发到整个系统,减少时间窗口达到最终的一致性,是提高系统可用性和用户体验的一个非常重要的方面。

那么问题来了,如何实现数据的最终一致性?答案在于事件驱动的架构。

最好的解决方案是采用事件驱动的架构。挑战之一是如何自动更新状态和发布事件。有几种方法可以解决这个问题,包括将数据库视为消息队列和事件源。

从目前技术的应用范围和成熟度来看,推荐使用第一种方法(本地事务发布事件)实现事件交付的原子化,即可靠的事件交付。

SpringCloud和Dubbo有什么区别?

总的来说,两者各有优势。后者虽然服务于调用的功能,但也避免了上面提到的原生RPC带来的问题。而且REST比RPC更灵活,服务提供者和调用者的依赖只依赖于一纸契约,没有代码级的依赖,在强调微服务快速进化的背景下更合适。

品牌机和组装机的区别:很明显SpringCloud比dubbo更强大,覆盖面更广,可以和其他Spring项目如SpringFramework、SpringBoot、SpringData、SpringBatch完美融合,这些对于微服务来说都是非常重要的。用Dubbo搭建的微服务架构就像组装一台电脑,每个环节我们都有很高的自由度,但可能总会因为内存质量影响整体,但对于专家来说不是问题。SpringCloud就像一台品牌机器。在弹簧源的整合下,做了大量的兼容性测试,保证了机器更高的稳定性。

当面对微服务基础设施的选择时,Dubbo和SpringCloud只能二选一。