警告:大文章,一些意见,含糊不清的“做对您最有效的”结论
通常,这是在数据库周围实现“六边形体系结构”的一种方式。您可以让Web应用程序,移动应用程序,桌面应用程序,批量导入器和后台处理都以统一的方式消耗您的数据库。当然,您可以通过编写用于访问数据库的丰富库并让所有进程使用该库来在某种程度上完成同一件事。实际上,如果您在一家拥有非常简单系统的小商店中,那实际上可能是一条更好的选择。这是一种更简单的方法,如果您不需要更复杂的系统的高级功能,为什么还要为此付出代价呢?但是,如果您使用的是大型,复杂的系统集,而这些系统都需要与数据库进行大规模交互,那么
平台独立性和维护
如果您有一个数据库,并且编写了一个Python库与该数据库进行交互,并且每个人都拉入该库与数据库进行交互,那就太好了。但是,突然说您需要编写一个移动应用程序,并且该移动应用程序现在还需要与数据库进行对话。而且您的iOS工程师不使用Python,而您的Android工程师也不使用Python。也许iOS人士想使用Apple的语言,而Android工程师想使用Java。然后,您将不得不使用3种不同的语言来编写和维护数据访问库。也许iOS和Android开发人员决定使用Xamarin之类的东西来最大化他们可以共享的代码。完美,除非您可能仍然需要将数据访问库移植到.NET。然后您的公司刚刚购买了另一家 的Web应用程序是一个完全不同但相关的产品,该公司希望将您公司平台中的某些数据集成到新收购的子公司的平台中。只有一个问题:附属公司是一家初创公司,决定将其大部分应用程序用Dart编写。另外,由于各种原因(原因可能超出您的控制范围),正在试用Xamarin的移动团队认为这不是针对他们的,他们宁愿使用特定于他们将要开发的移动设备的工具和语言。但是当您处于该阶段时,您的团队已经在.NET中交付了很大一部分数据访问库,并且公司中的另一个团队正在编写一些疯狂的Salesforce集成资料,并决定从那时起在.NET中进行所有这些工作。已经是的数据访问库。
因此,现在,由于发生的事件非常现实,您拥有了用Python,.NET,Swift,Java和Dart编写的数据访问库。它们也不如您希望的那样好。您无法像您想要的那样有效地使用ORM,因为每种语言都有不同的ORM工具,因此您必须编写比自己想要的更多的代码。而且,您无法为每个化身投入足够的时间,因为其中有5个。Dart版本的库特别繁琐,因为您不得不自己动手购买一些事务,因为库和支持还不存在。因此,您试图证明Dart应用程序应该只对数据库具有只读功能,但是企业已经下定决心,无论他们计划使用什么功能,都值得付出额外的努力。事实证明,数据访问库的所有这些化身中都存在一些验证逻辑中的错误。现在,您必须编写测试和代码来修复所有这些库中的此错误,获取对所有这些库所做的更改的代码审查,对所有这些库进行质量检查,并使用所有这些库。同时,您的客户不满意并进入Twitter,将您从未想到的粗俗结合在一起,更不用说针对您公司的旗舰产品了。产品负责人决定完全不了解这种情况。
请理解,在某些环境中,以上示例并非人为设计。还应考虑到这种事件序列可能会在几年的过程中发生。通常,当您到达架构师和业务人员开始谈论将其他系统连接到数据库时,就是在您想要将“将REST API放在数据库前面”纳入路线图的时候。考虑一下是否很早,当很明显该数据库将开始由几个系统共享时,在它前面放置了一个Web服务/ REST API。修复验证错误会更快,更轻松,因为您只需执行一次即可,而不是执行5次。而且发布修复程序会容易得多,因为
TLDR;与将数据访问逻辑分发到需要访问数据的每个应用程序相比,集中数据访问逻辑和维护非常瘦的HTTP客户端要容易得多。实际上,您的HTTP客户端甚至可以从元数据生成。在大型系统中,REST API可让您维护更少的代码
性能和可扩展性
有些人可能认为直接与数据库对话而不是先通过Web服务对话会更快。如果只有一个应用程序,那肯定是正确的。但是在较大的系统中,我不同意这种观点。最终,在某种程度上,将某种类型的缓存放置在数据库的前面将是非常有益的。也许您正在使用Hibernate,并且想要安装Infinispan网格作为L2缓存。如果您有4个强大的服务器集群来独立于应用程序托管Web服务,则可以负担得起具有启用同步复制的嵌入式拓扑的能力。如果您尝试将其放置在30个应用程序服务器的群集上,则在该设置中启用复制的开销会太大,因此,必须以分布式模式或某种专用拓扑来运行Infinispan,突然之间,Hibernate必须通过网络出去才能从缓存中读取。另外,Infinispan仅适用于Java。如果您使用其他语言,则需要其他缓存解决方案。在使用数据库之前,必须先从应用程序转到Web服务的网络开销很快就被需要使用更为复杂的缓存解决方案所抵消,而这些缓存解决方案通常会自身带来开销。
此外,REST API的HTTP层提供了另一种有价值的缓存机制。用于REST API的服务器可以在其响应上放置缓存头,并且这些响应可以缓存在网络层,扩展性非常好。在具有一台或两台服务器的小型设置中,最好的选择是在与数据库进行通信时仅在应用程序中使用内存中的高速缓存,但是在具有许多应用程序在许多服务器上运行的大型平台中,您希望利用网络来处理您的缓存,因为在正确配置后,诸如鱿鱼,清漆或nginx之类的东西可以在相对较小的硬件上扩展到疯狂的水平。每秒从HTTP缓存执行数十万或数百万个请求的吞吐量要比从应用程序服务器或数据库执行的便宜得多。
最重要的是,让大量的客户端全部指向您的数据库,而不是让它们全部都指向几个服务器(这些服务器又指向数据库),可能会使数据库调整和连接池的设置变得更加困难。通常,应用程序服务器上的大部分实际工作量是应用程序填充。等待数据从数据库返回通常很耗时,但通常在计算上不是很昂贵。您可能需要40台服务器来处理应用程序的工作负载,但是您可能不需要40台服务器来协调从数据库中获取数据。如果您将该任务专用于Web服务,则该Web服务可能将在运行于服务器上的服务器数量少于应用程序其余部分的服务器上,这意味着与数据库的连接数量将大大减少。这很重要,因为数据库通常不
TLDR;在单个专用Web服务中发生的事情比在使用不同语言和技术的许多不同应用程序中发生的事情更容易调整,扩展和缓存数据访问
最后的想法
请不要回避“哦,我应该一直使用REST API来获取我的数据”或“这个白痴试图说我们做错了,因为我们的Web应用程序直接与数据库进行对话,”我们的东西很好!” 。我要说明的重点是,不同的系统和不同的业务有不同的要求。在很多情况下,在数据库前放置REST API确实没有任何意义。这是一个更复杂的体系结构,需要证明这种复杂性。但是,当需要保证复杂性时,使用REST API会带来很多好处。能够权衡各种问题并为您的系统选择正确的方法才是一名优秀的工程师。
此外,如果REST API妨碍了调试的方式,则该图片中可能存在某些错误或缺失。我不认为在本质上增加抽象层会增加调试的难度。当我使用大型n层系统时,我想确保拥有分布式日志记录上下文。也许当用户发起一个请求时,为该请求生成一个GUID并记录该用户的用户名和他们提出的请求。然后,当您的应用程序与其他系统对话时,将该GUID传递给它。通过适当的日志聚合和索引编制,您可以查询整个平台,以供用户报告问题,并可以查看其所有操作,并且可以遍历系统以快速确定问题出在哪里。同样,它是一个更复杂的架构,
来源:http
:
//alistair.cockburn.us/Hexagonal+architecture https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing