Java应用在架构设计时该考虑什么
前言
最近公司因业务发展需要建设一个新应用,在架构设计时我也有机会能在提供一些建议,这个过程还是比较有趣的,要找到符合业务场景和用户需求的技术,并且要考虑未来的扩展性,相对来说还是比较困难的。
涉及到后端、前端、开发规范、运维等多个方面的大量技术内容,为了以后能在类似的工作中变得更容易,我决定在本期内容中进行整理,列出一些在新项目建设时需要考虑的一些问题。
提前声明一下,本期内容在大多数问题下只提供一些解决该问题的技术,对于实现细节不是这期内容的重点;可能存在不完整的地方,主要的技术栈为Java;希望能对正在建立新系统的你有所帮助。
架构风格
首先需要明确新系统的基本架构风格,是现在比较流行的微服务架构,还是单体架构,SOA架构等。
单体架构
单体架构将所有功能包含在单个部署单元中;
可能不支持灵活的发布周期,但不需要分布式通信。
微服务
多个较小的部署单元,它们利用分布式通信来实现应用程序的功能;
支持更小、更快的版本迭代,多个团队协同开发更加灵活,但代价是分布式通信问题。
后端相关
对于要新建应用的后端,需要考虑一下这些事情。
- 应用服务
应用服务该如何托管?对于分布式体系结构与Spring Boot配合使用是现在很好的解决方案;
而单体结构可能更适合使用如Wildfly
这样的应用服务器;
应用服务的选择通常是为要提前确定的。
- 系统间通信
在构建分布式系统时,因为涉及到分布式系统间的通信,而通信技术的选择也有多种,例如:通过消息中间件(例如kafka
、RocketMQ
等)进行异步通信,也可使用Spring MVC
和Feign
进行Rest通信,或者Dubbo
、Spring Cloud
等进行RPC通信。
- 接口文档
在通信方式确定之后,对于提供交互的内外部接口API需要创建某种形式的文档记录。
对于Rest API,可以使用Swagger
或者使用Spring rest Docs来实现;
如果不使用接口框架,则一般使用Markdown或Asciidoctor等标记格式手动记录API;
不推荐使用Word这样极度不友好的方式记录API。
- 身份验证、授权
一般需要和用户交互的系统,都会涉及到用户登录、授权等功能。用户如何证明自己的身份?是否需要用户提供用户名密码,或者是通过手机号码验证等;
对于单页面的应用程序,使用OAuth认证、JWT等令牌机制实现身份验证;有些Web应用程序可能使用session+cookie
就足够了;
一旦通过身份验证,应用程序还需要检查用户可以做什么操作;在服务器端,Spring Security
是一个支持实现不同授权机制的框架。
- 数据库
如果应用程序需要结构化的数据库,则使用关系数据库如MySQL
,Oracle
等;如果需要存储文档结构的数据,使用MongoDB
;键值对存储使用Redis
,如果有图表数据存储可以使用Neo4J
。
- 持久层框架
在使用关系数据库时,Hibernate
和MyBatis
是两个常用的技术,在国内的技术选型上MyBaits
更多一些;还可以使用Spring data JPA
,JPA默认使用hibernate
作为ORM实现,还支持许多NoSQL
数据库,比如Neo4J
或MongoDB
。
- 任务调度
几乎每个大中型应用程序都需要执行计划任务,如清理数据或批量导入第三方数据等;
Spring提供了基本的作业调度功能,如Spring Batch;
对于更复杂的需求,还可以选择Quartz、Elastic Job以及xxl-job等。
- 日志
日志记录的技术选型基本使用SLF4J作为日志记录门面,具体日志实现使用LogBack或Log4J2。
- 指标监控
如果需要对于应用程序运行时的吞吐量之类的进行监控,需要使用像DropWizard Metrics
、Prometheus
等这样的监控框架;微服务状态,数据库连接,MQ状态、磁盘占用等指标数据也可以选择使用Spring Actuator
。
前端相关
影响前端架构的因素有哪些?
- 前端技术体系
应用程序是否需要作为Web应用程序集中托管,还是富客户端。
如果是Web应用程序,它是客户端的单页面应用程序,还是服务器端的Web框架;
如果是富客户端,需求是支持Swing或基于JavaFX的客户端,还是支持完全不同的东西,比如Electron。
- 客户端数据库
是否需要在客户端存储数据,在Web应用程序中,可以使用 Local Storage 和IndexedDB;
在富客户端中,可以使用一些占用空间较小的数据库,如Derby。
- 外围设备
客户端是否需要访问某些类型的外围设备,如读卡器、U盾或执行某种外部测量的其他硬件;
在富客户端中,可以直接访问这些设备;
在web应用程序中,可能需要提供一个小型客户端应用程序,该应用程序可以通过本地主机上的http服务器访问这些设备并使其数据可用,该服务器可以集成到浏览器中的web应用程序中。
- 页面布局框架
客户端应用程序应该如何布局和设计呢,在基于HTML的客户端中,可能希望使用像Bootstrap这样的框架。对于富客户端,可用的技术可能会有很大不同。
- 指标监控
是否有一些事件(如错误、客户端版本等问题),需要客户端向中央服务器报告;这些事件将如何传送到服务器;
- 离线模式
客户端是否需要脱机工作?哪些用例应该脱机使用,哪些不应该?一旦客户端在线,客户端数据将如何与服务器同步?
运维相关
在进行系统设计时,有哪些东西是需要和运维团队进行沟通的,主要包括以下内容:
- 服务器
应用程序是托管在真实硬件服务器上还是托管在虚拟机上?使用Docker还是k8s等虚拟化技术。
- 网络通信结构
网络应该设置如何?应用程序的不同部分之间或应用程序与第三方应用程序之间是否存在网络通信障碍?
- 负载均衡
如何在软件的多个实例之间平衡应用程序的负载;是否有硬件负载均衡器;这个应用程序是否需要一个反向代理来将请求路由到应用程序的不同部署单元(比如使用Zuul)。
- 监控
如何对服务器实例的运行状况进行监控和报警?报警应该通知给谁?是否应该有一个中央仪表盘,用来测量所有类型的指标,如吞吐量等(Prometheus +Grafana是比较好的工具)。
- 服务注册与发现
在构建微服务架构时,可能需要服务的中央注册表,以便彼此发现。Eureka、Nacos等是现在比较流行的方案。
- 中央日志服务
可能需要有一个中央日志服务体系,尤其是当建立分布式服务,具有很多部署单元时,使用中央日志服务对于日志查找来说是相对容易的,不需要登录到不同的主机查找日志。
Elastic stack(Elastic 、Logstach、Kibana)是很成熟的中央日志方案。
- 数据库
对数据库有怎样的要求,是否需要支持数据库实例之间的热故障转移、负载平衡;师傅需要在线备份等。
开发相关
在开始开发之前,一定要与开发团队讨论这些每天都要处理的事情。
- IDE
对于IDE的使用公司是否有相关政策,是否运行开发人员按自己的习惯选择;当然,我认为强制开发人员使用他/她不习惯的IDE会大大降低效率,我自己更喜欢使用IntelliJ IDEA。
- 构建工具
选择哪种构建工具,使用Maven
还是Gradle
,这两个各有优缺点。
- 单元测试
代码的哪些部分应该进行单元测试;使用哪些框架来实现;JUnit4
和Mockito
是比较好的选择。
- 端到端测试
代码的哪些部分应该使用自动化的端到端测试进行测试?推荐使用Selenium
作为远程控
制浏览器进行自动化测试的工具。
- 版本控制
代码如何托管,版本控制工具推荐Git
,SVN
已经过时了。
- 代码规范和质量
类和变量是如何命名的?注释如何编写?如何衡量代码质量、编码规约等;
系统的使这些指标如何统计并查看,推荐使用SonarQube
这样的中央代码质量服务器。
建议选择现有的代码格式化程序和Checkstyle
规则集,并将其作为构建步骤包含到构建过程中,以确保只有符
合您的约定的代码才会提交到代码库。
- 代码评审
开发过程中如何执行代码评审工作,怎样的周期,是开会还是使用工具。
一些版本控制工具,如GitLab支持每个用户在自己的分支上工作的工作流,直到他准备合并代码。在代码Merge之前是代码评审的一个好机会。
- CI/CD(持续集成/持续部署)
构建过程将如何定期执行?是使用Jenkins服务器还是云厂商提供的工具等。
是否有自动任务可以将应用程序部署到开发、测试或生产环境,这些任务将如何执行。
- 日志规范
应该在何时记录什么样的日志,如何让开发人员在日志中打印有用的价值,日志应如何记录应用程序的哪些部分?什么信息?
- 文档
应该在类似Confluence
、语雀这样的Wiki中记录文档,而不是在Word文件中;推荐使用像Markdown
这样的标记格式记录文档。
小结
基于Java体系建设一个系统需要考虑的内容涉及各个方面,有很多地方可能有更好的解决方案和选择,如果你有不同的意见或者更高的工具、框架、解决方案,欢迎在下放评论区交流。
我是小黑,一个在互联网“苟且”的程序员。
流水不争先,贵在滔滔不绝