发布于 

读《持续架构实践》

之前看到过一种言论,说相比互联网产品,做 ToB 产品没有那么大的业务量,也没有那么多的用户量,所以非功能性的需求没那么重要,重要的还是业务。

虽然不是很认同,但之前也确实对非功能性需求不够重视,后来发现随着客户信息化越来越成熟、系统使用的时间越来越长,用户数的增长和业务量的增长都会带来问题,导致系统的可用性降低。

那么,什么是非功能性需求呢?

最近看的一本书《持续架构实践》中有详细的讲解。

书中提倡架构应该持续地进行,就是说在整个研发生命周期中,持续提出架构决策,需要遵守六个架构准则:

1、用产品思维,而非项目思维来设计架构

2、聚集质量属性,而不仅仅是功能性需求

3、在绝对必要的时候再做设计决策

4、利用微小的力量,面向变化来设计架构

5、为构建、测试、部署和运营来设计架构

6、在完成系统设计后,开始为团队做组织建模

这六个准则贯穿全书,其中准则二说的质量属性,指的就是非功能性需求,包括:安全性、伸缩性、性能、弹性等。这也是本文的主要内容。

可伸缩性

可伸缩性经常被人忽视,但随着用户使用系统的人数越来越多,数据量越来越大,可伸缩性的重要性就体现出来了。

什么是可伸缩性呢?

通过增加或减少系统成本来处理增加或减少的工作负载,这个工作负载指的是更大的业务量,或更大的用户量。

对于 ToB 企业级应用来说,这个系统成本通常是增加。那什么是系统成本呢?有两个维度:

  • 垂直伸缩:增加服务器资源,比如硬盘、内存、CPU ,这种是最简单的,程序不需要做任何调整就把问题解决了,但会有上限的问题。

  • 水平伸缩:添加多台服务器,构建集群,对于应用来说,可能需要进行代码改造才能支持集群方式部署;对于中间件会增加部署的复杂度。

中间件的伸缩都有成熟的方案,我们自己开发的程序可能会遇到些问题,现在的架构基本都是前后端分离,后端 API 接口是无状态的,但如果在 API 中将数据存在内存中,就会变得复杂。

所以说,有状态和无状态对可伸缩是有影响的,有状态的额外数据存放在服务器的内存中,垂直伸缩的时候没有问题,水平伸缩就会涉及到数据同步的问题。不过也有处理的办法:

  • 同一台机器保持相同的访问实例,可以通过 Nginx 的配置实现;
  • 当数据发生改变的时候,发广播通知其他节点进行数据同步,要考虑数据一致性的问题。

安全性

安全问题基本上在开发过程中很少考虑,客户环境一旦有护网行动,或者进行安全漏洞扫描,就出扫出一堆问题,然后按照危险等级进行修复。

所以,如果在架构设计时就对安全性进行了考虑,会省去很多的麻烦。

下面列举下经常出现的安全性的问题:

1、数据库的 Sql 注入;

2、API 接口没有鉴权可以直接调用;

3、某些页面是需要授权才能访问的,但拿到页面地址,在权限不匹配的情况下也能进行访问;

4、登录时调用接口,密码是明文;

5、在一些进行数据库连接设置的界面,接口会返回一些不必要的信息,比如数据库密码;

6、对关键信息的修改没有相关日志记录;

7、中间件使用默认配置,没有设置密码,比如:Redis、MongoDB 等;

8、恶意攻击下的缓存的雪崩、击穿、穿透问题;

9、API 出现异常时,没有进行合理处理导致返回了敏感信息;

上面只是简单列了几条常见问题,在实际软件开发过程中,应该将安全性左移,不能等扫出问题再进行补救,应该在整个软件生命周期中就伴随着安全性的考虑。

性能

开发经常说:我本地是好的呀!我本地不慢呀!

这是因为和生产系统相比,环境不一样、用户数不一样、业务量也不一样。自然结果也不一样。

我们在交付软件的时候,由于有时间节点的压力,往往都是功能、业务优先,大数据量、高并发并不会作为第一优先级考虑。这就会导致在客户环境中可能出现性能问题。

小的性能问题会影响使用体验,严重的性能问题可能导致系统不可用,给客户带来损失。

提高性能的策略有下面一些方式:

对内:

  • 优化代码
  • 降级处理,在相同资源的情况下,保证核心业务稳定

对外:

  • 增加服务器资源
  • 使用缓存
  • 将一些业务使用消息机制异步处理

减少开销:

  • 微服务的整合,减少调用层级
  • API 瘦身,减少不必要的信息返回到前端

在书中也建议将性能测试活动左移,尽早发现性能问题,提前进行正常负载、预计的最大负载的压力测试。

弹性

软件系统可用性有三个层级:可用、可靠、弹性

  • 可用:系统不跨,主要依靠基础设施的能力,进行副本集复制,自动故障转移等
  • 可靠:建立在可用基础之上,增加了一条,就是系统是正确的,业务流转不会出现问题
  • 弹性:结合了上面两种,让系统可以从容地处理意外故障和恶意故障并进行恢复

在系统出现问题时,怎样让系统恢复可用,损失降到最小,是优先级最高的,之前看过一个说法,我认为很有道理:

运维有三大法宝:重启、扩容、回滚。

其实就是让系统能尽快恢复使用。那怎么做到有弹性呢?

1、识别问题:出现问题时能快速识别,就需要用到监控系统。

2、隔离问题:服务的拆分、容器化部署等都可以让一个服务失败时,其他可以继续运行,不受影响。

3、缓解问题:数据、系统出现问题时能够回滚,让系统恢复正常,留出排查问题的时间;数据出错,有补偿机制,可以手动进行修复。

4、解决问题:需要有详细的日志进行辅助、全链路日志追踪、日志检索等。

总结

1、非功能性的需求都需要左移,伴随着软件生命周期一起成长,左移让所有人、事都融合起来,每个迭代的目标性更强;

2、非功能性需求需要配合监控,只有发现问题,才能解决问题;

3、我很认可一句话:架构是演进出来的,不是设计出来的,这其实就很符合持续架构的思想。