Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

周记 2019/09/06:尴尬的微服务,web app 的性能瓶颈 #45

Open
wangpin34 opened this issue Sep 9, 2019 · 0 comments
Open
Labels

Comments

@wangpin34
Copy link
Owner

wangpin34 commented Sep 9, 2019

我似乎又回到了一年之前开发前一个 app 时所处的困境,不同的是,此时我既要负责前端还要负责后端。我想要做的更好一点,但现实狠狠地给了我一巴掌。

尴尬的微服务

微服务的卖点确实很亮眼:把一个庞大的系统纵向切分成不同的更小的系统,每个小系统就是一个微服务(micro service)。微服务带来很多好处:

  1. 单个服务 crash 不会再影响整个系统的稳定性
  2. 给任务最繁重的服务配置更多的资源使其更加稳定可靠

微服务带来的好处和软件工程中频频提及的模块化,组件化,高内聚低耦合,有异曲同工之妙。所以,我有理由相信,微服务最初的想法来源于软件工程固有的最佳实践。而软件工程的这些最佳实践也无疑参考了传统企业的做法。比如,我可以把微服务的核心思想抽象一下:将内部太过于复杂的整体分离成可以逻辑自治的小单位,使得每个单位只需要负责自己的内部事务,对外只需要提供约定的职能。你会发现将前面这段套用在任何地方都无不妥,比如,如果你负责一个大车间,几百个工人,那按照每个人负责的工种不同,将工人们组成一个个专业的团体,对外提供专业单一的职能。你可以称这样的团队「微小组」。

相应的,组成「微小组」之后,作为上层管理者,你得明白从这一刻起你不再是管理一个个活生生的人了,而是一个个新鲜的集体,方式方法都得与时俱进。比如,以前你会找张三去做电焊,现在你需要将电焊的工作安排给电焊二组,由二组负责人再将具体的工作安排给张三李四甚至王五。我得承认,经历过这样的一层消息传递,肯定不比你直接找张三快速直接,但是好处也是显而易见的:

  1. 如果张三不能提供服务(请假,任务中,等等),二组负责人会安排其他人干活;
  2. 如果张三做的有问题,二组负责人会纠正甚至返工;
  3. 如果张三离职了,二组负责人会招聘新人;

作为上级,你获得的好处是更加可靠的服务,同时,你的管理压力也通过这样的方式转嫁到小组负责人肩上。不足之处在于,各个小组只能负责只能相对单一的工作,如果要跨小组协作,依然离不开你的指挥。

我们首先遇到的问题,就是跨小组协作。

协作艰难

注:我司真实案例
员工个人信息(profile),组织关系(relation),组织详细信息(department),分别由三个微服务管理,如何查询完整的员工信息(profile + relation + department)呢?

作为一个极其业余的微服务开发者,我的第一版程序就是简单的先查 profile API,再 relation API,再 department API,然后组合 profile + relation + department,最后返回。API 响应时间相当于三个 API 叠加,这还只是最简单的情况。有时候,一个员工可能隶属于多个 department,于是需要查询多次 department API,最终累计下来的时间消耗达到 2 ~ 3 秒。当时,我们在好几个会议上讨论这个问题,最终在架构师的建议下开始做并行查询,也就是多起几个线程一起查。这样的做法从表面上看放佛解决了问题,但很快引起了其他问题如线程太多引起内存极速消耗,服务频繁崩溃。而且这种做法很快达到了性能瓶颈,毕竟,并行查询只是查询发起的一方牺牲部分内存达到的虚假快速,最终得到数据还要依赖后台相关服务的响应,而大量的查询请求又对这些服务,以及后台的数据库造成了巨大的压力。

查询的问题仅仅只是速度的问题,而其他操作还要涉及到数据完整性准确性,所以更加复杂。比如,一个用户操作需要更新 a,b,c 三块数据,那我必须保证三者更新完整。换言之,更新 a 成功,但其他失败,则必须回滚 a 到更新操作之前的状态。这就是事务安全。截止到我写这篇文章为止,我们系统中很多的事务安全是依靠调用 api 来回滚的,而非依赖数据库的事务支持。使用 api 的坏处是有随时都可能失败,失败的后果就是数据状态不正确。

