文章目录
- 1、功能设计
- 1.1 系统设计
- 1.2 数据设计
- 2、非功能设计
- 2.1 稳定性设计
- 2.2 可测试性设计
- 2.3 应用安全、异常处理、扩展性、兼容性
- 3、开发技术栈与工具
- 3.1 编程语言与框架
- 3.2 集成开发环境与工具
- 3.3 数据库与数据存储
- 3.4 中间件与分布式
- 3.5 操作系统与应用部署
【后端开发】互联网后台开发,通用必备技术栈(设计与工具)
《服务端开发:技术、方法与实用解决方案》——读书笔记
目录:
1、功能设计
1.1 系统设计
1.2 数据设计
2、非功能设计
2.1 稳定性设计
2.2 可测试性设计
2.3 应用安全、异常处理、扩展性、兼容性
3、开发技术栈与工具
3.1 编程语言与框架
3.2 集成开发环境与工具
3.3 数据库与数据存储
3.4 中间件与分布式
3.5 操作系统与应用部署
1、功能设计
1.1 系统设计
需求分析与抽象建模
- 在实践中,根据业务复杂度的不同,有时候可能只需画个简单的流程图便可梳理清楚,但是复杂系统的设计则困难得多。不论采用何种设计方案,首先需要明确一个问题——你了解业务吗?如果根本不了解业务,那么,又怎么可能设计出满足业务需求的系统呢?
- 在实践中,设计并开发一个软件系统,并不单纯是技术层面的问题,首要任务是深入了解其业务,而欲了解业务则必经需求分析。
- 软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的,遵循的是人类世界的自然语言,而软件世界里通行的则是机器语言,两者间跨度太大,需要一座桥梁来联通,抽象建模便是打造这座桥梁的关键。基于抽象建模,不断地去粗取精,从现实世界到业务模型,从业务模型到设计模型,最终完成现实世界到软件世界的转换。
- 事实上,服务端开发工程师在大部分工作时间里并不是在写代码,而是在抽象建模。工程师需将业务需求抽象成领域模型、模块、服务和系统,面向对象开发时需抽象出类和对象,面向过程开发时抽象出方法和函数。
- 某种意义上,软件的本质就是抽象,建模则是系统地实施抽象的过程。 作为一种将事物形象化的有效手段,建模可将现实世界中的事物及事物之间的关系准确地表达出来。
设计和划分功能域
- 系统设计,又被称为系统架构,在本阶段,需要将抽象建模的成果有条不紊地映射到具体的技术实现,这个阶段需要通盘考虑、权衡取舍,要求工程师具备良好的技术深度、技术视野,同时充分理解业务。如果在抽象建模阶段做得足够好,建模方法选型与业务特点匹配,且抽象出的模型可以准确刻画业务的本质特征,那么,系统设计将是一件相对轻松的事情。
- 在互联网领域,一些业务的复杂度是非常高的。如下图所示,为阿里的电商业务摘要架构图,自顶向下划分为前台、中台、PAAS、IAAS等,而业务中台又可细分为会员中心、商品中心、交易中心、支付中心、评价中心和订单中心,这其实就是一种高层次的功能域设计和划分。
- 对于复杂的业务,首先应设计和划分功能域,以降低复杂度。具体而言,在完成抽象建模后,可基于模型将系统分拆为不同的功能域,各个功能域相互协作,共同实现业务需求。需要特别注意的是,不同功能域之间必须有清晰的职责边界,同时单个功能域的复杂度不能过高。
设计功能域之间的协作
- 经过多年的发展,互联网领域的“高增长”时代已经过去,正大步迈入“存量”时代。由于大多数业务已经相当成熟,通用基础能力亦趋于完善,因此业务需求的复杂度通常不会高到需要步骤 1 中的设计和划分功能域。
- 设计功能域之间的协作,可视为一种“粗粒度”的服务编排。具体而言,借助已有功能域提供的服务,目标功能域(新建或者在已有功能域的基础上扩展)可以快速实现新的功能,满足业务需要。在实践中,功能域之间协作的关键在于充分、合理地利用已有公共基础服务。
- 如下图所示,会员中心的权益投放通常有两种策略:个性化推荐(算法推荐)和运营定向投放(运营针对特定人群,如新用户,定向投放特殊权益),这两种投放策略可以通过不同的功能域协作实现。
确定功能域之间的数据边界
- 功能域之间的协作设计完成后,整个系统的上下游依赖也就清楚了,接下来我们需要进一步明确功能域之间的数据边界。
- 以微服务架构为例,一个功能域可作为一个应用,不同功能域之间通过服务调用来协作,对于服务,通常用请求(服务调用方发起请求)和响应(服务提供方响应请求返回结果)的数据模型来描述边界。
- 如果需求有多名服务端工程师(甚至团队)参与开发,在确定数据边界之后,不同功能域的职责也就进一步明确了,工程师可以专注于其所负责功能域的内部设计和开发。
功能域内部设计
- 功能域的技术目标得以明确,接下来便是通过设计去实现这些技术目标。在功能域内部,为了降低问题的规模和复杂度,同时增强系统的可扩展性和可维护性,一般采用如下图所示的“分层架构”。
详细设计
- 基于前面步骤的铺垫,就到了系统设计的最后一个环节,对大多数服务端开发工程师而言,这个环节应该是最为熟悉和擅长的,毕竟在一名工程师的职业生涯中,大多数时间都在从事子系统/模块的设计和开发。
- 子系统/模块的设计是一种详细设计,需要从细节层面考量问题,所做的设计用于直接指导开发。在这一步中,设计结果一般包括以下内容:
- 1、相关模型:如领域模型图,类图,实体关系图,数据表清单等,其中领域模型图一般在抽象建模阶段完成,而数据表清单则属于数据设计范畴,在下一节详细介绍。
- 2、上下游交互:大多数业务场景,或多或少存在上下游交互,交互一般通过数据库、接口、消息等方式。如果选择通过接口交互,需写明类名、方法名、入参、出参、结果码等;如果选择通过消息交互,需写明消息 Topic、Group、消息体结构等;如果选择通过数据库交互,需写明表名、索引、QPS 等。
- 3、方案描述:当业务较为复杂的时候,文字描述难以直观地反映设计方案的细节,也不便于后续评审和实施,因此,一般通过流程图、时序图来描述。
1.2 数据设计
数据设计
- 谈及数据设计,大多数 IT 从业者的第一反应是数据库设计,这其实是片面的。事实上,数据设计的内涵非常丰富,数据库选型、表结构设计、字段设计、索引设计、缓存设计、数据核对、数据监控等都属于数据设计的范畴。
- 如下图所示,完整的数据设计一般包含三个环节:领域概念模型设计、逻辑数据模型设计和物理存储模型设计。
- 不过,落实到具体的业务需求,这个三个环节并不是必需的,例如在一些相对简单的业务场景中,根本不涉及领域概念模型,也无需领域概念模型设计。
数据库选型:
- 数据库类型不同,其特性和适用的场景也存在较大差异。服务端开发工程师需要根据业务场景自身的特点,结合数据库的性能、存储成本、容量、一致性、读写偏好、稳定性等指标综合评估选型
存储类型 | 特性和适用场景 | 业界常用产品 |
---|---|---|
关系型数据库 | 支持索引、事务机制的结构化关系模型数据,SQL查询,适用于单表数据量较小的场景(单表过千万行需配合拆表拆库分布式路由) | MySQL、Oracle、PostgreSQL |
KV内存型数据库 | 基于key存取数据,O(1)级高效查询,一般用于数据查询缓存 | Redis、Memcached |
列式存储型数据库 | 面向列族组织的半结构化数据,基于RowKey读写,方便横向水平扩展,成本低廉。缺点是无索引、无跨行事务支持。适用于分布式海量数据存储(单表TB&PB级)和数据分析场景 | HBase |
文档型数据库 | 面向文档类数据,无需schema定义,如配合CDN机制高效存储和加载图片 | MongoDB |
搜索型数据库 | 基于倒排索引解决数据的全文搜索问题,用于搜索引擎和海量数据分析领域 | Elasticsearch |
图数据库 | 基于图论存储海量的数据实体和丰富的关系信息,提供图模式的查询搜索能力。适用于社交网络、知识图谱等复杂关系数据 | Neo4J |
2、非功能设计
业务方提出的需求和产品经理设计的产品方案大都聚焦于业务功能描述,在验收时,通常也只是验证要求实现的功能是否符合预期,极少考虑稳定性、兼容性、安全性、异常补偿等非功能性问题。
然而,很多时候,非功能性问题往往事关项目成败,因此必须根据业务场景谨慎评估非功能性问题并设计相应的解决方案。
2.1 稳定性设计
在互联网领域,稳定性设计是最重要的非功能性设计。
- 根据阿里官方公布的数据,在 2020 年的“双 11”大促活动中,天猫平台订单创建峰值达 58.3 万笔/秒,如此巨大的流量,若没有稳定、可靠系统和服务,业务便是空中楼阁,随时有崩塌的可能。
- 那么,在互联网企业,可以通过哪些具体的措施来保障稳定性呢?如下图所示,稳定性保障流程中,容量评估、接口限流、应急预案等环节都是需要服务端工程师保障的。
2.2 可测试性设计
与客户端不同,服务端对用户来说是不可见的,测试工程师无法直接通过 UI(User Interface)界面来验证服务端的复杂逻辑,因此,服务端开发工程师在进行非功能性设计时,需充分考虑可测试性。
2.3 应用安全、异常处理、扩展性、兼容性
非功能性设计涉及面广,除了上面介绍的稳定性和可测试性,还有应用安全、异常处理、扩展性、兼容性等方面,如下图所示。
3、开发技术栈与工具
3.1 编程语言与框架
后端开发,编程是最基本的能力。目前,全球已经投入使用的编程语言超过 50 种,其中多数可用于后端开发,但术业有专攻,不同语言的流行度和学习成本不一样,各自的特性也有较大差异。在选择开发语言时,可以参考国内大厂的主流编程语言。
序号 | 企业 | 服务端主流编程语言 |
---|---|---|
1 | 阿里巴巴 | Java |
2 | 腾讯 | C++、Go |
3 | 字节跳动 | Go、Java、Python |
4 | 百度 | PHP,Python |
5 | 蚂蚁金服 | Java |
6 | 网易 | C++ |
7 | 京东 | Java |
8 | 美团 | Java,Go |
9 | 微软 | C++ |
10 | 中小厂 | Java |
框架是实现了某应用领域通用功能的底层服务。使用这种框架的软件开发者可以在通用功能已经实现的基础上开始具体的系统开发。框架提供了所有应用期望的默认行为的类集合。具体的应用通过重写子类或组装对象来支持应用专用的行为。通俗地说,框架是完成了某种应用的半成品,它可以提供一些常用的工具类和基础通用化的组件,基于此,软件开发者可以专注于自身业务的开发。
针对部分主流服务端编程语言,下面是对应的常用框架,如下表所示。
序号 | 编程语言 | 常用框架 |
---|---|---|
1 | Java | Spring,Spring MVC,SpringBoot,Mybatis,Hibernate,Struts,Log4j |
2 | C++ | ASL,Boost,ffead-cpp,JUCE,Loki,Ultimate++,Dlib,Folly,libPhenom |
3 | Go | Gin,Gorm,Beego,Iris,Buffalo,Echo,GoFrame |
4 | Python | Django,Flask,Web2py,Bottle,Tornado,webpy |
3.2 集成开发环境与工具
集成开发环境 IDE
-
集成开发环境(Integrated Development Environment,IDE)是指用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。
-
集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套件。所有具备这一特性的软件或者软件套(组)都可以叫集成开发环境。IDE 可以独立运行,也可以和其他程序并用。
-
一个集成开发环境的易用性,很大程度上除了编辑器本身的质量,还取决于对应插件生态丰富程度,在特定的开发场景下是否能找到易用的工具插件。
常用的IDE有以下两种
- VSCode:全称Visual Studio Code,是由微软开发的一款功能强大的现代化轻量级IDE,社区版免费,通过它强大的插件扩展能力,VSCode几乎支持所有主流语言(C++、Java、Go、Python等)的项目开发。
- JetBrains:是一家捷克的软件开发公司,该公司出品了支持Java、C++、Python、Go等主流编程语言的系列知名IDE,堪称IDE界集大成者。其中最具代表性的是IntelliJ IDEA,在业界被公认为最好的Java IDE。
代码管理利器 Git
- 在实践中,一个软件项目通常由多名工程师协作完成,工程师各自开发自己所负责部分的同时,还需兼顾整个项目。由几个人协同开发的小项目尚可通过人力管理来应对,但几十人、几百人协作的项目呢?如果没有一个强大的工具支撑,那将无疑是人力“黑洞”,著名的版本控制软件 Git 便是在这种背景下诞生的。
- 其他版本管理还有svn等,但是一般采用的最多的还是git。
建模工具
- 为了提升设计环节的沟通效率,在较大的项目中,业界一般采用建模的方式进行交流。常用的图表类型,例如:类图、用例图、序列图、状态机设计图、动态图、组件图、部署图、对象图、交互概述图、支持使用事件案例流、生成事件案例流序列图、需求管理、需求图、文本分析等。
- 常用UML建模工具如下:Visual Paradigm是一款常用的适用于大型项目的UML建模工具。 PlantUML也是一款好用的UML建模语言,可以根据代码生成UML。其他小型项目还可以适用的有drawio,visio等等。
- 一般大公司,也会自己建设自己的UML建模工具,确保相应的建模图标存在自己的数据中心内,以确保数据的安全性。
- 更多内容可以参考:【软件工程】建模工具之开发各阶段绘图——UML2.0常用图实践技巧(功能用例图、静态类图、动态序列图&状态图&活动图
3.3 数据库与数据存储
信息时代,数据已悄然成为企业的核心资产,由于数据库是数据唯一的持久层,几乎所有的业务流程最终都依赖数据库中的数据,因此作为后端开发工程师,掌握数据库及数据存储技术尤为重要。
数据库:
- 大致可以分为两大类,即 SQL 数据库和 NoSQL 数据库。SQL、NoSQL数据库在存储数据类型和存储方式上差异较大。
- SQL(Structured Query Language)数据库,指关系型数据库,主要代表有 SQL Server、Oracle、MySQL、PostgreSQL、SQLite。
- NoSQL(Not Only SQL)泛指非关系型数据库,主要代表有 MongoDB、Redis、HBase、Memcached。
- 关系型数据库 : 适合存储结构化数据,如用户的账号、积分、等级、注册时间等。这些数据通常需要做结构化查询,比如过滤出所有积分大于 1000 的用户,使用 SQL 查询就非常方便,这类场景下,关系型数据库就要胜出一筹。
- 随着互联网的发展,海量数据场景越来越多,如发微博、发微信、发评论等。一方面,这些数据规模大,增长的速度难以预计;另一方面,这些数据类型比较复杂,可能同时包括文字、图片、音频、视频等,使用 SQL 无法直接存储。关系型数据库在应对这些场景时显得有些力不从心,逐渐暴露出许多难以克服的难题。因此出现了针对大规模数据场景,以性能卓越和应用便捷为目标的数据库产品——NOSQL 数据库。NOSQL 数据库是主要根据 “非关系实体模型”的数据库,NOSQL的原意为“Not only SQL”,而不是“NoSQL”,显然,NoSQL 数据库的出现并不是要完全否认或替代关系型数据库,只是做为传统关系型数据库的一个合理补充。
3.4 中间件与分布式
中间件(Middleware)是一种应用于分布式系统的基础软件。
- 从纵向层次来看,中间件位于各类应用、服务与操作系统、数据库系统以及其他系统软件之间,主要解决分布式环境下数据传输、数据访问、应用调度、系统构建、系统集成和流程管理等问题。
- 目前,中间件并没有很严格的定义,但业界普遍接受 IDC 的定义:中间件是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于服务器的操作系统之上,管理计算资源和网络通信。
- 从这个意义上可以用一个等式来表示中间件:中间件=平台+通信,这也就限定了只有用于分布式系统中才能叫中间件,同时也把它与支撑软件和实用软件区分开来。
消息中间件
- 也称消息队列,是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削峰等问题。
- 它可以实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。
- 消息队列在电商系统、消息通讯、日志收集等应用中扮演着关键作用,以阿里为例,其研发的消息队列(RocketMQ)在历次天猫“双十一”活动中支撑了万亿级的数据洪峰,为大规模交易提供了有力保障。
- 作为提升应用性能的重要手段,分布式消息队列技术在互联网领域得到了越来越广泛的关注 。常用的分布式消息队列开源软件有 Kafka、ActiveMQ、RabbitMQ 及 RocketMQ。
事务式中间件
- 事务式中间件又称事务处理管理程序,是当前用得最广泛的中间件之一,主要用于解决分布式环境下的事务一致性问题。
- 在单机数据库下很容易维持事务的 ACID(Atomicity、Consistency、Isolation、Durability)特性,但在分布式系统中并不容易,分布式事务中间件可以保证分布式系统中的分布式事务的 ACID 特性。
- 通常,分布式事务中间件可支持 DRDS、RDS、MySQL 等多种数据源,并兼容消息队列实现事务消息。通过各种组合,可以轻松实现分布式数据库事务、多库事务、消息事务、服务链路级事务等多种业务需求。常用的分布式事务中间有GTS、TXC、Seata等。
数据中间件
- 处于底层数据库和应用系统之间,主要用于屏蔽异构数据库的底层细节的中间件,是客户端与后台的数据库之间进行通信的桥梁。
- 数据中间件一般用于解决海量请求下数据访问瓶颈及数据库的容灾问题,具备分布式数据库全生命周期的运维管控能力,支持分库分表、平滑扩容、结果集合并、SQL解析、数据库容灾和分布式事务等特性。开源的数据中间件有Vitess、MyCat、Atlas、OneProxy等。
- 总体来看,目前开源的数据中间件比较少,广受认可的更是寥寥无几,大型互联网企业几乎都自研的数据中间件,如阿里的DRDS、蚂蚁的 Zdal、京东数科的 CDS、美团点评的 zebra 等等。
3.5 操作系统与应用部署
操作系统
- 对于服务端研发工程师,学习并掌握操作系统知识极为重要。通常,服务端程序几乎都是部署在Linux操作系统的服务器上的。
- Linux 系统相关的知识点非常多,市面上介绍 Linux 系统的书籍基本都是“大部头”,通篇学习实属不易,效果也很难保证。对于服务端开发工程师,可重点学习一些常用的命令和操作:
常用帮助命令
文件和目录管理
Vim文本编辑
文件系统与文件查找
应用部署
- 工程师开发的代码需要经过编译、打包等流程,并最终部署到服务器上,才能运行并对外提供服务。在 2014 年前,生产环境应用部署一般是通过工程师编写脚本实现,而开发环境则基本是手动部署,效率普遍较低。
- 经过多年的发展,目前在一些头部互联网企业,研发平台和流程已经非常完善,不仅可以支持不同研发环境下自动编译、部署,而且能提供场景化分析、定制化质量和风险控制能力。研发平台化、流程标准化使研发更加简单、高效、可靠的同时,也对工程师屏蔽了背后的技术细节,某种程度上对初入职场的服务端研发工程师是不利的,应用部署不应该成为一个“黑盒”。
- 应用部署的发展历程,大致可分为物理机部署、虚拟机部署和容器化部署三个阶段。读者可重点了解容器化部署。
容器化部署
- 为了解决虚拟机部署的不足,容器技术应运而生。容器化部署的本质是构建一个完整、独立的运行环境,包含三个关键:环境隔离、资源控制和文件系统。
- Docker 便是容器化部署的佼佼者, 自2013年发布,目前已成为了首屈一指的容器平台。它能提供轻量的虚拟化和一致性环境,允许将应用和其依赖的运行环境打包在一起,打包好的“集装箱”(镜像)能够被分发到任何节点上执行,无需再进行配置环境的部署。
- 如此一来就解决了开发和部署应用时环境配置的问题,规范了应用交付和部署,降低了部署测试的复杂度以及开发运维的耦合度,极大提升了容器移植的便利性,便于构建自动化的部署交付流程。
运维监控与日志监控
- 运维监控对应用稳定运行、业务效果感知十分重要。通过日常运维监控,一方面有助于预警、定位问题,从而快速解决,避免影响扩大化;另一方面,还可以洞悉业务效果和发展趋势,从而帮助业务决策。
- 在互联网企业,对于一个上线运行的产品,运维监控在其整个生命周期中将一直存在。当产品用户规模较小或业务场景较少时,运维监控通常由产品和研发兼任,甚至完全由研发负责;当产品的用户量增长到一定规模或业务场景增加时,运维监控通常会逐步独立出来由专职人员负责,通常称为 SRE(Site Reliability Engineer)。
- 在实践中,如何开展运维监控呢?基础监控(CPU、Load、硬盘、内存、网络等),一般可借助专业的监控工具(如Anturis、SeaLion、Icinga、Munin 等),并非服务端研发工程师专长。
- 事实上,对于服务端研发,最重要的依托是日志,基于规范的日志可以快速构建、感知常用服务指标。站在业务角度,合理打印日志不仅能辅助定位问题原因,同时可以多维度聚合分析各类场景。某种程度上,排查问题的过程,其本质就是日志结构化还原的过程。如果日志能结构化还原特定场景,那么该场景就能快速被定位。
参考资料:1,2,3,4,5