三层架构一般包括:表示层、业务逻辑层以及数据访问层。java
虽然传统的三层架构帮助咱们将应用在逻辑上分红了三层,但它并非物理上的分层。这也意味着,即使咱们将应用架构分红了所谓的三层,通过开发团队对不一样层的代码实现,经历编译(非静态语言则忽略编译阶段)、打包、部署后,不考虑负载均衡以及水平扩展的状况,最终仍是运行在同一台机器的同一进程中。对于这种功能集中、代码和数据中心化、一个发布包、部署后运行在同一进程的应用程序,咱们一般称之为单块架构应用。linux
提倡将单一应用程序划分红一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每一个服务运行在其独立的进程中,服务与服务之间采用轻量级的通讯机制互相沟通(一般是基于HTTP的RESTful 服务)。每一个服务都围绕着具体的业务进行构建,而且可以被独立地部署到生产环境、类生产环境中。另外,应尽可能避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。算法
(1)如何拆分微服务?多微才够微小缓存
代码行数网络
重写时间架构
团队以为好才是好:业务独立性、团队自主性负载均衡
(2)单一职责框架
单一职责(高内聚、低耦合,不一样的服务经过“管道”的方式灵活组合,从而构建出庞大的系统。运维
(3)轻量级通讯dom
指的是与语言无关、平台无关的交互方式。所熟知的REST是实现服务之间相互协做的轻量级通讯机制之一。团队能够选择更适合的语言、工具或者平台来开发服务自己。
(4)独立性
独立性是指在应用的交付过程当中,开发、测试以及部署的独立性。
对于每一个服务,都有独立的代码库。当对当前服务的代码进行修改后,并不会影响其余服务。从代码库的层面而言,服务与服务是个隔离的。
(5)进程隔离
微服务架构实际上是将单一的应用程序划分红一组小的服务,每一个服务都是具备业务属性的独立单元,同时可以被独立开发、独立运行、独立测试以及独立部署。
开源的应用容器引擎,容许开发者将他们的应用以及依赖包打包到一个可移植的容器中,而后发布到任何装有Docker的linux机器上。
Docker的出现,有效的解决了微服务架构下,服务粒度细、服务数量多所致使的开发环境搭建、部署以及运维成本高的问题。同时利用Docker的容器化技术,可以实如今一个节点上运行成百甚至上千的Docker容器,每一个容器都能独立的运行一个服务,所以极大的下降了随着微服务数量增多所致使的节点数量增多的成本。
(1)服务做为组件
若是把微服务做为组件,则同传统使用组件方式最大的区别是,组件能够被独立部署。
显著的优点在于:能以松散的服务方式,构建可独立部署的模块化应用。
(2)围绕业务组织团队
(3)关注产品而非项目
(4)技术多样性
(5)业务数据独立
(6)基础设施自动化
(7)演进式架构
不断调整软件的架构,将不须要的服务(业务)抛弃,将须要的服务升级,并采用合适的技术或者工具不断优化架构,保持其处于一个不断演进的状态。
(1)性能
分布式系统因为组件与组件的调用是跨进程、跨网络的调用,所以必然要考虑网络延迟以及带宽的影响。
(2)可靠性
组件间的远程调用可能失败,还有可能出现潜在故障点。
(3)异步
跨网络的调用,须要考虑异步的通讯机制。异步通讯大大增长了功能实现的复杂度。
(4)数据一致性
分布式事务管理成本更高。
(5)工具
IDE等工具须要为开发分布式系统提供足够的支持。
(6)运维成本
每一个服务都须要独立的配置、部署、监控、日志收集等,成本呈指数级增加。
(7)部署自动化
如何有效地构建自动化部署流水线,下降部署成本,提升部署频率,是微服务架构下须要面临的一个挑战。
(8)DevOps与组织架构
(9)服务间的依赖测试
(10)服务间的依赖管理。
一段话道出微服务的本质:
微服务架构将一个应用拆分红多个独立的、具备业务属性的服务,每一个服务运行在不一样的进程中,服务与服务之间经过轻量级的通讯机制相互协做、相互配合,从而为终端用户提供业务价值。同时每一个服务能够根据业务逻辑,采用不一样的语言、框架、工具以及存储技术来解决业务问题。所以微服务架构强调的是一种独立开发、独立测试、独立部署、独立运行的高度自治的架构模式,也是一种更灵活、更开放、更松散的演进式架构。
超时与重试是保护系统、下降微服务失败率的重要手段(如Spring Cloud中参考CSDN-SpringCloud之Feign、Ribbon设置超时时间和重试机制的总结
),经过设置合理的超时时间,防止出现某服务的依赖服务超时时间过长且响应慢,慢请求累积引发连锁反应,甚至形成应用雪崩,超时以后应该有相应的策略来处理,常见的策略有重试(等一下子再试、尝试其它分组和机房服务,重试算法能够采用如指数退避算法,由于网络波动、系统资源分配的不肯定性、跨机房的请求等缘由,都会或多或少的致使一小部分请求的失败,而这部分失败的请求中,又有大部分请求其实只须要简单重试几回便可成功)、摘掉不存活节点(负载均衡、分布式缓存场景)、降级托底(返回历史/静态/缓存数据)、等待页或错误页。读服务自然适合重试,大多数写服务重试就须要考虑幂等问题。
关于幂等分析与解决参考:幂等
降级、限流、熔断、隔离
服务支持local、share、microservice三种工做模式,以及Api支持client和server两种调用模式。
假设如今关注公共服务如登陆服务的版本,那么本地起该服务便可,注册中心会优先使用本地起的登陆服务。具体须要实现Eureka的getFilteredListOfServer接口。
/** * This interface allows for filtering the configured or dynamically obtained * List of candidate servers with desirable characteristics. * * @author stonse * * @param <T> */ public interface ServerListFilter<T extends Server> { public List<T> getFilteredListOfServers(List<T> servers); }
public class LocalDebugServerListFilter implements ServerListFilter { @Override public List getFilteredListOfServers(List servers) { boolean hasOwnService = false; Object ownServer = null; //获取本地ip配置 List<String> ips = getLocalIPs(); for(Object server : servers){ DiscoveryEnabledServer domainExtractingServer = (DiscoveryEnabledServer)server; if(ips.contains(domainExtractingServer.getInstanceInfo().getHostName())){ hasOwnService = true; ownServer = server; break; } } if(!hasOwnService){ return servers; } else { List result = new ArrayList<>(); result.add(ownServer); return result; } } private List<String> getLocalIPs() { List<String> localIPs = new ArrayList<>(); try { Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces(); while (netInterfaces.hasMoreElements()) { NetworkInterface ni = netInterfaces.nextElement(); Enumeration<InetAddress> ia = ni.getInetAddresses(); while (ia.hasMoreElements()) { InetAddress ip = ia.nextElement(); if(validIPv4Address(ip.getHostAddress())){ localIPs.add(ip.getHostAddress()); } } } } catch (SocketException e) { e.printStackTrace(); } return localIPs; } private boolean validIPv4Address(String ip) { Pattern pattern = Pattern.compile("^\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}$"); Matcher matcher = pattern.matcher(ip); return matcher.matches(); } }
参考资料
《微服务架构与实践》王磊