所以我们是如何面对协作问题的:依靠操作的发起方自己来保证数据的正确。也就是说,如果你是工程部需要技术部提供电焊和水管工作,技术部的负责人不会帮你安排这两个小组,需要你自己去找人。也就是说,技术部老大划分好小组就可以睡大觉了。

事实上我司的架构师们就是这么做的,写好 ppt,开几个 meeting 通知一下技术部门,然后就去做别的了。

业务逻辑分散

前面所说我负责的微服务,就是我们公司所谓的前台服务,也就是直接为 app 提供数据支持的服务。前台服务不直接操作数据库,访问后台服务 API 来获取/更新数据。后台服务是一个个职责非常单一的微服务,简单到只有基本的增删改查。比如前文提到的 profile,它只负责用户个人信息的增删改查,至于这个用户是哪个部门的员工,领导是谁,它一无所知。

正是因为后台服务太过于简单,所以很多核心业务逻辑转移到了前台服务。为什么我觉得前台服务不适合处理核心逻辑。原因有三:

  1. 核心逻辑对数据准确性十分敏感,最好就近管理数据库,以免数据损失;
    2.核心逻辑可能大量消耗计算资源(比如我司关于足底压力的计算),最好由专用的服务器负责计算和持久化;
    3.核心逻辑只应该有一个活跃版本,避免数据不统一(比如我们现在有很多核心逻辑散落在几个前台服务,造成最终呈现在 app 上的数据差异);

我们现在遇到的问题几乎都是由于核心逻辑的分散造成的,同样的原始数据,仅仅是因为在不同的前台服务中处理过,最终产生显著的差异。同时,前台服务天生不具备数据库访问权限,很多实时计算的结果不能很好的存储起来,导致计算资源浪费。

缓存缺失

第三个严重的问题和微服务本身无关,只是微服务架构让这个问题更加突出而已。我们的系统并没有一个统一的缓存平台。后台服务不需要缓存,前台服务按照自己的需要,或用 redis,或用 mongodb,缓存些仅仅和自己业务相关的数据。作为一个整体,我们应该有统一的缓存平台,只要是对 profile 的缓存,不管是 A 服务缓存的,还是 B 服务缓存的,大家可以彼此信任,互惠互利,而不是像现在各自为政,不理不睬。这变相的加剧了协作的问题,毕竟,如果大量的请求打到缓存上,后台服务的压力不会太大,处理起并行查询也会从容更多把。

总结

我们的微服务架构太简陋,只考虑切分系统而不考虑如何协作,导致前台承载过多业务逻辑以至于规模庞大,效率低下。同时,缺乏统一的缓存系统又变相加剧了这个问题。

web app 的性能瓶颈

我们的 web app 挺可怜,一方面,后台 api 效率感人,所以 app 的开发需要考虑添加很多额外的逻辑来减弱 api 的负面影响,比如,模拟后台服务的数据更新,当发出 api 后,直接更新 app 状态而不是等待后台确认。如果 api 的响应足够快,这样的逻辑其实是可有可无的。

另一方面,相当数量的业务逻辑,还有所谓的为了兼容老版本数据的代码,已经越来越难以维护了。这些代码产生的原因大部分是因为前端的妥协,理由是后台服务更新后,一部分客户端还没有更新到最新版本,所以在添加新代码支持新版服务的同时,保留维护老代码。问题是,客户端总有一天会全部升级到新版本,这部分老代码也就失去意义了。所以我们为什么没有一个章程来终止对老版本的支持呢?

所以 web app 的性能瓶颈就这么来了,而且让我无法反抗。因为从本质上来讲,app 本身的优化空间虽然还有(上 ssr,pwa ),但根本问题不解决( api 慢,老代码多),总归还是死路一条。遗憾的是,掌握话语权的人并不这样想。所以我们的 app 总是很慢,慢的不可思议。

@wangpin34 wangpin34 changed the title 周记 2019/09/06:尴尬的微服务;web app 的性能瓶颈 周记 2019/09/06:尴尬的微服务,web app 的性能瓶颈 Sep 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant