dubbo三

九、最佳实践
分布式应用和单体应用的主要区别是本地调用和远程调用,解决的主要问题都是和远程调用相关。首先,远程调用的性能差于本地调用;其次,远程调用受网络状况影响,有一定的失败率,框架和应用需要对失败进行处理;再次,分布式场景下,事务控制会变得及其复杂;第四,分布式调用和调用本地API的不同。
远程调用的性能:远程调用的复杂性和流程远超本地调用,包括序列化反序列化,网络传输,反射调用等重量级开销。要保证高性能,除了框架自身之外,应用的实现也应该尽可能高性能话,最佳实践包括:1、尽可能异步或并行化服务调用,提高服务吞吐量,降低服务调用时延,或者使次要事件不影响响应时间;2、减小调用传输量,包括dubbo在内的很多分部式服务框架在服务的消费者和提供者之间使用单一长连接,传输量大会严重降低服务吞吐量,增大调用时延;3、在消费者端控制超时时延,避免慢响应的服务引起故障扩散;4、做好服务隔离,避免次要服务消耗过多资源,影响重要服务的吞吐量或性能。
容灾容错:在分布式服务框架和应用中需要做好被调用服务出错或不可用的准备,并进行兼容,避免次要服务引起整个业务无法进行的状况。前面在服务降级中进行过详细描述,此处不再细讲。
分布式事务的一致性:单体应用中,事务是个极其简单的控制,spring的声明式事务提供了很多事务控制策略,代码中几乎不需要考虑事务一致性问题。服务分布化之后,每个服务都拥有自己的数据库,服务之间的调用也变成了远程调用,事务一致性几乎无法通过框架来保证,事务一致性控制可能是分布式应用和单体应用的最大区别。通常,两阶段提交时企业应用保证分布式事务的常规策略,然而,两阶段提交采用悲观锁策略策略所表现出的低吞吐量和在出现故障时的脆弱性,几乎不被互联网应用所采纳。回到问题的本质,我们之所以采用事务,是为了数据的一致性,而为了达到数据一致性,不一定只有事务一种方式,尤其是在分布式场景下,采用分布式事务带来的吞吐量下降是无法接受的。我们考虑在整个业务处理过程中,保证数据在任何时间内强一致的必要性,在很多业务场景下用户对短暂的数据不一致是可以理解和容忍的,只要最终数据是一致的即可。使用最终一致性,就不需要使用强一致的两阶段提交型分布式事务,从而使得系统的吞吐量得到保证。常用的最终一致性方案,要么在整个业务过程中记录每个调用其他服务事务性操作的结果,对失败的操作进行重试,如果某个关键性服务返回失败,例如支付时余额不足,则对每个成功的事务性操作进行补偿性操作调用,以达到事务回滚的效果;要么使用带有事务功能的MQ做中间人角色,做本地事务之前向MQ发送prepare消息,然后执行本地事务,执行成功的话向MQ发送commit消息,执行失败则发送rollback消息。对于最终一致性,一个很关键的点就是:对于网络超时的事务性请求,不能假设为失败,必须查询后,根据查询结果决定下一步的操作,如果成功则进行下一步操作,失败则重试。
分布式调用与本地调用的不同:远程调用比本地调用复杂,所以有一些通用的最佳实践。
分包:建议将服务接口,服务模型,服务异常等放在api包中;
粒度:服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题;
序列化:服务参数及返回值建议使用POJO对象,即通过set,get方法表示属性的对象,服务参数及返回值都必需是byValue的,而不能是byRef的,远程调用出现byRef可能出现难以预料的问题;
异常:建议使用异常汇报错误,而不是返回错误码,异常信息能携带更多信息,以及语义更友好。

作为本系列的终结篇,强调最后一次,在分布式应用中,一定要处理好异常,处理好调用失败,处理好网络超时等各种非正常的场景。

你可能感兴趣的:(dubbo三)