首页 > 数据库 > 数据库开发技术 > 架构设计流程:详细方案设计
在完成备选方案的设计和选择之后,我们可以稍微放松一下,因为我们已经过了架构设计过程中最困难的部分。然而,整个架构的设计工作还远未结束,作为架构师,我们仍需继续努力。接下来的步骤是进一步深化和细化我们选择的备选方案,把它转化为一个实际可执行的设计方案。因此,我将在今天的讨论中介绍架构设计流程的第四步:详细化方案设计。
简而言之,详细方案设计的任务是锚定方案涉及的关键技术细节。
例如,如果我们决定使用 Elasticsearch 实现全文搜索功能,我们就需要决定是为每个业务线建立单独的索引,还是统一使用一个大索引;决定副本的数量是两个、三个还是四个,以及集群中的节点数量是三个还是六个等。
若选择了 MySQL 进行数据库分库分表,我们需要确定具体哪些表需要进行这样的操作,依据什么维度进行分库分表,以及如何处理分库分表后的联合查询问题。
如果引入 Nginx 来处理负载均衡,我们需要确定如何配置 Nginx 的主备方案以及选择哪种负载均衡策略(是权重分配、轮询、ip_hash、还是其他)。
可以看出,详细设计方案中包含的技术选择与备选方案阶段有些类似。例如,Nginx 的负载均衡策略选择,虽然备选策略有多个(包括轮询、权重分配、ip_hash、fair、url_hash),但具体选择哪个实际上更为简单,只需根据各技术的适用场景进行选择即可。

例如,对于 Nginx 的负载均衡策略,可以根据以下简单规则来选择:
轮询(默认):按时间顺序将请求逐一分配给不同的后端服务器,保持请求分配均匀,若服务器宕机,可自动剔除。
加权轮询:依据服务器权重进行请求分配,适用于服务器性能参差不齐的情况。
ip_hash:根据用户IP的hash结果分配请求,每个用户固定访问一个服务器,适用于需要会话支持的应用,例如电子商务平台。
fair:根据服务器的响应时间分配请求,优先考虑响应快的服务器,适用于后端服务器性能不一的情况。
url_hash:根据请求URL的hash结果分配,每个URL固定由一个服务器响应,适用于能缓存URL响应的后端。
通过这种方式,我们可以根据实际业务需求选择最合适的策略。例如,对于电商平台这种与用户会话强相关的架构,使用ip_hash策略进行负载均衡可能是最佳选择。
在详细设计方案阶段,我们可能面临一种困难情况,即在深入细节设计后发现原先选定的备选方案实际上行不通。这通常是因为在方案选择阶段漏掉了一些关键的技术细节或重要的质量属性。例如,我有过一个经历,在方案选择看似可行,但进入详细设计阶段时才意识到方案涉及的细节过多,整个开发周期可能长达一年,最终不得不放弃原方案,重新设定项目目标和计划。这种情况的根本原因在于初期评估时忽视了开发周期这一关键属性。
幸运的是,我们可以通过以下措施有效预防这种情况:
架构师不仅需要负责方案设计和选择,还应对所选方案的关键技术细节有深刻理解。例如,在选用 Elasticsearch 作为全文搜索解决方案时,架构师应对其索引、副本、集群等核心技术有充分了解,而不是仅仅因为听说 Elasticsearch 性能优异。架构师也应避免成为那种经常说“细节后面再讨论”的所谓“PPT 架构师”。

通过分步骤、分阶段和分系统的方法来降低方案的复杂度,因为方案越复杂,某个细节可能导致整个方案失败的风险越大。简化复杂度有助于减少这类风险。
对于本质上复杂的方案,应采用设计团队的方式进行,这样可以利用团队成员的集体智慧和经验,避免单个或少数架构师可能遇到的思维或经验盲点。
详细方案设计实战
尽管我们在上一期为“前浪微博”消息队列的架构设计中选定了备选方案 2 作为最终解决方案,但该方案在备选方案阶段的描述还相对粗略,还不足以指导开发人员进行具体的设计和开发工作。因此,基于该方案,我们需要进一步的细化。
数据库表设计细化:
设计两种类型的表:日志表用于快速存储消息至 MySQL,消息表每个队列对应一张。
发布消息时,首先写入日志表,日志表写入成功则视为消息成功存储;后台线程定期从日志表中提取数据,写入消息表。
读取消息时,直接从消息表读取。
日志表(MQ_LOG)包括字段:日志ID、发布者信息、发布时间、队列名称、消息内容。
消息表的名称与队列名称相同,字段包括:消息ID(自增)、消息内容、发布时间、发布者信息。
日志表需定期清理已迁移到消息表的数据,消息表保留最长30天消息。
数据复制细化:
使用 MySQL 的主从复制机制,只复制消息表,不复制日志表。
主备服务器切换细化:
使用 ZooKeeper 管理主备状态,主备服务器都在 ZooKeeper 中注册,主服务器路径为“/MQ/server/分区编号/master”,备份路径为“/MQ/server/分区编号/slave”,节点类型为临时性(EPHEMERAL)。
备机监控主机节点,一旦主机断线,备机立即切换状态,开始提供消息读取服务。
业务服务器消息写入细化:
消息队列系统定义生产者和消费者两个角色,每个角色有唯一标识。
提供 SDK 供业务系统调用,SDK 读取配置中的服务器信息,使用轮询算法向主服务器发送写入请求。若主服务器响应异常,SDK 将请求转发至下一台服务器。
业务服务器消息读取细化:
提供 SDK 供业务系统使用,SDK 轮询所有服务器发起读取消息请求。
消息队列服务器记录每个消费者的消费状态,即已读取的消息位置,根据请求返回下一条未读消息。
业务服务器与消息队列服务器间通信协议细化:
考虑到系统将接入多种编程语言开发的系统,选择 TCP 作为传输协议,使用 ProtocolBuffer 作为数据格式,以提高系统间的兼容性。
这些仅是一部分细化设计的例子,实际的设计方案需要更多详细的考虑和细化。通过这些例子,可以展示如何对一个方案进行进一步的具体化和实施规划。
原文作者:二进制跳动;如有侵权,请联系管理员删除。