AI算法与应用 & 全栈开发 & 前端开发 & 后端开发 & 测试开发 & 运维开发

AI-driven算法与应用 & 全栈开发 & 前端开发 & 后端开发 & 测试开发 & 运维开发

前言

AI会改变开发模式甚至行业岗位

1.AI-driven 算法与应用

1.1. 12 days of OpenAI

  • day1: o1解决理工科问题(含数学、工程、代码等),具备较强能力,比o1 preview表现好。o1能很专业的解决工程问题,且接受多模态输入。
  • day2: Reinforcement fine-tuning for your own use cases. Use o1-mini with reinforcement your own data to solve.
  • day3: Sora. For Video Generation and a a series of video makeing functional. End to end product, a tool.
  • day4: Canvas. Wirting & Coding. 我觉得像是把gpt对话框扩展成了一个编辑器+,在canvas里写作和写代码,可以直接给你反馈,而且针对代码,他不仅是能给你建议,而且能直接run你的代码,所以甚至不是编辑器+,是一个和gpt高度融合的通用IDE。
  • day5: Apple mobile devices. ChatGPT in mobile devices.
  • day6: Senta. ChatGPT in audio. Advanced voice. 在手机上,直接与GPT对话,并share摄像头/share屏幕,然后咨询问题处理方式,他做出指导。真正的多模态嵌入到移动设备当中。
  • day7: ChatGPT in project. 读项目代码不会被卡脖子了。但我认为需要具备基础代码能力。
    Tips: 前端好好的。后端也好好的。Not over. 讲座的是前端
  • day8: Search. You can search web information in chatgpt.
  • day9: Developer. Building on top of Open AI API. One, like normal, use JSON Schema. Two, real time API in video/audio, so crazy. 只需要12行代码,你就创建了和open ai api的语言实时对话关联。视频中介绍了一种商业场景,在玩具中放上miccontroller模块,与玩具实时对话。让人惊讶点在于,你不需要设置很多硬件设备,不需要制造很多硬件设备,只需要有一个带wifi的,能语言输入输出mic,能充电的小小处理器,然后连上chatgpt,就能实现。Three, fine tuning customization. 除了给精确的输入输出的监督微调,还能给输入,输出给perfer和non-perfer的perfering微调。
  • day10: 直接打电话给chatgpt,不通过network,降低使用门槛。
  • day11: Desktop App. Interact with terminal. Interact with code in an IDE. 直接监控屏幕实时变化。
  • day12: Next frontier model. O3 and O3 mini. AGI. AGI测试集。Interesting, AI里找规律的问题,和行测题很像。Think deeper please.

1.2. AI Developer Studio

开发平台/工具一般包含多种先进的LLM,并开放了很多定制化设置,供用户开发。相比于纯ChatGPT这种使用工具,AI Developer Studio是基于AI的工作平台。
一般来说,满血的账号费用都较高,免费使用的阉割了很多功能,仅开放一小部分数据训练、参数调整以及少量LLM供选择。

1.Vertex AI (Geogle)

  • Vertex AI Studio:Multimodal、Language(text/tasks/code…)、Vision(video/image…)、Speech(audio…)

  • LLM (Large Language Model) prompt: Zero-shot prompting / One-shot prompting / Few-shot prompting

  • Prompt design:
    1.freedom:大模型直接问答
    2.structured(Context给出背景,Example给出想要的input和output,以规训重点,最后Test):大模型根据你的偏好,save一个特定大模型,回答你的问题

  • How to design Prompt(Prompt工程师):
    Be concise
    Specific and clearly-defined
    ask one task at once
    ask to classify instead of generate(要选择题最好不要发散式)
    include examples

  • temperature(概率分布): 对回答的随机程度进行调优, 0-1, 0是确定, 1是随机, 即越靠近0概率越大
    top K: 对回答的概率最高的一部分答案进行随机
    top P: 对回答的概率最高的答案进行累加,直到累加值达到top P,即对回答的概率最高的答案进行随机

  • 模型调优(Model tuning):
    How to customize and tune a gen AI model:
    越来越偏技术:
    1.Prompt design: Input(required) Context(optional) Example(optional)
    2.Adapter tuning(Parameters-efficient tuning): Fine-tuning a model on a specific task or dataset.监督,给出一小部分样本调优参数
    3.Reinforcement tuning(Parameters-efficient tuning): Fine-tuning a model on a specific task or dataset.非监督调优
    4.Distilling(Student model weight updates): 在Geogle cloud可以做, 可以更加生成特定模型。我理解就是迁移学习。

  • Difference between AI and Machine Learning:
    输出确定的、“旧的”东西,用学术的话,输出的是Number、Discrete、Class、Probability的,叫ML。
    能输出“新的”东西,用学术的话,输出的是Natural language、Image、Audio(即所谓的非结构化数据),叫GEN AI。
    举个例子,如果输入猫狗图片,且每张图片label是文字“猫”、文字“狗”。训练后模型最后能预测猫狗,这叫ML。
    如果输入大量的猫狗图片,且按照你想要的方式进行训练(这里涉及到模型了,具体需不需要lable或者怎么lable有疑惑)。训练后模型最后能生成新的猫狗图片,这叫Gen AI。

  • AI Develop
    Data Security,开源的模型,私有化部署local AI(teacher student…)

2.Azure AI Foundry (Microsoft)

1.3. Transformer

1.绝大多数先进的多模态大模型(如 GPT-4o、DeepSeek、Qwen2.5 等)的底层架构均基于 Transformer,但会根据多模态需求进行扩展和优化。Transformer 的核心优势在于其 自注意力机制(Self-Attention),能够高效建模长距离依赖关系,并天然支持并行计算。对于多模态任务(文本、图像、音频等),模型会通过以下方式扩展:

  • 多模态输入编码:将不同模态数据(如文本、图像、音频)统一编码为向量序列。例如:图像被切分为小块并通过视觉编码器(如 ViT)转换为嵌入向量;音频通过语谱图、波形编码、短时傅里叶变换等预处理方式,预处理为向量序列(my work)。
  • 跨模态注意力机制:允许不同模态的嵌入向量在注意力层中交互。

2.Transformer 模型的训练方式
核心训练范式:自监督预训练 + 有监督微调

  • 阶段 1:预训练(自监督学习):让模型从海量无标注数据中学习通用表示(如语言规律、跨模态关联)。输入和标签均来自同一数据,无需人工标注。典型的方法有掩码语言建模、自回归预测、多模态对齐等
  • 阶段 2:微调(有监督学习):针对特定任务(如问答、图像描述生成)优化模型。需要人工标注的输入-输出对。指令微调、强化学习等
  • 阶段 3:推理(部署后)。训练时需标签(显式或隐式),推理时仅需输入。

references:
Attention is all you need
十分钟理解Transformer

1.4. AI Agent & RAG

  1. AI Agent
  • 能够基于任务目标执行(行动,动作,action)多步骤动作的系统,它能通过调用工具、API 、知识库、插件、代码库等等,动态规划并完成复杂任务。Agent 具备一定程度的自主决策能力。
  • 核心组成:
    Brain: 处理/计算/记忆/计划/决策
    Perception: 多模态输入
    Action: 调用工具、SDK、API 、知识库、插件、代码库等等,完成交互
  1. RAG, Retrieval Augmented Generation
  • LLM应用方案。将大模型应用于实际业务场景遇到几个问题:1.无法具备全部知识(包括实时数据、非公开数据、私有数据、私有专家知识等) 2.幻觉(无法具备全部知识)3.数据安全
  • 核心思想:检索 增强 生成。检索体现在:私有数据/数据存储到向量数据库(因为结合了transformer训练时数据处理word embedding)后高效的检索能力,召回目标知识。生成体现在:大模型+Prompt工程,将召回的知识合理利用,融入到Prompt里,大模型更根据目前的提问+能够参考相应的知识(上下文),生成目标答案

Tips:
Prompt工程:一般包括任务描述、背景知识(检索得到)、任务指令(一般是用户提问)

1.5. LangChain

LangChain for LLM Application Development:

  • LangChain is a open-source framework for developing applications powered by language models(LLM Applications).
  • python version(packages) & JS/TS version(packages)
  • Composition and modularity
  • Components / Off-the-shelf chains: Off-the-shelf chains make it easy to get started. Components make it easy to customize existing chains and build new ones.

modules:

  • Components fall into the following modules:
    1.Models
    2.prompt and output parsers
    3.index(for RAG)
    4.Chain(eg. prompt + LLM + output parsing. And more and more application chains)
    5.Agents(LLM base, Memory(chatbot), Action)

Models, Prompts, Output Parsers: API/Local. (LangChain’s hello world)

Memory: LLMs are stateless. Chatbots appear to have memory by providing the full conversation as context. However, LLMs API is charge by token. Langchain provide some memory tricks, feature like keep just a number of conversiation/tokens.

Chains: use ‘MoE’ idea in Enginner. Intertesting.

Q&A with Documents: word embedding, vector database, index. query come, after this, give LLM. Stuff method, simple RAG. Additional 3 methods: Map_reduce/Refine/Map_rerank

Evaluation: use LLM to evaluation answer.

Agent: pre/cus tools.

  • LCEL

LangChain Expression Language (LCEL): 异步、批处理和流支持
eg. 代码里写chain = prompt | model | output_parser,类似学linux操作系统里的linux命令的piple概念。

  • ReAct
    The ReAct (Reasoning and Acting) pattern is a framework for building AI agents that combine reasoning (thinking) with acting (taking actions).Break Down.

Built an agent from scratch.

Prompts: can import. allow reusable prompts(LangChain hub).

Tools: get a tool from the library.

Others: pattern is also like graphs.

  • LangGraph

Knowledge Graph 知识图谱:是结构化的语义知识库,用于迅速描述物理世界中的概念及其相互关系。实体,关系,实体。

图数据库:Neo4j

LangGraph 是一个结合 LangChain 与知识图谱(Knowledge Graph)的应用,旨在通过结构化的知识库增强语言模型的理解和响应能力。

Graphs to build Agent:
1.Nodes(Agents or functions), Edges(connect nodes), Conditional edges(decisions)
2.Data/State: State Memory (State Snapshot)
3.Image: can draw the image of your graph.
4.powerfull Tool: Search Tool(like Tavily)
5.persistence and streaming: usefully in long running application.
checkpoints(database, SQL, NoSQL) for persistence.
get individual messages / observation message / token of streaming(not .invoke)
Above of these can config as 2 thread to separate 2 mode. (another model don’t have this model’s persistence/memory)
6.user/human can interrupt the loop and choose(improve)

  • SQLite

一款轻型-轻量级的数据库,是遵守ACID的关系型数据库管理系统。

架构:MySQL 是一个客户端/服务器架构的数据库管理系统,这意味着它需要一个单独的服务器进程来运行。而 SQLite 是一个无服务器的数据库管理系统,它直接读取和写入磁盘文件

存储:MySQL 数据库存储在磁盘上的文件中,但需要通过 MySQL 服务器进程来访问和管理。SQLite 数据库也存储在磁盘上的文件中,但可以直接通过 SQLite 命令行工具或编程语言的 SQLite 库来访问和管理。

SQLite是文件级的。所以替代的是文件存储的级别,不是client/server数据库的级别。单体/接单用足够。直接给它存成文件。

LangGraph写Agent用到了。

1.6. MCP, Model Context Protocol

MCP, Model Context Protocol,旨在统一大型语言模型(LLM)与外部数据源和工具之间的通信协议。分client和server。client在host里。

host指的我们的调用程序本体,可以是LLM程序,IDE,AI工具,LangChain代码框架。

client / server,感觉和之前原始手写socket一个意思,一个client一个server建立网络通信TCP/IP。

协议

阿里云百炼 业内首发MCP服务,与开发者共同打造企业级AI应用新生态

1.7. Ollama

  • Get up and running with large language models.
  • 本地部署(非常方便的)多种LLMs
  • 支持模型微调
  • 支持命令行运行与直接交互、Ollama 的 Python SDK使用、API交互、WebUI

1.8. Dify

1.9. LLM应用落地方法论 & 从技术创新到场景落地(讲座)

方法论:

  • 概念验证:确定使用场景、案例、数据。初步测试LLM是否符合预期
  • 评估LLMs: 测试并选择出最合适的LLM模型
  • 部署、监控和安全:Local VS Cloud-Based deploy
  • 持续性和可靠性:CI/CD
  • 模型迭代/管理
  • 经典场景与方向:RAG & Agent

讲座:

通义千问与DeepSeek的技术突破及企业应用前瞻

大语言模型:通用模型(基础模型能力/Agent两条线,我理解就是算法和工程两条路)(语料,T级数据) / 推理模型
多模态模型:多模态理解 / 多模态生成

DeepSeek:真实能力 / 算法 / 工程 / 其他工作 - > 爆

  • deepseek V3 突破性技术与应用

MoE / 671B / excellent / low cost

Architecture Opti:
MLA(Multi-Head Latent Attention,空间换时间->reduce KV cache压缩->损耗?->细节处理,不同压缩方式)
MoE(Mixture-of-Experts, router选Experts。多个Experts -> load balancing ->打分选不同Experts)
MTP(预测下一个token->预测下两个token->预测下n个token)

Infrastructure Opti:
Train Framework(并行,硬件?)
DualPipe(bid pipeline scheduling,减少了last one和中间的waiting(空泡),硬件?)
FP8 training(浮点数)

  • deepseek R1 突破性技术与应用

RL auto / few shot prompting / Distillation / 规则奖励reward / better reasoning

pretrain -> SFT (labelled) -> RL

deepseek-r1-zero: Training Template (Prompt Engineering) / Rule-based Reward Models (Accuracy reward: Math and Coding. Format reward: < think >) / GRPO (Group Relative Policy Optimization)

deepseek-r1 (solves issues of deepseek-r1-zero): deepseek-v3-base +SFT(poor readability)+RL(reasoning + language mixing)+SFT(reasoning + general)+RL(human preference alignment)

Distillation (base-model ability is important)

2. 全栈开发

2.1. 系统建设方法论及具体方法

  • 一、方案调研:

网络搜索、AI、同学同事圈,确定解决方案:

选择一:外采
根据调研结果,联系供应商,明确需求,明确报价,明确时间点,明确数据安全问题。

若采用此方案,后续工作只需要作为业务方和供应商的中间媒介和监督者的角色即可,即将业务需求尽量翻译为计算机实现方式(也可以让供应商提供该人员)给到供应商,同时对供应商的开发进度、产品质量等方面做总体把关,不需要了解技术细节。

即,此时计算机从业人员为产品经理 & 项目经理 & 甲方经理(类似于土建行业的甲方)角色,因此后续工作也将不再涉及。

选择二:自研
通过需求,抽象出我们想要的功能,可以借助AI工具帮我们做抽象。然后根据相关关键词,通过网络搜索、AI、同学圈、同事圈四个方向进行调研,形成框架思路。如是简单的增删改查系统,我们可以直接进行实现,如涉及到核心逻辑/业务逻辑,则需更进一步思考大概的技术解决方案。

与此同时,我们需要考虑基础设施的问题,即我们的系统是部署到自有物理服务器上还是部署到上,亦或是混合的方式,亦或是我们只需要一个微信小程序,一般来说系统级应用微信小程序搞不定。

对于大型互联网公司,往往有自己的物理机房,甚至有自己的云集群,且基础设置较为完备,因此不需要考虑此问题。

对于一些敏感性企业(银行/国企),由于数据的敏感性,也需要部署到自己的物理服务器上,或是本地&云混合的方案。

对于中小型企业,往往可以直接上云,公有云相对私有云价格更合适,若想保护数据安全也可以采用私有云部署。

上云的一个很大的好处是即租即用即部署即调整。举个例子,你有一个系统,如果想要部署到自己的服务器上,首先你需要采购物理服务器,然后要布线网络,然后要对服务器环境进行初始化,如安装一些基本的系统运行环境,并在一个相对不友好的界面监控。与此同时,你的服务器资源也不是百分百利用,甚至你还要考虑网络安全、设备安全等等一系列的运维问题。如果采用市场上常用的Iaas、PaaS等云服务,那么将极大的节省前期建设成本、中期运维/管理/监控成本、后期回收成本以及一系列的安全问题、法律问题(IP、DNS备案等等)。

最后,在敲定解决方案后,形成第一次汇报报告。

注意事项:对于百分之80的情况,我们需要用敏捷开发的思想来构建系统,即step by step完成最终目标。当然,如果你的+1/+2允许你更完善,那便可以多想一些技术实现。总而言之:沟通出平衡点老板关注的是时间成本和金钱成本,以及回报,用英语说就是Tell Me Your Story。最后才可能感兴趣实现。兄弟们,哈哈

  • 二、系统架构设计:系统包含哪些平台、宏观上具备哪些功能

根据市场常见手段或自己的业务人员拉会头脑风暴,明确高优先级需求,抽象出架构图,一定要明确包含哪些平台、包含哪些核心功能。

与此同时,明确技术方案。即采用全栈一把梭方案(常见的如python Dj框架),还是采用前后端分离方案(常见如国内公司后端Java配spring、国外公司后端c#配.net等等,前端vue、react等),数据库一般国内用MySQL,国外MS SQL。对于进阶级别的系统,需要考虑Nginx做前端服务器做反向代理,后端部署服务器若考虑分布式服务还需要经典的spring cloud配合服务注册、服务发现等,再进一步,需不需要redis缓存、需不需要kafka消息队列对并发性做一些优化,这些都要根据具体需求考虑,亦或是前期留下相关接口,后期迭代时再考虑接入。

此时有许多细节需要注意,比如orcal jdk和open jdk的区别,MySQl企业版和MySQL Community Server的区别。许多国外工具讲究租的概念,即可能你可以下载下来使用,一段时间后你无法使用或提示会有账单,且作为企业级应用具有很多安全风险、法律风险。因此,需要具备对开源工具和闭源工具的识别。

注意事项:AI辅助加速设计进程

  • 三、用户界面设计:统一UI风格,用户友好,不学即用

根据需求敲定UI页面,确定包含哪些交互及展示方式,与业务方碰头,进一步明确需求。(该部分要控制好时间,根据情况决定方向。如果时间不乐观警惕业务人员陷入页面细节优化)
注意事项:AI辅助加速设计进程

  • 四、数据模型设计:数据库表设计

范式、索引。具体设计思路可以按上面的想法,同时注意对业务场景的实体抽象要尽可能合理,符合人类社会对事物的认知。注意事项:AI辅助加速设计进程,且可以辅助出UML图,帮助开发实现。

  • 五、逻辑功能设计:明确核心逻辑所采用的算法实现。比如某些核心系统在状态转移的逻辑怎么实现。

  • 六、敏捷开发人力计划:明确方案。

明确阶段目标、明确需求表达、明确接口定义(对于前后端分离项目来说,接口就是前后端工作集成的协议,必须尽可能今早敲定),合理根据开发量、难度设定人力。

  • 七、代码开发

代码开发中的一些最基本的规则:

1.后端代码逻辑中,运用回溯等算法时,注意边界条件,尽量逻辑完备。注意算法的时间和空间复杂度,善用各类数据结构,最简单的一遍Map可以替代N遍循环。
2.注意代码的保护。加try catch保护系统稳定。
3.数据的增删改注意并发性和完整性,考虑事务。数据库的查考虑效率。
4.代码善用设计模式可以提高可维护性。
5.前端代码考虑数据为空的展示,考虑页面布局大小的flex展示,考虑渲染压力,考虑表单的校验,考虑用户的输入不规范处理、考虑数据初始化等等。

注意事项:AI辅助可以大大加速开发速度或是代码阅读debug速度具体开发中还有很多实际问题和技术细节,之前的博客中均有记录目前也在这个方向上继续深入

  • 八、测试
    测试相当于传统制造业中的质量部门,从更专业的角度保证我们的产品更加完备。

单元测试:开发人员自测,自己保证功能的可用与完善。

集成测试:前后端链接,将软件的不同部分组合在一起。作为整体保证整个系统的可用与完善。

产品测试:从功能完备性的角度和复杂情况的角度,设计测试案例,保证整个系统的功能完备,符合需求。

安全测试:通过拦截包修改参数、身份验证等专业方式,测试系统的安全性。

性能测试:响应时间、吞吐量、资源利用率,有QPS指标等等。

用户测试/验收测试:由客户或用户对软件进行测试,以验证软件是否满足他们的需求

  • 九、部署及运维:

部署窗口期、是否灰度、部署方案、回滚机制等等。监控软件运行状态。

  • 十、用户支持:

分析用户问题属于系统BUG还是使用问题,耐心解答。一定不能告诉用户不能解决、不知道等拱火回答。

  • 十一、成果展示与结束:Power Point Presentation,论文 / 专利 / 软著,成果落地结束

2.2. Course: IBM Full Stack Software Developer

很多全栈知识来源于这里,包括把前后端开发类比装修。

2.2.1. Introduction to Software Engineering

  1. Software Development Life Cycle, SDLC: planning (including requirements), design, development, testing, deployment, and maintenance.

  2. Requirements Documents
    在软件开发生命周期(SDLC)中,SRS、URS和SysRS是用于描述软件需求的文档。它们分别代表软件需求规格说明书(Software Requirements Specification)、用户需求说明书(User Requirements Specification)和系统需求规格说明书(System Requirements Specification)。下面是它们的详细解释:
    软件需求规格说明书(SRS)

    • SRS是一个详细的技术文档,它描述了软件系统必须做什么,以及如何满足用户的需求。
    • 它包括功能需求、非功能需求(如性能、安全性和可用性)、接口需求、设计约束和假设条件等。
    • SRS是开发团队、测试团队和项目管理人员的重要参考资料,它为软件的设计、开发和测试提供了依据。

    用户需求说明书(URS)

    • URS是由项目团队与用户和利益相关者合作制定的文档,它以用户的角度描述软件系统的需求。
    • 它通常包括用户的目标、期望的功能、操作流程、用户界面需求等。
    • URS是需求分析阶段的重要输出,它为SRS的编写提供了基础。

    系统需求规格说明书(SysRS)

    • SysRS是一个综合性的需求文档,它描述了整个系统的需求,包括硬件、软件、人员和过程等方面。
    • 它不仅包括软件的需求,还可能包括网络、数据库、安全和其他系统组件的需求。
    • SysRS通常在系统层面进行制定,它为系统的设计、开发和集成提供了指导。

    这些文档之间的关系通常是这样的:URS是用户视角的需求描述,SRS是基于URS进一步细化和技术化的软件需求描述,而SysRS则涵盖了整个系统的需求,包括但不限于软件需求。
    在编写这些文档时,应该确保需求的完整性、一致性和可验证性,以便为软件的开发和测试提供清晰的方向。同时,这些文档应该随着项目进展而不断更新和细化,以确保它们始终保持最新和准确。

  3. method of SDLC

a.type

  • Waterfall model: compliance. These methodologies made it very difficult to adapt to change because by the time testing started, not all requirements were relevant anymore. This often resulted in software products that did not meet expectations because they couldn’t change fast enough along with new requirements.
  • V-shape model
  • Agile: Responding to change over following a plan. (Feedback, Modularization, hard to schedule). Scrum methodology

b.testing

  • In my situtation: unit testing, sit, 安全/性能测试,fat,uat
  • In course situtation: Unit testing, Integration testing, System testing, Acceptance testing

c.doucmentation
d.different job roles

  1. Front-end developer
  • To create a website, web developers usually use HTML, CSS (SASS, LESS), JavaScript.
  • JS framework: Angular, React.js (JS library, routing is not of this), Vue
  • multiple browsers, multiple operating system, multiple devices.
  1. Back-end developer
    JavaScript (Framework: Node.js and Express)
    Python (Framework: Django and Flask)
    别把眼睛就放在Java、C++、Go、C#!!!!!
    随着AI发展,开发成本下降,我认为将来一定不会用语言来区分岗位
  2. agile & team work & pair programming
  3. Tools of Development (include all): Version Control & Libraries & Frameworks (框架决定了代码工作流程,it call 控制反转) & CI/CD (DevOps) & Build tools & Packages & Package Manager
  4. technology stack (more bigger then software stack) & software stack:技术栈。
    some interesting stack:
  • MEAN: MongoDB / Express.js / Angular.js / Node.js
  • MEVN: MongoDB / Express.js / Vue.js / Node.js
  • LAMP: 感觉前后端分离,后端用java / c++ / go等,前端用vue php 原生等,都是该的变体
  1. Type of Languages
  • Interpreted (programming) languages (also called script language, go through an interpreter in the OS or Browser): Python, JavaScript, Lua(game), HTML
  • Compiled (programming) languages (Executable files on device): C/C++/C#, Java
  • Query languages: SQL
  • Assembly languages
  1. Pseudocode & Flowcharts

  2. object-oriented programming & procedural programming

  3. Software Design and Architecture

  • UML, Unified Model Language. System Design & Architecture.
  • Component-Based & Service-Based Architectures: Object -> Component -> Service
  • Distributed system architecture: client-server (bs) / peer-to-peer / three-tier / Microservices(HTTP/HTTPS、gRPC) / …
  • 详解 事件驱动 / 微服务
  1. Application environments
    Application environments: dev / test / staging / prod
    Cloud deployment types: Public / Private / Hybrid

  2. Skills of Software Engineer
    Hard Skills of Software Engineer: Design, Build, Maintain, Repair
    Soft Skills of Software Engineer: Team work, Stakeholders

  3. Job titles
    Front-end engineer
    Back-end engineer
    Full-stack engineer
    DevOps engineer
    Software quality assurance engineer
    Software integration engineer
    Software security engineer
    Mobile app developer
    Games developer

2.2.2. Introduction to Cloud Computing

  1. Cloud technology: On demand. Self-serving.
  2. Alibaba Cloud: Aliyun
  3. A cloud strategy: core component of any business strategy today. eg.弹性资源/敏捷部署/高速计算/全球化/AI…
  4. AI / Big Data / IoT / Blockchain
    Blockchain: An immutable network allowing members to view only those transactions that are relevant to them.
  5. IaaS (System Admin)-> PaaS(Dev) -> SaaS(Users)
  • IaaS: is a form of cloud computing that delivers fundamental compute, network, storage to consumers on-demand, over in internet, on a pay-as-you basis.
    Test, Development, Deploy faster / Business Continuity and Disaster Recovery / Scalability / High performance Computing / Economically Balance

  • PaaS: is a cloud computing model that provides a complete application platform to Develop, Deploy, Manage.
    High Abstraction (eg网页点击就能部署) / focus on application develop

mPaaS(mobile Platform-as-a-Service),起源蚂蚁金服。
具体能力见:

mPaaS能力介绍1
mPaaS能力介绍2
实时发布服务能力MDS
离线包
小程序

  • SaaS: a cloud offering that provides access to a cloud-based software.

交付模型:SaaS、PaaS、IaaS

部署模型:私有云private cloud、社区云Community cloud、公有云public cloud(省钱,然而concern Security and Data)、混合云Hybrid cloud

商业优势:省去软硬件成本/构建成本/运营成本等等多种成本,且成本控制监控灵活可变,可快速敏捷部署,用户友好等等多种优势

云计算(cloud computing)中讨论的服务包括基础设施即服务(IaaS, Infrastructure-As-A-Service),平台即服务(PaaS, Platform-As-A-Service)和软件即服务(SaaS, Software-As-A-Service)三个层次的服务。(理解:IaaS如买的阿里云买的服务器、PaaS如mPaas提供了移动平台、SaaS如钉钉,三个层次层层递进

怎么选择?如果有应用,且没时间重新构建cloud native application,则选择IaaS. 如果有应用,有时间,则可以考虑re-platform,如果没应用,但有时间也可以基于PaaS开发cloud native. 如果没应用,没时间,直接买SaaS,因为SaaS很多时候也不是定死的,可以定制化一些东西,当然supply提供support定制更多

  1. Virtualization / Hypervisor: cost saving, agility speed, backup…
  2. Cybersecurity
  3. Containers: Executable Unit of Software. Package Application Code, Libraries, Dependencies. Run anywhere, include desktop, Traditional IT, cloud.
    eg. docker.
    容器化在规模、灵活性、可拓展性(cloud native思想,弹性伸缩复制服务)、统一性等方面超过VM
  4. cloud storage
  • Direct Attached
  • File Storage: IOPS. NFS
  • Block Storage: IOPS
  • Object Storage:
    阿里云OSS( Object Storage Service )
    API to upload/download.
    Bucket: Object can put in Bucket.
    Tiers/Classes: Based on how frequently the data is accessed. Different Tiers, different charges.
    Any Data which is static and read/write speeds are not necessary.
  1. CDN: Content Delivery Network. Make your website faster! Speed!!! 内容分发网络是一种分布式服务器网络,可根据用户的地理位置向用户分发临时存储或缓存的网站内容副本。
  2. Microservices、Serverless
  3. Cloud Native Application: Microservices、Container、解决方案堆栈/复用/弹性/独立/标准化
  4. DevOps: Agile and Lean Thinking, CI/CD构建方案,对测试/部署都有好处。

持续集成(Continuous Integration,CI) :高频代码提交变更集成至共享代码库,并触发自动化构建与测试流程。这种实践能够快速暴露集成冲突和兼容性问题,Git、SVN等版本控制系统为此提供了基础设施支持。

持续交付(Continuous Delivery,CD) :在CI基础上建立的全流程自动化机制,确保代码变更始终处于可发布状态。通过标准化交付流水线(Jenkins/Bamboo等工具实现),使软件产品能够以最小人工干预快速、可靠地交付到预生产环境。

持续部署(Continuous Deploymen,CDep) :CD的高级形态,当代码通过所有质量门禁后,自动完成生产环境部署。这种端到端自动化显著缩短了从开发到交付的周期,但需要完善的测试体系和监控机制作为保障。

持续监控(CM) :通过Prometheus、ELK等工具建立的实时观测体系,对应用性能指标(APM)、日志和基础设施健康度进行持续追踪。

  1. 数字化云改造/现代化改造的3大方面:架构、基础设施、交付方式(工作流程)

  2. 云安全 与 云监控
    Identity and access management, IAM: zero-trust implementation
    OpenID Connect: OpenID Connect 是基于OAuth 2.0协议的现代标准。
    云计算本身提供了许多设施层面的解决方案。

2.3. 低代码 Low-code

(低代码行业市场崛起:预计2025年市场规模将达到131.0亿元-中金企信发布 低代码行业市场崛起:预计2025年市场规模将达到131.0亿元-中金企信发布。美国在低代码领域研究的时间较长,在经历了萌芽期、探索期等阶段后,已经进入到巨头的整合阶段。相较而言,国内对于低代码的研究较晚,目前仍然处于探索阶段。国内低代码产品的应用路径从早期的数据库交付、数据集结构搭建逐渐抽象出各种流程引擎、可视化界面等,而应用也从BPM延伸到更复杂的应用场景如ERP、CRM等应用系统的搭建。同时,低代码开发平台的使用门槛也在降低,主要使用群体由专业开发人员和业务人员共同构成。)

国内外低代码厂商:钉钉宜搭、简道云、氚云(BPM起家)、金蝶云苍穹、炎黄盈动(BPM专家/流程数字孪生)、Mendix…

Node-RED: Low-code programming for event-driven applications. The easiest way to collect, transform and visualize real-time data. Node-RED is built on Node.js, taking full advantage of its event-driven, non-blocking model. 可以直接通过NPM安装,通用IoT编程工具,关键概念:Node节点、Flow流,用户拖拽建立流程。

2.4. Node.js

Node.js is a free, open-source, cross-platform JavaScript runtime environment that lets developers create servers, web apps, command line tools and scripts.

Node.js 是单线程、事件驱动、非阻塞 I/O 模型

  • 单线程:Node.js 在一个单独的线程中运行 JavaScript 代码,这意味着它一次只能执行一个任务。这种设计避免了多线程编程中的复杂问题,如线程同步、死锁和竞态条件,使得代码更加简洁、易于理解和维护
    (之前Java/spring boot的线程池那一套)

  • 事件驱动:Node.js 使用事件循环来处理并发请求。事件循环是一个无限循环,它不断地检查任务队列中的任务,并在任务完成后执行相应的回调函数。这种机制使得 Node.js 能够在一个线程内同时处理多个请求,而不需要为每个请求创建一个新的线程
    (联想到架构范式EDA,事件驱动架构,又联想到消息队列Kafka,又记录联想到什么场景需要?高内聚低耦合,交易处理链路较长的准实时或非实时场景,或是广播类型场景,例如移动商城抢购后需要跟进的一系列动作短信通知、发货申请、更新订单状态等。又发现有什么典型需要处理的错误?重复处理/消费等,所以要考虑幂等。查询类操作还好,变更类操作,一定要考虑幂等设计,联想深入终止。)

  • 非阻塞 I/O:在 Node.js 中,I/O 操作(如文件读写、数据库查询、网络通信等)不会阻塞主线程。当执行这些 I/O 操作时,Node.js 会将这些操作委托给底层的线程池,主线程可以继续处理其他请求。一旦 I/O 操作完成,事件循环会将相应的回调函数放入任务队列中,等待主线程执行
    (之前Java/spring boot的线程池那一套)

Node.js 不适合处理 CPU 密集型任务。
Java 的多线程模型使其能够更有效地处理 CPU 密集型任务。

Node.js:适用于实时应用(如聊天应用、直播流、协作工具等)、微服务架构、流媒体应用、物联网应用等。
Java/Spring Boot/JVM,适用于大型企业级应用、科学计算

2.5. AI-Driven 全栈开发

根据需求大小动态调整

阶段1:需求讨论第一次(启动)

  • 人工:确认范围,是否需要前后端(仅后端需求,仅前端需求)。
  • AI:会议纪要。

阶段2:初期准备

  • 人工:整合现有条件、资源、情况、利益方,总结背景。
  • AI:辅助生成解决方案报告,多次调整,生成最终业务解决方案。
  • 人工:Report
  • AI:利用现有原型图/UI工具或AI生成式,生成简单原型图

阶段3:需求讨论第二次(需求确认)

  • 人工:沟通解释,对齐业务需求,确认业务逻辑
  • AI:会议纪要

阶段4:解决方案确认

  • 人工:整合现有条件、资源、情况、利益方,确认最终技术解决方案,形成完善计划,Reprot
  • AI:辅助生成解决方案,判断确认最佳路径

阶段5:需求讨论第三次(计划确认)

  • 人工:确认计划与时间点
  • AI:会议纪要

阶段6:开发

前端:
人工:
AI辅助开发,根据确认UI图/原型图,生成静态页面。

后端

3.前端开发

3.1. 前端开发注意事项和规范点

  • eslint代码规范
  • 接口async/await语法糖trycatch
  • 无数据避免空白页(用户友好)
  • 移动端盒模型border-box和flex
  • ts为java风的js等等
  • vue表单项交互数据挂载注意更新与初始化

3.2. 经典web前端(Vue)项目结构 - 最佳实践

基于Vue框架的前端:webpack or vue-cli,将.vue文件及各类配置文件等文件,打包(打包和编译是两个概念)成浏览器认识的html/css/js(尤其是js)

Vue 2.X配webpack or vue-cli,Vue 3.X一般直接配Vite了。注意,一些UI级的库也与Vue版本不同要做更改,比如Vue2.X的element-ui和Vue3.X的element-plus

├── build/               # 构建脚本和配置
├── public/              # 静态资源文件
├── src/
│   ├── api/             # 接口请求封装
│   ├── assets/          # 静态资源(图片、字体等)
│   ├── components/      # 公共组件
│   ├── directive/       # 自定义指令
│   ├── layout/         # 布局组件
│       ├── components/  # 布局相关子组件
│       ├── mixin/      # 布局相关的混入(多端适配)
│       └── index.vue   # 主布局组件
│   ├── plugins/        # 插件
│   ├── router/         # 路由配置
│   ├── store/          # Vuex状态管理
│   ├── utils/          # 工具函数
│   ├── views/          # 页面视图组件
│   ├── App.vue         # 根组件
│   ├── main.js         # 入口文件
│   ├── permission.js   # 权限控制
│   └── settings.js     # 系统设置
├── .env.*              # 环境变量配置
├── babel.config.js     # Babel配置
├── package.json        # 项目依赖和脚本
└── vue.config.js       # Vue CLI配置
  • package.json :项目的 package.json 是配置和描述如何与程序交互和运行的中心。 npm CLI(和 yarn)用它来识别你的项目并了解如何处理项目的依赖关系。package.json 文件使 npm 可以启动你的项目、运行脚本、安装依赖项、发布到 NPM 注册表以及许多其他有用的任务。 npm CLI 也是管理 package.json 的最佳方法,因为它有助于在项目的整个生命周期内生成和更新 package.json 文件。类似于Pom.xml感觉。

  • 多端页面适配(vue中实现多端页面样式适配)

1.PC与移动端适配:router.js -> 每个路由的component为Layout(统一布局,统一移动端适配),然后children里是真实业务代码路径 -> Layout的适配.js里,监听当前是pc还是移动端 -> 状态管理:在vuex记录设备类型 -> layout动态控制页面布局css

2.不同移动端之间的适配(UI给的设计图中往往是根据某个标准尺寸):lib-flexible插件配合postcss-px2rem插件(阿里解决方案,配合了vant组件库)
方案流程:

  1. npm i lib-flexible --save,在main.js里import ‘lib-flexible’,设置or注释掉标签< meta >
    flexible会为页面根据屏幕尺寸自动添加标签,动态控制initial-scale,maximum-scale,minimum-scale等属性的值。同时flexible.js文件中封装这refreshRem方法,与页面监听事件绑定,可以动态设置根元素的font-size。体现在页面上就是html根上的style="font-size"会根据机型屏幕尺寸变。
    举个例子:如iphone6的尺寸是375px,它的页面上就是html根上的自动被依赖设置为style=“font-size: 37.5px”
    在lib-flexible里的flexible.js源码里的refreshRam()体现了这一核心操作,他的rem也是 var rem = (width / 10) + ‘px’。
    该公式的物理含义为 1rem=1根元素字体大小
    在做rem布局方案中,一般推荐是将我们的网页划为十等份,我们的HTML标签的字号为视口宽度的1/10(和上面公式也对上了)。
    举个例子:375尺寸的设计图,1rem=37.5px,即1rem十等分了设计图尺寸。
    只用该插件我们可以在样式文件中直接以 rem 作为单位编写样式,而无需手动计算不同屏幕下元素的具体尺寸。
  2. npm install px2rem-loader,配置px2rem-loader,在build文件中找到util.js,将px2rem-loader添加到cssLoaders中,设置remUnit: 设计图尺寸 / 10
    postcss-px2rem会将你写的px值转换为对应的rem,rem单位用于适配不同宽度的屏幕,它是根据标签的font-size值来计算出结果的。设置完remUnit我们就可以直接根据设计图上的px值进行正常开发了。
    举个例子:如果设计图尺寸是375的,此时remUnit就要设置成37.5。此时在该设计图尺寸下16px就是16 / 37.5 = 0.426667rem(rem是个比例单位)。当机型变成其他尺寸,如414,此时16px字体尺寸肯定要等比例放大。此时lib-flexible已经帮我们把根元素的font-size变化更新了出来,postcss-px2rem帮我们转换px尺寸。在设计图375px下是根元素fontsize是37.5,此时更新成了41.4,代表的物理含义是1rem = 41.4px,最后该375下的16px字体就变成了414屏幕尺寸 41.4 * 0.426667 = 17.6px。
  • Vuex状态管理

Vuex 中的"状态"二字指的是应用中需要共享和管理的全局数据。通过集中管理这些状态,可以更好地组织代码、实现组件间通信,并提高应用的可维护性和可扩展性。状态管理被广泛应用于用户信息、设备类型、侧边栏状态、标签页状态等方面。

比如,对于存储用户状态(token,用户名,用户角色,用户权限)来说:
多个组件可能需要使用相同的用户状态,存储在前端可以确保所有组件访问的是同一份数据,避免不一致
部分功能可用 :即使网络不稳定或暂时断开,前端仍可以根据本地存储的用户状态提供部分功能。离线支持

由于用户状态,我们又引出来问题,为什么不直接用cookie或localStroage存呢?要用Vuex存?
Vuex 的状态是存储在内存中的,页面刷新后,内存会被清空,导致状态丢失。因此,Vuex 本身并不适合直接存储需要持久化的数据。所以,对于需要持久化的数据,结合使用 Vuex 和持久化存储(如 localStorage 或 cookie)来保存用户信息。一般来说,最佳实践是:敏感数据使用 cookie (对于敏感数据如 token,建议使用 cookie 并设置 httpOnly 和 secure 属性,防止被恶意脚本访问),非敏感数据使用 localStorage(用户名) ,并在应用启动时初始化 Vuex 状态。这样我们即持久化了数据,又在持久化时一次读取信息到vuex里(内存里),供给其他组件使用,既能利用 Vuex 的响应式特性,又能实现数据的持久化。
(内存访问更快 :Vuex 中的数据存储在内存中,访问速度比 localStorage 或 cookie 更快。减少 I/O 操作 :频繁读写 localStorage 或 cookie 会增加 I/O 操作,影响性能。而 Vuex 中的数据只在内存中操作,性能更高。)

总结优势:
状态集中管理 :将应用的所有状态集中到一个store中,便于维护和调试
组件通信 :解决跨组件通信问题,特别是非父子组件之间的通信
状态持久化:通过Vuex插件(vuex-persistedstate简化操作)和localStorage 、 cookie 或 sessionStorage实现状态的持久化,如用户登录状态、标签页状态等
开发工具支持 :Vue Devtools对Vuex有很好的支持,方便调试
可预测性 :通过严格的流程控制状态变更,使状态变化更可预测

  • 项目框架路由链

1.main.js初始化:全局挂载、创建Vue根实例(一般会注入router and vuex store)
2.加载App.vue
3.初始化路由系统(< router-view / >)
4.Router一系列

router/index.js:定义路由结构静态+动态路由模板,配置、去井号等等

permission.js :这里一般是路由守卫,router.beforeEach 注册一个全局前置守卫,router.afterEach全局后置守卫。处理登录前后的权限逻辑、路由动态加载、每次路由跳转逻辑及权限逻辑等等(结合NProgress 是一个轻量级的进度条库,专门用于在网页中显示页面加载或异步操作时的进度状态,页面跳转时用户体验)。路由守卫,可全覆盖,每次路由跳转(无论是编程式导航router.push还是声明式导航< router-link >。无论是首次加载还是页面间跳转。)都会执行完整流程

sequenceDiagram
    participant A as 路由跳转触发
    participant B as beforeEach
    participant C as 组件内守卫
    participant D as afterEach
    
    A->>B: 触发全局前置守卫
    B->>C: 执行组件内守卫(beforeRouteEnter等)
    C->>D: 触发全局后置钩子
    D->>页面: 完成导航渲染
具体守卫router.beforeEach(to, from, next)里做的事儿:

未登录状态处理:
  if (whiteList.includes(to.path)) {
    next() // 放行白名单路由
  } else {
    next(`/login?redirect=${to.path}`) // 重定向到登录页
  }

已登录状态处理:

sequenceDiagram
    participant A as permission.js (路由守卫)
    participant B as store/permission.js
    participant C as router/index.js
    participant D as 后端API
    
    A->>B: dispatch('GenerateRoutes')
    B->>D: 调用getRouters()获取菜单
    D-->>B: 返回菜单数据
    B->>C: 导入dynamicRoutes模板
    B->>B: filterAsyncRouter处理数据
    B->>B: filterDynamicRoutes权限过滤
    B->>C: router.addRoutes动态注册
    B-->>A: 返回处理后的路由
    A->>Router: 跳转目标页面

其他状态处理:

直接放行next()等等

5.登录页的router

this.redirect = route.query && route.query.redirect;
结合
this.$ router.push({ path: this.redirect || ‘/’ })
结合
next(/login?redirect=${encodeURIComponent(to.fullPath)})
结合

sequenceDiagram
    participant 用户
    participant 系统
    用户->>系统: 直接访问/admin/user(需权限页面)
    系统->>用户: 拦截并重定向到/login?redirect=/admin/user
    用户->>系统: 完成登录
    系统->>用户: 自动跳转回/admin/user

用户体验 :

  • 避免让登录后的用户重新导航
  • 维持用户操作上下文
  • 业务需求 :

支持邮件/短信中的直接链接

  • 保持多步骤业务流程

实现了「从哪里中断,就从哪里继续」的优质用户体验,是SPA权限系统的标准实践方案。

  • 菜单管理和路由管理,有的是分开管理的

3.3. 微前端

  • 微前端概念和微服务一样,解耦前端页面框架。可以做到vue、react、原生混合开发,互相解耦。典型框架是qiankun

3.4. 真实案例:前端优化

  • 问题:把一个word文档内容(分不同章节)展示在一个竖直大长页中,包含多个echarts/表格/页面数据、多个接口请求。除上拉滑动查看外,还可以大纲直接点击章节查看。如何实现并优化?

  • 解决方案:章节锚点(定位) + 上拉滚动监听(优化按需渲染压力、按需发送请求压力)+ 节流(优化滚动监听频率)+ 异步组件懒加载(优化按需渲染压力、按需发送请求压力)+ 章节锚点flag数组(避免重复发送请求)

  • echarts / g2plot 画图:1.id重复画图问题。2.g2plot更新数据要调用更新数据的方法,echarts更新数据要重置配置里的data。3.实时更新数据用watch就行。

  • 数据制作成展示结构(包括页面直接展示、表展示、柱状图、饼图、折线图展示,类似于仪表大盘实现):
    大概:由于该需求特殊性,前端整理组织全部数据。故利用工厂设计模式整理数据。页面多个模块显示内容是调用不同接口得到数据,且包含列表、echarts、直接显示等多种展示方式,给每个某块设计一个独立的vue data属性,即独立的数据结构对象(其实有点typescript的感觉)。实时性可采用定时器发请求。
    具体:.map方法数组筛选出数组、三个点…拆装箱、固定自定义数据结构。注意let temp = { a:[] }初始化列表。直接属性temp.b = 3可以,列表temp.a.push()必须初始化了a才行

  • webworker:该需求js数据计算的量级不大,单次处理不到100条数据,所以没用webworker

  • 总结:章节锚点(定位) + 上拉滚动监听(优化按需渲染压力、按需发送请求压力)+ 节流(优化滚动监听频率)+ 异步组件懒加载(优化按需渲染压力、按需发送请求压力;非v-if不完全懒加载,webpack打包后文件验证)+ 章节锚点flag数组(避免重复发送请求) + 其他优化考虑(由于是mpaas离线包方案,故没采用gzip压缩;由于计算量不大,没采用并发webworker) + 图表(多表头固定首列原生tr/td实现,饼图/柱状图等统计图用echars/g2plot框架实现,实时变化加定时watch,多张图不能混id) + 表单联动规则(map数据结构编码联系;事件冒泡阻止) + 每章节同一组数据文字/表/图三种展示方式(工厂设计模式整理数据,On处理出一个章节的数据结构,类ts思想)

3.5. 真实案例:PC端-登录/上传文件

1.针对上传文件功能:

  • element-ui的上传文件组件。前端默认发的是post请求,Content-Type为multipart/form-data,即通过常见的FormData编码(一般二进制文件上传都要用这个)类型把File类型(继承Blob,二进制,其type属性为为该文件具体的MIME类型)文件直接传上去了。后端Spring框架的MultipartFile类来处理上传的文件(它通常用于处理multipart/form-data类型的请求),通过get等方法获取文件信息、文件流内容等,处理文件。该流程也是比较常见常规的上传文件流程。(小文件!!!

  • 有并发量,且文件达到一定的大小的,如10M,需文件服务独立部署。常见解决方案,阿里云OSS场景。可通过阿里OSS给前端/客户端/后端暴露的oss.put()调用上传文件。前端/客户端发的是put请求(后端没验证,但感觉大概率是。PUT请求用于向指定URL传输文件或数据,在文件上传场景中,可以使用PUT请求直接将File从客户端发到服务器,和前面post传文件涉及到了restful风格接口设计问题),Content-Type为application/msword或其他类型或干脆没有Content-Type字段,通过该编码类型把File类型(继承Blob,二进制,其type属性为该文件具体的MIME类型)文件传上去了。可以看出来和element-ui的上传文件组件及后端处理文件方式这一条龙相比,没用multipart/form-data对文件进行编码,而是直接甩File上去。再次,针对大文件上传。blob切片上传。这里文件包含音视频文件、文本文件等全部,都是处理二进制文件流/blob,然后针对所有场景加上各种编解码规则。最后,为了防篡改可以加验签环节。

  • 断点续传:可以使用 localStorage 或 sessionStorage 来存储已上传的切片信息,包括已上传的切片索引、切片大小等。采用文件唯一标识符或用户会话标识符进行区分。

# 数据库存储文件性能压力详解

当文件直接存储在数据库中并频繁读写时,会对系统各个层面产生显著压力,以下是详细分析:

## 1. CPU压力

**产生原因**:
- 数据编解码:数据库需要将二进制文件内容编码为可存储格式
- 加密解密:如果启用透明数据加密(TDE)
- 查询处理:解析包含大字段的SQL语句

**具体表现**:
- CPU使用率飙升(特别是数据库服务器)
- SQL查询执行时间变长
- 数据库连接池等待时间增加

## 2. 内存压力

**产生原因**:
- 缓冲池占用:文件内容会占用数据库缓冲池(InnoDB buffer pool)
- 连接内存:每个连接需要内存存储结果集

**具体表现**:
- 内存不足导致频繁GC或OOM
- 缓冲池命中率下降
- 查询性能急剧下降

## 3. 磁盘I/O压力

**产生原因**:
- 大文件读写占用大量I/O带宽
- 日志写入(binlog/redo log体积膨胀)
- 临时表操作可能触发磁盘写入

**具体表现**:
- 磁盘队列长度增加
- I/O等待时间上升(await指标)
- 其他业务SQL响应变慢

## 4. 网络压力

**产生原因**:
- 大文件在应用服务器和数据库间传输
- 结果集网络传输耗时

**具体表现**:
- 网络带宽饱和
- TCP重传率上升
- 连接超时增多

## 5. 数据库内部压力点

**存储引擎层面**:
- InnoDB行格式处理大字段效率低
- 大事务导致锁持有时间延长
- 备份恢复时间呈指数级增长

**执行计划层面**:
- 大字段导致索引效率下降
- 全表扫描成本增加
- 排序操作内存不足

## 各组件压力关系图


[客户端请求][应用服务器] ←网络压力→ [数据库服务器]
   ↑                       ↓
[用户浏览器]          [CPU压力][内存压力][磁盘I/O压力]


## 实际场景示例

**场景**:100个并发用户同时下载1MB文件

**压力表现**:
1. 数据库需要同时处理100个包含BLOB的查询
2. 产生约100MB的数据传输量
3. 磁盘需要随机读取100个不同位置的文件内容
4. 数据库连接池可能耗尽

## 性能指标参考值

| 指标          | 正常值       | 文件存储场景可能值 |
|---------------|-------------|------------------|
| CPU使用率      | <70%        | 90%-100%         |
| 内存使用率     | <80%        | 95%-OOM          |
| 磁盘IOPS       | 根据配置     | 2-3倍于正常      |
| 网络带宽占用   | <50%        | 90%-100%         |
| 查询响应时间   | <100ms      | 1s-10s           |

## 各压力组件关联影响

CPU压力 → 查询处理变慢 → 连接堆积 → 内存压力 → OOM风险 → 服务不可用

这种连锁反应会导致系统性能急剧下降,最终可能引发雪崩效应。对于文件存储这类场景,专业的外部存储方案(如OSS)能有效规避这些风险。

2.针对登录功能(仅前端,后端在下面微服务里介绍)(PC页面;基于mpaas hybird方案移动端一般由客户端控制登录):

1.区分二维码登录和账户登录
基于账户登录
2.登录(登录验证、登录保持、登录退出):

  1. localstorage获取缓存的用户名等其他信息做展示
  2. 用户名和密码校验(特殊字符校验、长度校验等定制化校验,即表单校验)
  3. 上锁(防止重复登录)
  4. client发请求获取公钥(服务端生成),拿到返回结果后,通过SM2加密算法和公钥,加密密码
  5. clinet将用户名和加密后的密码发请求*
  6. server返回的header里Set-Cookie加密token、加密sessionId(涉及redis会话保持),并在body里放了加密token和用户uuid
  7. 解锁,到此步已经登录成功,后续均为具体需求场景
  8. client拿用户uuid和token发请求,拿到用户全部信息
  9. client清除之前的localstorage、sessionstorage中无用缓存信息,并set新的用户信息(可用做下次登录用户名头像签名等信息的展示等等),并格式化用户信息数据,并vuex中保存信息。(总结:清除/初始化localstorage、sessionstorage、vuex中保存的用户信息,vuex/localstorage等保存这些可以用来做登陆保持)
  10. 获取菜单信息,动态调整页面路由,千人千面
  11. 退出。清除信息、状态,返回登录页。

基于二维码登录
3.登录(登录验证、登录保持、登录退出):

  1. 拿到qrcode的string,通过组件生成qr码
  2. 二维码定时器发检查登录状态,再来个计数器刷新码
  3. 检查成功,发请求拿token后边都一样

tips细节:

  • 为了更安全,可以在3.client发请求*时候再来个公私钥密码对发给server,这样server发来的sessionId和token也能加密)

  • 登录过程中有许多信息需要共享使用,借助vuex可以在代码中共享

  • sessionId和token一般会set在cookie里。(cookie localstorage sessionstorage区别在前文)

  • token放在cookie无法跨域,可以放在HTTP请求的头信息Authorization字段或者代码里存一下;sessionId遇上分布式场景,可以存在redis里来识别。

  • 加密/解密(防泄露) 和 签名/验签(防篡改)
    加密/解密过程:密码原理上安全,但可以抓到公钥,而且可以篡改信息
    a -> b :a请求登录,需要加密密码,向b请求获取公钥
    b -> a:b配合加密算法生成公/私钥对,自留私钥,给a发公钥
    a -> b:a拿到公钥,配合加密算法,加密密码,发给b,b用私钥解密

签名/验签过程:保证信息不会篡改,就算抓到报文和公钥,因为不知道私钥也没法改信息
a -> b:a配合加密算法生成公/私钥对,自己对信息做签名,把签名(即加密后信息)+原文信息发给b
b -> a:b收到消息后,向a发请求获取公钥验签
a -> b:a给b发公钥
b:b验签

加密配合签名,可以保证防泄漏和防篡改。整个报文加密,需要通过https进行网络传输层面加密。

3.6. 数字孪生(web端)/ XR

层层递进:

  • OpenGL:跨平台的原生图形渲染 API,适用于桌面/移动端原生应用开发。在原生操作系统运行,提供直接操作 GPU 的底层接口。
  • WebGL:基于 OpenGL ES 2.0 标准的 浏览器 JavaScript API,是 OpenGL 在 Web 环境的实现,可在浏览器中呈现3d图形。
  • Three.js:通过 JavaScript 简化 WebGL 操作的 高级 3D 库。将 WebGL 的底层调用封装为易用的对象。
  • A-Frame: 面向 WebXR/VR 的 HTML 标签化框架,底层依赖 Three.js。用类似 HTML 的标签定义 3D 物体(如 < a-box >、< a-entity >)。默认集成 VR 设备支持。(Tips: VR, Virtual Reality. AR, Augmented Reality. MR, Mixed Reality. XR, __Reality. )

(物理引擎: Cannon.js(专注于刚体物理模拟的 JavaScript 库)等等)

+-------------------------------+
|  Renderer Process (JavaScript) |
|   - Three.js 逻辑              |
|   - WebGL API 调用             |
+-------------------------------+
              ↓ IPC
+-------------------------------+
|  GPU Process                  |
|   - 转换 WebGL 为原生图形 API    |
|   - 管理显存资源                |
+-------------------------------+
              ↓ 系统调用
+-------------------------------+
|  OS Graphic Driver           |
|   - Direct3D/OpenGL/Vulkan    |
+-------------------------------+
              ↓ 硬件指令
+-------------------------------+
|  Physical GPU                 |
+-------------------------------+

3.6.1 Three.js

  • Three.js 应用都必须包含这三个核心对象:
  1. 场景(Scene)
    scene = new THREE.Scene();
    相当于一个3D舞台,所有要显示的对象(模型、灯光、相机)都必须添加到场景中

  2. 相机(Camera)
    camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
    决定用户能看到场景中的哪些部分,类似人眼的视角。
    Three.js 使用右手坐标系。

  3. 渲染器(Renderer)
    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    作用:将场景和相机的内容绘制到网页上(生成图像)

  • 几何体(Geometry)与材质(Material):
  1. 高性能几何体BufferGeometry与普通 Geometry:定义物体的形状,包含顶点坐标、颜色、法线等数据。
  2. 材质Material:定义外观特性
  3. 将几何体和材质结合,创建一个可渲染的系统
  • 光照系统:环境光(AmbientLight),提供均匀的基础照明,没有方向性。点光源(PointLight):从一个点向所有方向发射光线,类似灯泡。

  • 动画与更新机制:如requestAnimationFrame 以显示器刷新率(通常60Hz)循环调用函数。每次循环中更新粒子位置并重新渲染。

  • 相机控制器(OrbitControls):允许用户通过鼠标拖拽旋转、缩放、平移场景。监听鼠标事件,修改相机的位置和朝向。

  • Three.js 创建的 WebGL 资源不会自动释放,必须手动清理

4.后端开发

4.1. 依赖注入(Dependency Injection, DI)& IoC & AOP

依赖注入(Dependency Injection,简称DI)是一种设计模式,用于实现控制反转(Inversion of Control,简称IoC)。在依赖注入中,对象的依赖关系不是在代码中直接创建的,而是通过外部容器(如Spring、ASP.NET Core等)来管理的。

在传统的编程中,对象的依赖关系通常在代码中直接创建。例如,在一个类中,你可能直接创建另一个类的实例,或者使用构造函数或方法参数来获取另一个类的实例。这种方式可能会导致代码的耦合度增加,使得代码难以测试和维护。
依赖注入通过将对象的依赖关系从代码中分离出来,由外部容器来管理,从而降低了代码的耦合度。在依赖注入中,对象的依赖关系是通过构造函数参数、方法参数或属性来注入的。
举个例子:C++需要自己释放对象管理内存,Java有JVM帮你管理对象释放内存,如果没有mybatis这些框架,那么你需要自己写连接与释放mysql连接,如果有,他会自动管理数据库连接的生命周期,包括创建连接、使用连接和关闭连接,在MyBatis中,连接池是通过SqlSessionFactory类来管理的。如果我们要用该方法,可以通过依赖注入的方式引入,即依赖注入通过将对象的依赖关系从代码中分离出来,由外部容器来管理,从而降低了代码的耦合度。(这段话其实解决了两个问题,1谁来管理数据库连接资源,2如何用到代码中即注入到代码框架中)

典型场景:spring boot里controoler通过@Autowired注入service。service通过@Autowired注入其他service.java、mapper等。避免循环依赖问题。若真遇到了:0.spring内部的三级缓存解决,无感。1.优化代码。2.配置(不建议)(spring:main:allow-circular-references: true)。3.两个依赖了一个@Lazy@Autowired另一个。4.@DependsOn指定加载顺序

  • Java后端经典

AOP典型案例:@Around(“@annotation(requiresPermissions)”),实现权限控制,校验方法调用的权限。各种切面。

IoC典型案例:容器管理,@Autowired bean注入。上面说的

sequenceDiagram
    用户请求->>+AOP代理: 调用@RequiresPermissions方法(spring 框架AOP,切割业务代码和权限,和前端钩子的异曲同工)
    AOP代理->>+PreAuthorizeAspect: 执行@Before、@around(环绕切入)等经典方式
    PreAuthorizeAspect->>+AuthUtil: checkPermi(requiresPermissions)
    AuthUtil(工具类不需要实例化即可使用)->>+AuthLogic:
    AuthLogic->>+AuthLogic: checkPermiAnd(), getLoginUser().getPermiList(),获取方式和之前博客记录一样,牵扯SecurityContextHolder。做权限校验
    AuthLogic->>权限校验: 比对用户权限列表和注解传进来的权限
    alt 校验通过
        return 放行
    else 校验失败
        NotPermissionException: 抛出异常
    end

4.2. 业务逻辑事务落库和发送邮件提醒

复杂业务逻辑涉及到多张表的增删改,需要用事务来保证一致性。最后发送邮件,最好送到消息队列里(Kafka),因为邮件发送服务器往往具有有时间长、异步的特点,且有网路延迟问题,放到kafka里可以应对并发场景,并提高用户前端感知响应速度,且信息丢失可能性降低

4.3. 经典web后端(Java/spring cloud)项目结构 - 最佳实践

对于web服务来说,目录结构很经典,已经非常结构化,导致可替代性很高。
其他微服务(日志、消息队列、网关、验权等等服务,相对来说就不是这个结构了),他们更多是业务逻辑。

  • PO(Persistent Object)/ DO (Domain Object) :PO/DO通常用于表示数据库中的表结构,每个PO都对应一个数据库表,其中包含了该表的属性和方法等信息。
    (bean、entity、model)

  • DAO(Data Access Object):DAO通常用于封装数据访问逻辑,以便在业务逻辑中使用。
    (mapper)

  • BO(Business Object):BO通常用于封装业务逻辑,使得业务逻辑与其他模块解耦。
    (service、manager、business)

  • DTO(Data Transfer Object):DTO通常用于封装数据传输逻辑,主要用于不同模块之间的数据传输。

  • VO(View Object):VO通常用于封装界面显示所需的数据,使得界面与后端服务解耦。

下方为流转关系
View < -------VO------- > Controller < ----DTO— > Service(BO) < -----PO------ > DAO < ------ > database

project-root/
├── src
│   ├── main
│   │   ├── java                             # Java源代码
│   │   │   ├── com
│   │   │   │   ├── company
│   │   │   │   │   ├── project
│   │   │   │   │   │   ├── controller       # 控制器层
│   │   │   │   │   │   ├── service          # 服务层
│   │   │   │   │   │   ├── repository       # 数据访问层
│   │   │   │   │   │   ├── model            # 实体类
│   │   │   │   │   │   ├── dto              # 数据传输对象
│   │   │   │   │   │   ├── exception        # 自定义异常
│   │   │   │   │   │   ├── config           # 配置类
│   │   ├── resources                        # 资源文件
│   │   │   ├── static                       # 静态资源
│   │   │   ├── templates                    # 模板文件
│   │   │   ├── application.properties       # 配置文件
├── target                                   # 编译输出目录

Tips:
1.java味儿大同小异,还有的把实体写成entity,有的把vo抽出来,有的把repository写成mapper等等。

2.写package时候,需要和目录结构(及父目录结构)and Pom.xml写的对应。别找不到依赖。

3.微服务架构一般用bootstrap替代application.properties,在nacos(其他服务注册中间间)上写具体配置。

4.4. 结构化数据、非结构化数据、半结构化数据

  • 结构化数据是指具有固定格式和长度,并且数据元素之间存在明确关系的数据。它通常以表格形式存储,如关系型数据库中的行和列。
  • 非结构化数据是指没有固定格式或长度,数据元素之间没有明确关系的数据。它通常以文本、图像、音频、视频等形式存在。
  • 半结构化数据介于结构化数据和非结构化数据之间,它具有一定的结构,但不是严格意义上的表格形式。常见的半结构化数据包括XML和JSON等。

4.5. NoSQL: MongoDB & Redis & Elasticsearch

  • MongoDB

SQL database < ---- > MongoDB database
SQL table < ---- > MongoDB collection
SQL row < ---- > MongoDB document
SQL column < ---- > MongoDB field

MongoDB Docs:
MongoDB CRUD Operations
MongoDB 文档
MongoDB Docs

eg.
const cursor = db.collection(‘inventory’).find({ status: ‘D’ });

=

SELECT * FROM inventory WHERE status = “D”

也有增删改查,也有事务,也有索引等等,也有自己特色比如时间序列…也有各种查询手段,比如聚合管道配合着各种系统关键字$match等类似于sql里各种join group by等等复杂的查询方式

简单想法记录:容易或可以高度抽象表结构、高价值、复杂事务/强一致性的数据的还是用传统SQL。快速迭代/变更/灵活、实时数据流、AI交互的数据可以MongoDB。如果对搜索、查询有要求,对操作几乎没有的场景,可以上Elasticsearch。具体场景具体分析。

  • Redis

内存数据库:内存键值存储(Key-Value Store)

缓存、会话、分布式锁…

  • Elasticsearch

文档存储(Document Store) + 搜索引擎

基于Lucene的分布式搜索引擎,JSON文档格式存储(和MongoDB对比,他查询厉害,尤其全文或模糊,重点是查询搜素,MongoDB操作比他厉害),强大的全文检索和聚合分析能力

全文搜索、应用查询、大数据领域、日志检索、监控监控

Elasticsearch 使用基于 JSON 的查询 DSL,有自己的查询语句。

Tips: 针对传统SQL数据库,需要先将数据库(如MySQL) 数据同步到 ES 中才能查询。

4.6. 真实案例:MySQL库表设计

机构、角色、用户MySQL库表设计

业务Tips
财务相关数据DECIMAL

最佳实践:自动记录创建和更新时间(不需要应用层维护)

created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

版本号:业务需要,并发乐观锁

基础概念

  • 主键Primary Key:主键是一种特殊的唯一索引,它要求表中的每一行记录都必须有一个唯一的主键值。特点:唯一性、非空性、唯一索引。主键可以是一个字段,也可以是多个字段的组合。如果是一个字段,则称为单字段主键;如果是多个字段,则称为联合主键。
  • 联合主键Composite Key:联合主键是指由两个或多个字段组成的键,这些字段共同唯一标识表中的每一行记录。联合主键通常用于需要多个字段共同唯一标识的情况,例如,在一个订单表中,订单号和客户ID可以共同作为联合主键,因为一个客户可以下多个订单,但每个订单号和客户ID的组合是唯一的。
  • 唯一键UNIQUE KEY:确保业务关键字段的唯一性。当主键不是业务字段时替代主键。唯一性约束,自动创建索,允许NULL值(除非列明确指定为NOT NULL,否则可以包含多个NULL值)
有了主键为什么唯一键?

## 主键(Primary Key)的作用
唯一标识记录 :
   - 主键是表中每一行数据的唯一标识符
   - 每个表只能有一个主键
   - 主键列不允许NULL值

## 业务唯一ID作为唯一键(UNIQUE KEY)的原因
主键与业务ID的分离 :
   - 主键:用于数据库内部标识记录(技术需求)
   - 业务唯一ID:用于业务系统标识记录(业务需求)
   - 业务唯一ID:分布式数据库时/后期分库分表场景,表示全局唯一(技术需求)

eg
CREATE TABLE orders (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,  -- 主键
    order_no VARCHAR(30) UNIQUE,          -- 订单号唯一
    customer_id BIGINT NOT NULL
);

技术需求 :
- 数据库引擎需要稳定、高效的主键(通常是自增整数)
- 主键通常作为外键引用
- 分布式场景
- 未来分库分表场景

业务需求 :
- 业务标识符可能有特殊格式(如"PROD-2023-001")
- 业务ID可能需要变更(主键一旦建立不应修改)
- 业务规则要求的唯一性约束

性能考虑 :
- 整数主键比字符串业务ID索引效率更高
- 业务ID作为唯一键仍能保证业务规则
  • 外键Foreign Key:外键用来引用其他表,通过子表的一个或多个字段对应父表的主键或唯一键值,将子表和父表建立关联关系。它确保了数据的完整性和一致性。外键确保了引用的表中的数据不会因为被引用的数据被删除或更改而丢失。例如,如果你有一个订单表和一个客户表,订单表中的客户ID必须是客户表中的有效ID,否则订单表中的数据将无法插入或更新。外键强制执行引用完整性,这意味着在删除或更新引用表中的数据时,必须考虑被引用表中的数据。例如,如果你试图删除一个客户,而该客户有相关的订单,MySQL将阻止删除操作,除非你先删除或更新这些订单。

  • 普通索引index:提高查询速度:特别是WHERE、JOIN、ORDER BY等操作。不强制唯一性,占用额外存储空间。频繁作为查询条件的列

  • ID:在MySQL中,id通常是一个自增的整数,用于唯一标识表中的每一行记录。由于MySQL的底层实现

  • UUID, Universally Unique Identifier:是一种128位的全局唯一标识符,通常用于数据库和分布式系统中,以生成唯一的标识符。其特点是全局唯一。

由于分布式架构的普及,以及随着数据量增大数据库迁移、同步、分库分表等操作,往往自增的id无法满足全局唯一性,所以引入UUID来保证全局唯一。然而,由于UUID是字符串且无序,如果把UUID作为主键,对于MySQL底层索引实现的B+树(数据结构知识)来说,这样很影响查询速度。所以,为了兼顾数据唯一性和查询速度的问题,通常把id作为物理主键,来保证查询速度,把uuid作为逻辑主键和外键,来保证数据唯一性以及和其他表的关系。

范式(Normalization):在(关系型)数据库设计中,范式(Normalization)是一种规范化的过程,用于消除数据冗余和依赖性,提高数据的一致性和完整性。

  • 第一范式(1NF):第一范式是最基本的范式,要求表中的每个字段都是原子性的,即每个字段不能再分割。实践过程中一般常识性满足。
  • 第二范式(2NF):第二范式是在第一范式的基础上,要求表中的所有非主键字段必须完全依赖于主键。换句话说,第二范式要求表中的所有非主键字段必须依赖于整个主键,而不是主键的一部分。实践过程中,遇到两张表是多对多关系,拆出来第三张表做链接表(设置外键、联合主键等),解决了数据的冗余问题。
    反规范化:在某些情况下,为了提高查询性能,可能需要进行反规范化,即在表中添加冗余字段。但是,反规范化会增加数据冗余,降低数据的一致性和完整性,因此需要谨慎使用。对于上面的具体事件,就是把A表的id加到B表的字段中,由于是多对多,导致B表出现很多冗余数据,但是提高了查询效率,剩去了去第三张链接表找数的时间。
    因此,需要根据实际场景判断用满足范式还是反范式。
  • 第三范式(3NF):第三范式是在第二范式的基础上,要求表中的所有非主键字段必须直接依赖于主键,而不是通过其他非主键字段间接依赖于主键。换句话说,第三范式要求表中的所有非主键字段必须依赖于主键,而不是依赖于其他非主键字段。实践过程中,解决的是数据添加、数据删除即数据修改的问题。

编码(character set & encode):

  • 字符集用unicode。unicode定义了世界上几乎所有的书写系统中的每个字符一个唯一的数字编码,包括中文和Emoji
  • 编码方式(将字符集编码为计算机可以存储和处理的二进制数据)用utf8mb4
  • 该方式设置避免了数据库中文数据乱码
  • 需要注意的是,不同数据库需要额外关心该事件。比如mysql的varchar可以存储Unicode字符,但MS sql server的varchar存储的是非Unicode数据,它只能存储ASCII字符。MS sql server需要用NVARCHAR来存储Unicode字符,且插入数据的时候,需要加N标识才能识别Unicode(如中文)。

数据迁移与数据备份问题:

迁移:1.完全推到重来(数据丢失)。2.全量迁移(跨系统数据库迁移工作量大,且容易对现有运行功能产生较大影响)。3.增量迁移,逐步清理(折中方案)。4.不迁移,通过trick连接系统。(影响最小,工作量最小)。

备份:1.数据库备份。2.数据库异地/云备份/灾难备份。3.数据库操作权限管理。主库不能给过大权限。4.操作生产环境一定要有落在纸面上的明确的回滚机制与指导方案,且具备一定的技术水平。5.对于过于重要的数据,又必须做一些操作,学习银行,在一个时间窗口内关闭系统,避免增量数据的产生。

MySQL表创建命令

  1. 机构表(Organizations)
    机构表存储了机构的信息,包括机构ID、UUID和机构名称。机构ID是自增的主键,UUID是唯一标识,机构名称是必填字段。
CREATE TABLE organizations (
id INT AUTO_INCREMENT PRIMARY KEY,
uuid CHAR(36) UNIQUE NOT NULL,
org_name VARCHAR(100) NOT NULL
);
  1. 角色表(Roles)
    角色表存储了角色的信息,包括角色ID、UUID和角色名称。角色ID是自增的主键,UUID是唯一标识,角色名称是必填字段。
CREATE TABLE roles (
id INT AUTO_INCREMENT PRIMARY KEY,
uuid CHAR(36) UNIQUE NOT NULL,
role_name VARCHAR(100) NOT NULL
);
  1. 职位表(Positions)
    职位表存储了职位的信息,包括职位ID、UUID、机构UUID、角色UUID、职位名称和职位有效日期。职位ID是自增的主键,UUID是唯一标识,职位名称是必填字段。机构UUID和角色UUID分别是外键,分别引用机构表和角色表的逻辑主键。
CREATE TABLE positions (
id INT AUTO_INCREMENT PRIMARY KEY,
uuid CHAR(36) UNIQUE NOT NULL,
org_uuid CHAR(36),
role_uuid CHAR(36),
pos_name VARCHAR(100) NOT NULL,
valid_to DATE,
FOREIGN KEY (org_uuid) REFERENCES organizations(uuid),
FOREIGN KEY (role_uuid) REFERENCES roles(uuid)
);
  1. 用户表(Users)
    用户表存储了用户的信息,包括用户ID、UUID和用户名称。用户ID是自增的主键,UUID是唯一标识,用户名称是必填字段。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
uuid CHAR(36) UNIQUE NOT NULL,
user_name VARCHAR(100) NOT NULL
......
);
  1. 链接表(UserPositions)
    链接表存储了用户和职位之间的关联关系,包括链接ID、用户UUID和职位UUID。链接ID是自增的主键,用户UUID和职位UUID分别是外键,分别引用用户表和职位表的主键。
CREATE TABLE user_positions (
id INT AUTO_INCREMENT PRIMARY KEY,
user_uuid CHAR(36),
position_uuid CHAR(36),
FOREIGN KEY (user_uuid) REFERENCES users(uuid),
FOREIGN KEY (position_uuid) REFERENCES positions(uuid)
);

优化

  1. 索引:在经常查询的字段上创建索引,以提高查询性能。例如,可以在org_namerole_namepos_nameuser_name字段上创建索引。

索引进阶:
A. where/join/group by/order by等语句使用的列创建索引
B. 利用最左前缀复用索引
C. 区分度大的列优先搞索引(如name,sex,用name建索引快)
D. 宽度小的列优先搞索引(宽度指这个列的的大小,因为索引树中一个节点能存的key值就越多)

分析查询执行计划优化索引:explain + SQL语句,查看性能,调优时用。优化思路:查询是否用了索引即key是否非空 -> 索引连接类型type(range往上) -> extra是否违反(Using where往上) -> 索引设计是否合理。

分库分表:把原本存储于一个库的数据分块存储到多个库上或把原本存储于一个表的数据分块存储到多张表上。单库资源有限,会影响应用性能,阻碍业务发展,单表数据过大,同样影响增删改查性能。垂直拆分:将表按照功能模块、关系密切程度进行划分,部署到不同的库上。水平拆分:当一个表中的数据量过大时,可将该表的数据按照某种规则分散到多张表上。

client → 查询缓存 → 解析器 → 预处理器 → 查询优化器 → 查询执行计划 → 执行引擎 → 存储引擎(InnoDB, MyISAM) → 执行引擎 → (缓存) client

  1. 字段长度:根据实际需求调整字段长度,避免浪费存储空间。例如,如果org_namerole_name字段的最大长度不超过50个字符,可以将它们的长度设置为VARCHAR(50)。
  2. 范式:根据实际需求,可以进一步规范化表结构。例如,如果positions表中的org_uuidrole_uuid字段经常一起查询,可以考虑将它们合并为一个字段,以提高查询性能。
  3. 冗余字段:根据实际需求,可以添加一些冗余字段,以提高查询性能。例如,如果经常需要查询某个职位所属的机构名称和角色名称,可以考虑在positions表中添加org_namerole_name字段。
  4. 数据类型:根据实际需求,选择合适的数据类型。例如,如果valid_to字段只需要存储日期,可以考虑使用DATE类型,而不是DATETIME类型,以节省存储空间。
    在这里插入图片描述

更深入的分析:组织和角色是多对多的关系,职位表示两张表的链接表。然而,物理世界中真的存在职位,且就是机构与角色的组合,所以他叫“职位表”更合适。而用户和职位的多对多关系所抽象出的链接表,没有任何物理含义,纯属是为了解决二范式(解决数据冗余)出来的抽象链接表。我们可以把角色uuid字段抽出来,放在职位表里吗?当然可以,这样减少了连表查询,加快了速度,然而会造成数据冗余,即职位表里有许多相同的数,这就叫反范式。

归根结底,到了计算机空间和时间取舍的经典问题,需要根据实际场景进行设计

AI能帮助我们?当然,根据经验可以明晰需求,并输入一个有上下文的Prompt

4.7. EDA, Event-Driven Architecture 事件驱动架构

是一种以事件为核心的系统设计模式,系统中的组件通过事件的产生、传递和响应实现松耦合的协作。事件代表系统中发生的状态变化或动作(如“用户下单”“传感器数据更新”),组件之间不直接调用接口,而是通过发布/订阅事件进行异步通信。

实时性(高实时性体现在异步不阻塞,低实时性体现在下游服务time-tolerance)、松耦合、可扩展(如突发流量时增加消费者实例)、异步、灵活(新增一个数据分析服务无需修改原有代码)

  • 事件(Event):系统中发生的任何有意义的状态变化或动作,通常包含上下文数据(如时间、来源、类型、负载)。

  • 事件生产者(Producer):检测或触发事件的组件(如用户下单时,订单服务生成“订单创建”事件)。

  • 事件消费者(Consumer):订阅并处理事件的组件(如库存服务监听“订单创建”事件,扣减库存)。

  • 事件通道(Event Channel):传输事件的媒介,如消息队列(Kafka、RabbitMQ)或事件总线(AWS EventBridge)。

  • 事件处理器(Event Processor):可能对事件进行过滤、转换、路由或聚合(如将原始日志事件转换为告警事件)。

事件生产者发布事件 → 2. 事件通过通道传递 → 3. 消费者订阅并处理事件 → 4. 处理结果可能触发新事件。

案例:

  1. 电商订单系统

事件流:
订单服务 → 发布“订单创建”事件(含商品ID、数量)。

消费者:
库存服务 → 扣减库存,发布“库存已扣减”事件。
支付服务 → 发起支付,发布“支付成功”事件。
物流服务 → 订阅“支付成功”事件,生成运单。

优势:支付失败时,库存服务可通过“支付失败”事件回滚库存。

  1. 物联网(IoT)监控

事件流:
温度传感器 → 每秒发布“温度更新”事件。

消费者:
告警服务 → 温度超阈值时触发告警。
数据分析服务 → 存储数据并生成报表。
可视化服务 → 实时更新仪表盘。

优势:新增一个机器学习服务分析温度趋势,无需修改传感器代码。

技术栈:消息队列Apache Kafka(还有其他消息队列、还有事件总线)

容易面临的问题:在事件驱动架构(EDA)中,组件通过异步事件通信,天然面临分布式系统的复杂性。事件可能重复传递、处理顺序不确定、消费者可能失败。

4.7.1 幂等性问题

定义:一个操作执行多次的效果与执行一次相同(无论操作执行一次还是多次,系统的最终状态一致)。
例如:多次调用“设置用户名为Alice”的接口,结果始终是“Alice”(幂等);但“给账户加100元”操作如果多次执行,结果会错误(非幂等)。

主流消息队列(如 Kafka)的“至少一次投递”(at-least-once delivery)机制可能导致消费者多次收到同一事件。例子:网络超时导致生产者重试,或消费者处理成功但未及时确认消息。

4.7.1.1 解决方案一:数据库表唯一约束

在数据库表中为事件添加全局唯一索引UUID,若插入失败(唯一键冲突),则判定为重复请求。适用低频请求场景。

(toB中经常还配一个状态字段,因为不太考虑并发,也可以来判断幂等是否处理)

4.7.1.2 解决方案二:Token + Redis

1.客户端申请Token → 2.服务端生成 Token 并存储到 Redis(设置超时时间) → 3.客户端携带 Token 调用业务接口,服务端尝试删除 Redis 中的 Token:删除成功 → 处理业务。删除失败 → 判定为重复请求。

4.7.1.3 解决方案三:乐观锁

哲学思想/起名艺术:

  • 乐观锁

假设冲突很少发生,在数据操作过程中不主动加锁,仅在提交修改时检查数据是否被其他事务修改过。后验解决。

实现:
版本号机制:在数据表中增加一个版本号字段version,每次更新时校验版本号。

-- 乐观锁流程(无需显式事务)
-- 更新前检查版本号
UPDATE products 
SET stock = stock - 1, version = version + 1 
WHERE id = 1001 AND version = 5;  -- 关键:提交时校验版本号

-- 不加物理锁,仅在提交时检查版本号是否变化。

若更新成功:版本号递增,其他事务的旧版本更新会失败。
若更新失败(affected_rows = 0):说明数据已被修改,需重试或抛异常。

(实现方式CAS(操作系统里学过))

读多写少、冲突概率低(如商品浏览计数、点赞)、高并发(如电商秒杀,吞吐量高,但部分用户需重试)

案例:电商秒杀(悲观锁 vs 乐观锁)
悲观锁流程:
用户A查询商品库存并加锁 → 其他用户无法查询或修改。
用户A扣减库存 → 提交事务释放锁。
用户B才能继续操作。
结果:强一致性,但高并发下用户体验差(排队等待)。

乐观锁流程:
用户A查询商品库存(version=5)。
用户B查询商品库存(version=5)。
用户A发起更新:WHERE id=1001 AND version=5 → 成功(version变为6)。
用户B发起更新:WHERE id=1001 AND version=5 → 失败(version已变)。
用户B重新查询库存(version=6)并重试。
结果:高并发下吞吐量高,但部分用户需重试。

  • 悲观锁

假设冲突经常发生,在操作数据前直接加锁,阻止其他事务修改,直到当前事务完成。先验防御。

实现:
行级锁(SELECT … FOR UPDATE):锁定单行数据(如 MySQL 的 InnoDB,支持事务)

-- 悲观锁流程(以 MySQL 为例)
BEGIN;
-- 步骤1:显式加行锁(阻塞其他事务)
SELECT * FROM products WHERE id = 1001 FOR UPDATE; 
-- 步骤2:更新数据(此时数据已被锁定)
UPDATE products SET stock = stock - 1 WHERE id = 1001;
COMMIT;
-- 其他事务若尝试修改 id=1001 的数据,会被阻塞直到当前事务提交或回滚。

表级锁:锁定整张表(如 MySQL 的 MyISAM,不支持事务)。

写多读少、强一致性(如金融交易)

4.7.1.4 解决方案四:Redis分布式锁

在分布式系统中,为了确保多个节点对共享资源的访问互斥,防止并发修改造成数据错误。

Redis 的 SETNX,生成锁 Key,确保同一请求在锁持有期间仅被处理一次。并配合EXPIRE命令为锁设置一个过期时间,防止因故障导致锁无法释放。

生成锁 Key(如按订单 ID 加锁)
获取锁成功 → 处理业务 → 释放锁
取锁失败 → 判定为重复请求

4.7.2 最终一致性问题 & 缓存和持久一致性问题

数据库基本概念:ACID

Seata是阿里开源的一款开源的分布式事务解决方案:AT、TCC、Saga、XA

4.7.3 事件顺序性问题

场景:事件可能乱序到达,导致状态错误。例子:先收到“订单取消”事件,再收到“订单创建”事件。

解决方案:使用 Kafka 的分区机制,将同一业务键(如 order_id)的事件发送到同一分区,保证分区内有序。

4.7.4 监控问题

场景:事件跨多个服务,难以追踪完整链路。

解决方案:为每个事件附加唯一 trace_id;记录事件的完整生命周期(生产、传输、消费时间戳)。

4.8. 真实案例:微服务架构搭建

传统经典

4.8.1 环境 & 一般技术选型

  1. JDK:没它跑不了spring。openjdk很多家都有。阿里也有。

  2. Spring Boot & Spring Cloud & Spring Security & Spring Cloud Gateway & Spring Cloud Feign (Spring Cloud Netflix) & Spring Cloud Alibaba Sentinel

  • Spring Boot: 每个微服务模块的启动类;基本的Web、MyBatis、Redis等集成;单体应用的功能实现;内嵌多个web容器;极大地提高了企业级项目开发快速构建项目、部署效率。
  • Spring Cloud: Spring Cloud基于Spring Boot构建,结合Nacos服务注册与发现,集成Feign做restful HTTP服务调用,集成Ribbon负载,集成了很多好的服务框架。分布式配置管理,利用spring boot巧妙地简化分布式系统基础设施开发。所以,Spring Cloud是各种微服务/分布式框架的有序集合,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理。
  • Spring Security: Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。Authentication(认证) & Authorization(授权) => auth。还有加密、会话、缓存等等功能
  • Spring Cloud Gateway: Spring Cloud Gateway是基于Spring构建的API网关。是系统对外的唯一入口。
  • Spring Cloud Feign: Feign是声明式的 web service 客户端,可做微服务之间的http调用。可以结合着nacos做很多高级配置,如开启sentinel流量控制、连接池等等。
  • Spring Cloud Alibaba Sentinel: 服务和服务之间的稳定性变得越来越重要。是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。

Spring Cloud Alibaba Sentinel

  1. Maven

直接集成外部服务时,注意解决各种依赖报错问题,这往往是迁移项目的第一大难关。

references:
【Maven】依赖范围、依赖传递、依赖排除、依赖原则、依赖继承

  • 依赖范围(Dependency Scope)< Scope >。用于控制依赖项在编译、测试和运行时的可见性和可用性。compile该依赖项在编译、测试和运行时都可用。这是大多数依赖项的默认范围。runtime该依赖项在编译时不可用,但在运行时和测试时可用。例如,JDBC 驱动程序通常以此范围进行声明,因为编译时并不需要 JDBC 驱动程序,但在运行时需要它来连接数据库。
  • 依赖传递(Dependency Transitivity)是指当一个项目依赖于其他项目时,它会自动获取这些依赖项所依赖的其他项目。例如,如果项目 A 依赖于项目 B,而项目 B 又依赖于项目 C,那么在Maven构建过程中,项目 A 将自动获取项目 B 和项目 C 的依赖。这样,你不需要手动在项目 A 中声明对项目 C 的依赖,Maven将自动完成这个过程。当多个依赖项声明了相同的库但版本不同时,Maven会使用一定的规则来解决冲突。通常,它会选择一个合适的版本来满足所有依赖项,并将其包含在最终的构建结果中。也可以通过显式地声明特定版本来覆盖冲突解析过程。
  • 依赖排除(Dependency Exclusion)< exclusions >。这可以用于解决依赖冲突或避免引入不需要的依赖项。
  • 依赖原则。当多个依赖项引入了相同的库但不同的版本时,Maven使用一套规则来解决依赖冲突。通常情况下,较高版本的库会被选择,但也可以使用 < dependencyManagement > 和 < exclusions > 等元素来显式地解决依赖冲突问题。
  • 依赖继承。pom继承。
    < parent >:指定父POM,用于继承父项目的配置。
    < groupId >: 项目的唯一标识。通常使用反向域名表示。通常使用反向域名表示。
    < artifactId >: 项目的名称标识符。各个模块都有自己的名称。
    < version >: 版本号。子模块会继承。

< dependencyManagement >: 通常是父 pom写。然而这里不同的地方在于,这里仅仅是对依赖进行了声明,并没有实际的引入这个依赖。这样子模块可以从声明的依赖中,选择自己需要的,写在< dependencies >里,而不会继承所有父 pom 中的依赖。即解决了依赖可以统一在父模块中管理,又解决了子模块全部集成太臃肿的问题。
< dependencies >: 真正的引入依赖。子模块可以什么也不做来继承父 pom 的依赖,也可以使用别的版本的依赖进行覆盖。所有父 pom 中定义的依赖会被所有子模块继承。

即使你只打包并运行子模块,Maven仍然会引入父模块的依赖

pom里未指定版本,通常是继承的。指定版本,可能是覆盖继承或引入新依赖。mvn dependency:tree可以查看依赖的具体来源和版本

  1. MySQL
    不过多解释,看上文。配合着持久化层弄。上云就RDS

  2. Redis

  3. Nacos

  4. Seata 分布式事务

  5. 其他融入或内嵌的技术手段
    DFS

4.8.2 必备与常见的微服务及模块

在微服务架构中,服务的类型和功能可以根据具体需求灵活设计。除了Web服务,还可以有任务调度服务、数据处理服务、消息队列消费者、定时任务服务、批处理服务、服务发现和配置服务、API网关服务、事件驱动服务等。这些服务都可以独立运行,拥有自己的main方法,从而实现高度的模块化和解耦。

4.8.2.1 Gateway 网关服务

Spring Cloud Gateway 是 Spring Cloud 的一个组件,用于构建 API 网关。

微服务可能部署在不同机房,不同域名下。当微服务实例众多时,这是非常难以记忆的,对 于客户端来说也太复杂难以维护。客户端相关的请求直接发送到网关,由网关根据请求标识解析(前端写的接口url)判断出具体的微服务地址,再把请求转发到微服务实例。

Spring Cloud Gateway默认基于 Netty,但也可以配置为使用其他 Web 服务器,如 Tomcat。

引出的详解问题:Nginx / Netty / Tomcat / Gateway Service ?

概念层级:Nginx - 软件服务器;Netty / Tomcat - 软件服务器;Gateway Service - 运行的服务

  • Nginx: 高性能的 HTTP 服务器和反向代理服务器

静态资源服务托管:提供 HTML、CSS、JS 等静态文件。
反向代理 :将客户端请求转发到后端服务(一般转到网关)。
负载均衡 :将请求分发到多个后端实例。
基础流量控制 :如限流、缓存、请求过滤等。
流量控制能力:
限流 :通过 limit_req 模块实现请求速率限制。
缓存 :通过 proxy_cache 模块实现响应缓存。
请求过滤 :通过 ngx_http_access_module 实现 IP 黑白名单。

  • Netty:Web 服务器和 Reactive 响应式模型(gateway默认的)

Netty采用异步非阻塞的 I/O 模型,能够高效地处理大量的并发连接,适合高并发场景。基于事件驱动的编程模型,Netty 将网络事件(如连接、读写)抽象为事件,通过事件循环(Event Loop)来处理这些事件。(联想:Node.js,也有这好处,异步非阻塞的 I/O ,事件循环但是只有单线程)

spring-cloud-starter-gateway 会自动传递依赖引入 spring-boot-starter-reactor-netty

框架通过RoutePredicateHandlerMapping等找nacos路由配置

  • Tomcat: Web 服务器和 Servlet 模型(传统MVC)

处理 HTTP 请求和响应。
运行 Java Web 应用程序(如 Spring Boot 应用)。
Tomcat 本身并不提供流量控制功能,它只是 Spring Cloud Gateway 的运行环境

Tomcat 本身并不提供流量控制功能,它只是Gateway Service的运行环境。那些具体的限流等高级能力都是由网关服务提供的。

  • Gateway Service

Spring Cloud Gateway 是 Spring 官方提供的 API 网关,提供了以下核心功能:

  • 路由Route:路由信息由ID(路由的唯一标识符,用于区分不同的路由规则)、目标 URI(指定请求的目标服务地址,websocket/http/注册中心(lb, load balance))、一组断言(定义路由的匹配规则)和一组过滤器组成(定义在请求转发到目标服务之前需要执行的过滤器链,过滤器的执行顺序与配置顺序一致)
  • 断言Predicate:Java8 中的断言函数。定义匹配来自于 Http Request 中的任何信息,比如请求头和参数等。最简单的是直接匹配一个匹配请求路径Path。还有其他很多如
    Route Predicate Factories:请求方法、请求路径等等很多
  • 过滤器Filter: 过滤器将会对请求和响应进行处理。实现请求和响应的预处理(如认证、限流、日志等)

负载均衡配置:spring-cloud-loadbalancer,体现在配置里就是lb://serviceName里的lb前缀

限流配置(cloud gateway 自带RequestRateLimiterGatewayFilterFactory。使用Redis 和Lua脚本实现了令牌桶的方式 或 引入三方Sentinel):1.添加依赖。2.配置规则。3.编写java配置类。

熔断降级配置:1.添加依赖。2.配置规则。3.java类。

跨域配置(服务端CORS):如果页面直接调用后端的域名或IP,故存在跨域问题。它是由浏览器的同源策略造成的。如果可以通过部署手段(例如nginx配置代理等)解决跨域,则可以不需要添加跨域支持。

白名单配置、黑名单配置、等等各种配置。一般手段就三下,引依赖,配置文件,编写对应java类。

  • 在微服务的最佳实践下,这些一般都会在gateway的nacos里配置。单体也可以在gateway的application.yml里。也可能会结合一些中间件。

Nacos(服务发现:Gateway 通过 Nacos 发现其他微服务。动态配置:Gateway 的配置(如路由规则)可以通过 Nacos 动态更新。)

Sentinel(限流、熔断、降级等等)

  • Nginx和Gateway都可以负载均衡,为什么还要Gateway网关服务?

Nginx 的作用:
入口层 :作为整个系统的统一入口,处理静态资源服务和基础的反向代理。
粗粒度流量控制 :提供基础的限流和请求过滤功能。
负载均衡/流量分发 :将请求分发到多个 Gateway 实例。

Gateway 的作用:
统一入口:所有外部请求必须通过网关,最佳实践。
微服务层 :作为web微服务的统一入口,处理 API 路由、认证鉴权、流量控制等。
细粒度流量控制 :可以结合别的中间件提供更精细的限流、熔断、降级等功能。也可以是一般是用spring-cloud-loadbalancer写lb:前缀做负载均衡。当然也可直接上Sentinel
动态路由 :根据规则动态调整路由策略。

Nginx 擅长处理静态资源服务和基础的反向代理,而 Gateway 擅长处理微服务的 API 路由、权限相关、负载均衡、流量控制等。功能互补,性能优化,提高系统的可用性和稳定性。

  • 再进一步:Nginx(前端服务器) / spring-cloud-loadbalancer(gateway常见配置) / Sentinel(微服务间Feign直连API调用) ?

1.Nginx和gateway里的spring-cloud-loadbalancer的区别上面已描述。

2.gateway里的spring-cloud-loadbalancer 和 微服务API里的feign的Sentinel:
外部请求走网关,内部服务间调用直连(需校验)是最佳实践
严格区分「南北流量」(外部请求)和「东西流量」(服务间通信)。遵循「外网走网关,内网直连」的原则
所以,我们的微服务间的API的HTTP方式调用,需要feign结合Sentinel直连调用,同时充分发挥sentinel的作用。Nginx/spring-cloud-loadbalancer 负责流量分发和负载均衡,而 Sentinel 负责流量控制和系统保护。

  • 综上:对于路由这一套东西:web前端最佳实践 & web后端最佳实践 & 微服务最佳实践 & 阿里云原生最佳实践de

1.动作:client/browser,用户输入url

2.基础设施层:域名,数字证书(SSL),DNS(可选,若需要高级效果,不需要可不额外买,买了域名自带DNS服务器解析)(通过DNS解析可拿到IP,请求资源,OSI网络7层模型)

3.基础设施层:CDN 和 OSS (阿里云ECS web服务应用最佳实践推荐,源站内容缓存,加速访问,CDN通过将静态资源缓存到全球分布的边缘节点,使用户可以从最近的节点获取资源,从而显著减少延迟,提高访问速度。OSS做存储。并提供了一层安全性)

4.基础设施层:若没有命中CDN缓存,则进SLB负载均衡入口(第一次负载均衡

5.基础设施层:ECS & Ngnix 前端服务器。Nginx是一款高性能的Web服务器和反向代理软件,可以用于处理静态资源、反向代理、负载均衡、SSL。可以看出来,它不止是做负载均衡的,更多的是作为一个静态资源处理器。当然这里也可以再做一次服务器配置层面的负载均衡配置(第二次负载均衡

6.动作:OSI网络7层模型,返回资源,client/browser开始渲染

7.代码层 / 应用服务层 / 前端(Ngnix 前端服务器托管的打包后的前端代码):以Vue为例子,Vue框架结合Vue Router & Vuex store,处理路由(含首页 / 、登录页配置重定向、其他路由跳转路径、以及配置的守卫前期做的权限请求等等相关工作)(页面路由的概念

8.动作:client/browser渲染首页。用户点击了某个页面跳转的动作,那么纯前端做页面跳转。但往往此时首页或跳转页会在前端created/mounted的钩子里做ajax/axios接口调用。(这里经典的面临跨域,注意配置,由于前后端计算实例分离,注意配置)

9.基础设施层:ECS || k8s 后端服务器。运行着后端的微服务/单体服务

10.代码层 / 应用服务层 / 后端:外部请求走网关(gateway),内部服务间调用直连。因此,网关会根据请求与配置对应,进行路由转发,此时一般结合lb:XXX(第三次负载均衡

11.代码层 / 应用服务层 / 后端:一上来往往进的是登录页,发登录请求要过auth服务,lb:XXX转发到auth服务。

12.代码层 / 应用服务层 / 后端:auth服务通过feign结合Sentinel调用真实业务服务。这里sentinel需要显示配置引入,而feignclient默认集成了Ribbon进行负载均衡,@FeignClient注解中的value = ServiceNameConstants.SERVICE,通过集成的Ribbon客户端自动进行轮询(默认策略)或其他配置的负载均衡策略,不需要在代码中显式编写负载均衡逻辑。(Sentinel主要是做更精细的微服务级别调用的流量控制)(Ribbon做第四次负载均衡

13.代码层 / 应用服务层 / 后端: 真实web服务。controller service mapper或其他各种持久层叫法/数据库交互层叫法。当然业务逻辑中间也可能调用其他微服务。

14.基础设施层:RDS云数据库 || 自己在某些地方部署的database || NoSQL

15.按上述链路,反向,把请求数据返回去。然后依靠Vue的声明式虚拟dom之类的前端技术渲染数据。

4.8.2.2 API 模块

统一管理服务间调用API

  • 解耦依赖 :调用方只需依赖 API 模块,无需引入服务实现
  • 版本控制 :API 变更可独立迭代
  • 文档生成 :配合 Swagger 自动生成接口文档

这里一般会用到Feign,属于Spring Cloud Netflix。Spring Cloud Netflix 是 Spring Cloud 项目的一部分,提供了 Netflix 开源的一系列工具的集成,用于构建弹性、可靠的分布式系统。

FeignClient默认集成了Ribbon进行负载均衡,写 JAVA HTTP 客户端变得更加简单。以及其他常用功能配置:

  • 默认注册中心Nacos获取服务(Ribbon能力)
  • 默认实现负载均衡(Ribbon能力)
  • 注解方式写请求
  • 性能优化(gzip),采用deflate算法压缩数据。这个和前端打包策略发散联系了,vue也通过gzip打包方式优化首页白屏时间。
  • Http连接池
  • 日志(请求日志)
  • 拦截过滤、异常保护、超时设置等
4.8.2.3 Auth 认证与授权服务(认证中心)

认证与授权(认证体现在用户认证。授权体现在token发放)服务是典型的用tomcat的mvc(controller那一套)(所以MVC那一套的东西是Tomcat支持,感谢spring cloud给我们集成这么多东西,我们直接一键run服务,即一键运行web服务)(所以微服务系统一大套代码里,有的不是可以运行的服务,只是把核心功能/代码/模块,抽象在一个模块里放着做调用

Spring Boot 默认内嵌了 Tomcat 作为 Web 服务器。无需单独安装和配置Tomcat。Spring Boot 通过自动配置机制( spring-boot-autoconfigure )来简化 Web 服务器的配置。当检测到 spring-boot-starter-web 依赖时,会自动配置并启动内嵌的 Tomcat。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>默认使用Tomcat
</dependency>

基于Spring MVC的传统同步阻塞架构,@RestController(需要Servlet容器支持需要Servlet容器支持)
main里自动配置Servlet容器

启动auth服务时控制台会显示Tomcat日志

auth中心一般包括:login、logout、register,即这三个阶段肯定需要去auth中心验证用户信息、create/refresh JWT等等给前端。在controller里。(后续请求在网关做一层校验,真实业务) 经常结合spring security

认证授权发展历程:
uuid sessionid 匹配 ->
sessionid + redis ->
token (JWT) ->
JWT + redis ->
现代登录:长时间会话保持与安全性平衡的需求、SSO(single sign on)单点登录的需求、跨平台三方系统登录的需求:JWT+redis 这套,再结合OAuth2.0协议(双重token,access token, refresh token)。此时还要申请跨平台授权。SSO阿里云有原生支持方式。OpenID Connect: OpenID Connect 是基于OAuth 2.0协议的现代标准。由于应用都上云,所以其实现在都直接上一些云安全的解决方案

关于自有登录系统(自有用户名密码)token发放常见的组合实践:

1.JWT + redis

sequenceDiagram
    participant Client
    participant Service
    participant Redis
    
    Client->>Service: 登录请求
    Service->>Service: 生成UUID
    Service->>Redis: 存储LoginUser(key=UUID)
    Service->>Service: 生成JWT(含UUID)
    Service->>Client: 返回JWT
    
    Client->>Service: 携带JWT的请求
    Service->>Service: 验证JWT签名(网关)
    Service->>Service: 提取UUID(网关)
    Service->>Redis: 获取LoginUser(key=UUID)
    Redis->>Service: 返回用户数据

网关验证,验证通过后,将用户信息写入请求头,发送到下游

下游业务服务牵扯到SecurityContextHolder(管理当前用户的安全上下文信息)拦截、解析,存入TransmittableThreadLocal,然后业务代码获取用户信息 

在分布式/微服务中,TransmittableThreadLocal可以用于在服务调用链路中传递数据

为什么在微服务架构中采用这种上下文传递机制,而非直接从请求头解析?
性能:在高并发场景下,上下文读取比反复解析请求头快10-15倍
性能提升(减少重复解析)
代码解耦(业务不依赖HttpServletRequest)
架构扩展性(支持异步/分布式场景)
统一安全管控(集中权限上下文)

那为什么又要结合TransmittableThreadLocal?
保证用户信息不会隔离污染。当你的应用使用线程池时:
1.线程池会复用线程(线程1处理完请求A后,可能立即处理请求B)
2.普通ThreadLocal会导致请求B错误地获取到请求A的上下文
3.TransmittableThreadLocal通过hook线程池操作,在任务执行前自动恢复上下文
(隐含的线程池使用:Spring MVC/WebFlux底层使用线程池处理请求(如Tomcat线程池))


	Service->>Service:业务代码安全获取用户数据处理业务
    Service->>Client: 返回业务数据

Tips:把uuid、用户信息、过期时间存到redis,
然后用uuid再签发jwt返回到前端,相当于jwt不整个存到redis

优势:

UUID:
服务端会话存储 :
- 作为Redis中的主键(key),存储完整的 LoginUser 对象
- 包含用户ID、权限、IP等敏感信息(这些信息不会暴露给客户端)

安全控制 :
- 支持服务端主动吊销(通过删除Redis记录即可立即使所有JWT失效)
- 避免JWT被篡改后造成的安全问题(实际用户数据仍由服务端控制)

状态管理 :
- 可实时更新用户状态(如权限变更、强制下线等)
- 精确控制token有效期(通过Redis的TTL)

JWT Token(传输token)

无状态验证 :
- 客户端每次请求携带JWT,服务端只需验证签名有效性

数据防篡改 :
- 通过签名确保传输过程中未被修改
- 包含基础声明(claims)如:UUID token引用、用户ID、用户名

跨服务传递 :
- 微服务间可直接解析JWT获取基本信息
- 不需要每次调用都查询用户中心服务

Tips:加密与签名

加密:保护消息的机密性。使用公钥进行加密,私钥进行解密。
常见:服务端生成公钥私钥,保留私钥。发给客户端公钥。客户端加密,服务端解密。

签名:确保消息的完整性和来源的可靠性。使用私钥进行签名,公钥进行验证。
常见:客户端生成公钥私钥,把==信息原文、签名(信息原文经私钥加密后)、公钥全部发给服务端,服务端公钥验签。客户端签名,服务端验签。(篡改原文,服务端一验,发现不一样,不行。拿着公钥解密签名,篡改信息,但你没私钥,没法改回去,还是不行。)

4.8.2.4 服务注册 & 配置(注册/配置中心)

Nacos 云原生应用的动态服务注册与发现、配置管理和服务管理平台。

生产者 - 注册中心 - 消费者
\ --------- /

  • 服务注册与发现(@SpringBootApplication)
  • 配置(单个服务配置与公共配置,动态更新,bootstrap.properties ->bootstrap.yml -> application.properties -> application.yml)
  • 可视化控制台,服务监控与管理
4.8.2.5 监控服务

Spring Boot Admin是一个针对spring-boot的actuator接口进行UI封装的监控工具。@EnableAdminServer 注解激活Spring Boot Admin服务端功能。监控能力由Spring Boot Admin框架提供

Spring Boot Admin可以直接从注册中心(Nacos)拉取服务实例

工作流:
1.被监控服务通过Actuator暴露端点

# 在被监控服务的配置中添加:
management:
  endpoints:
    web:
      exposure:
        include: '*'  # 暴露全部端点
-----------------------------
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env  # 只暴露这4个端点,还有其他很多端点
      base-path: /actuator  # 端点基础路径
  endpoint:
    health:
      show-details: always  # 显示健康详情
    metrics:
      enabled: true  # 启用metrics
    info:
      enabled: true  # 启用info

2.Admin Server通过注册中心发现服务
3.定时拉取各服务的健康状态
4.通过内置UI展示监控数据

监测、日志

4.8.3 相关必备解决方案

4.8.3.1 接口文档

SpringDoc / Swagger

遵循规范的API 文档自动生成,并可视化展示。文档测试一体化,但测试的功能上不如postman强大。

提升生产力工具,提升前后端集成效率。

单个spring boot用 or 网关里接全部的service用

4.8.3.6 分布式事务
  • 数据库回顾(大部分在之前文章中记录过)

1.事务ACID:

Atomic: 原子性,构成事务的所有操作,要么都执行完成,要么全部不执行,不可能出现部分成功部分失败的情况。

Consistency: 一致性,在事务执行前后,数据库的一致性约束没有被破坏。经典案例,转账。

Isolation: 隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰,一个事务不能看到其他事务运行过程的中间状态。通过配置事务隔离级别可以避脏读、重复读等问题。经典八股文。

Durability: 持久性,当事务正确完成后,它对于数据的改变是永久性的。不会轻易丢失。

2.本地事务:同一数据库和服务器,称为本地事务。

3.各种log

Error Log: 记录数据库启动、运行过程中发生的错误信息,包括启动失败、权限问题、连接错误等。默认开启,workbench默认可查看。

General Query Log:记录所有执行的 SQL 查询语句。用于调试和性能分析,但会生成大量数据,因此不建议在生产环境中开启。需配置。

Slow Query Log:记录执行时间超过指定阈值(通过 long_query_time 参数设置)的 SQL 查询语句。用于识别和优化性能较差的查询。默认情况下,MySQL 并没有开启慢日志,可以通过修改 slow_query_log 参数来打开慢日志。

Binary Log: 记录所有对数据库进行更改的 SQL 语句(如 INSERT、UPDATE、DELETE,DDL)。所以称它为逻辑日志。server级别日志,所以所有引擎通用。主要目的是复制&备份&恢复&同步(功能上与redo log类似,但场景上不一样,bin log做各种数据备份,mysql集群,主从备份等等,所以保护的层次不一样)。

(事务日志)redo log: InnoDB 存储引擎独有。实现数据的恢复。有种情况数据还在缓存BufferPool,没来得及刷到磁盘。记录的都是变更后的数据。持久性。
redo log涉及到一个两阶段提交

(事务日志)undo log: InnoDB 存储引擎独有。撤销/回滚, 也叫回滚日志。实现事务回滚和MVCC机制。原子性。
当一条写入类型的SQL执行时,都会记录Undo-log日志。当事务中某条SQL执行失败时,MySQL就需要回滚事务中其他执行成功的SQL,将库中的数据改回事务发生前的样子。

undo log \ redo log \ bin log只记录增删改,不记录查

典型事务流程 :

1. 事务开始,记录undo log
2. 执行DML操作:
   - 记录数据变更到redo log buffer
   - 修改内存中的数据页
3. 事务提交:
   - redo log prepare → 刷盘
   - bin log写入 → 刷盘
   - redo log commit标记
崩溃恢复流程 :

1. 检查redo log的prepare条目
2. 找到对应的bin log记录:
   - 如果bin log完整 → 重做(redo)
   - 如果bin log不完整 → 回滚(undo)
  • 分布式事务:微服务、分布式系统。

典型场景:库存、订单、账户。

CAP定律:在一个分布式系统中、Consistency(一致性)、Availability(可用性)、Partitiontolerance(分区容错性),三者不可得兼。

BASE理论:BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)

两阶段提交(2PC)是分布式事务的核心协议,2PC理论:
准备阶段(Phase 1):所有参与者准备执行事务,但不提交。
提交/回滚阶段(Phase 2):根据准备阶段结果决定全局提交或回滚

Seata是阿里开源的一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。Seata 提供了 AT、TCC、SAGA 和 XA 事务模式。AT为默认,且常用。

Seata基本架构:TC (Transaction Coordinator,统筹) ,TM (Transaction Manager,发起) ,RM (Resource Manager,执行)
TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端

AT模式(基于支持本地ACID事务的关系型数据库):AT模式是一种无侵入(业务代码不需要为了支持分布式事务而做出特殊修改或添加额外逻辑)的分布式事务解决方案,在AT模式下,用户只需要关注自己的“业务SQL”,用户的“业务SQL”作为一阶段,Seata框架会自动的生成事务的二阶段提交和回滚。

AT的2阶段:

Seata的两阶段提交协议(2PC)是对传统2PC的改进版本,主要解决了传统2PC的阻塞问题和资源锁定时间长的问题。下面详细解释其工作原理:

### 一阶段:本地事务提交
1. SQL拦截与解析 :Seata会拦截业务SQL,分析SQL语义,确定要修改的数据
2. 前置镜像保存 :在执行业务SQL前,保存数据修改前的状态(undo log),这里undo log是指的显式存储在创建的undo log表中。
3. 业务SQL执行 :执行实际的业务数据修改
4. 后置镜像保存 :保存数据修改后的状态(redo log),这里redo log是指的本地数据库的自带机制,保证一阶段正确
5. 行锁生成 :锁定相关数据行,防止其他事务修改
6. 本地提交 :所有操作在同一个本地事务中提交
### 二阶段:全局事务决议
1. 异步提交 :如果所有分支事务都成功,只需异步删除undo log即可
2. 补偿回滚 :如果有分支事务失败,利用一阶段保存的undo log生成反向SQL进行补偿

-----------------

graph LR
    A[全局事务开始] --> B[分支事务1提交]
    A --> C[分支事务2提交] 
    B & C --> D{全局事务决议}
    D -->|成功| E[异步删除各节点undo_log]
    D -->|失败| F[基于undo_log回滚]

-----------------
Seata undo_log:应用层,业务数据JSON快照,全局事务结束时删除,分布式事务回滚 
InnoDB redo:数据库引擎,物理页修改记录,检查点推进时清理,崩溃恢复保证持久性 
InnoDB undo:数据库引擎,行版本链(用于MVCC),事务提交后立即清理,单机事务回滚和MVCC,原子性

回滚靠应用层undo_log
持久化靠数据库原生机制


实操(阿里云上有商用版本的GTS):maven依赖、nacos配置、每个分布式数据库建undo_log表、写业务代码(无侵入、有侵入)

参考:

(十一)MySQL日志篇之undo-log、redo-log、bin-log…傻傻分不清
学习分布式事务Seata看这一篇就够了,建议收藏

4.8.3.7 分布式日志

ELK,Elasticsearch(搜索),Logstash(收集),Kibana(日志分析友好的Web 界面)

5.测试开发

6.运维开发 DevOps

6.1. 单机/本地服务器/本地虚拟机/单体应用运维

  1. MySQL Workbench 操作 MySQL Server
    数据库备份与迁移(即数据导入和数据导出):data import/restore和export
    Users and Privileges:配置用户权限
    SQL script:写SQL语句
    mysqldump: MySQL备份工具。编写脚本前,需添加环境变量,不然无法识别到命令。比如在windows里编写.bat脚本
  2. Windows Server: Task Scheduler。编写脚本,利用windows自带的Task Scheduler设置定时任务。比如MySQL数据库备份。

6.2. Security

ref: https://zhuanlan.zhihu.com/p/613848542
在这里插入图片描述
Network security and cyber security sound like interchangeable terms, however they differ slightly in their scope and coverage. Cyber security is a broader, overarching concept, while network security focuses specifically on securing and protecting network systems.

6.3. 容器化技术 Docker & k8s

  • Docker

Docker 是一个开源的容器化平台,提供了创建、部署和运行容器的工具和环境。Docker 使得开发者可以将应用及其依赖打包成一个镜像,然后在任何安装了 Docker 的环境中快速部署和运行。

Docker Engine:Docker 的核心组件,用于构建和运行容器。

Docker Hub:Docker 的官方镜像仓库,用户可以从中拉取和推送镜像。

Dockerfile:用于定义镜像构建步骤的文件。

  • Kubernetes(k8s)

Kubernetes 是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展和管理。Kubernetes 可以在多个节点上调度和运行容器,提供高可用性、负载均衡、自动扩展等功能。

Pod:Kubernetes 中最小的部署单元,是一个逻辑单元的概念。可以包含一个或多个容器。Pod 中的容器共享网络命名空间、存储等。

  • docker和k8s的关系

Docker 和 Kubernetes 是互补的技术,它们共同用于容器化应用的开发、部署和管理。Docker 负责创建和运行单个容器,而 Kubernetes 负责管理和编排多个容器,尤其是在大规模、分布式环境中。

Docker 是 Kubernetes 的基础:Kubernetes 使用 Docker(或其他兼容的容器运行时)来创建和运行容器。Docker 提供了容器化的基础功能,而 Kubernetes 在此基础上提供了更高的抽象和管理能力。

Kubernetes 扩展了 Docker 的功能:虽然 Docker 可以在单个节点上管理容器,但 Kubernetes 提供了在多个节点上管理容器集群的能力,包括自动扩展、负载均衡、服务发现等。

  • image: 镜像。

Docker 和 Kubernetes(k8s)本身并不是容器,它们是用于管理和编排容器的工具和技术。容器本身是通过镜像创建的运行实例。

镜像image是用于创建容器的只读模板,它包含了容器运行所需的一切,包括操作系统、应用程序、依赖库、配置文件等。镜像是静态的,不可修改,但可以基于它创建可运行的容器实例。

容器Container是镜像的运行实例,是基于镜像创建的可运行环境。容器是动态的,可以启动、停止、删除等。容器在运行时会添加一个可写层,所有对容器的修改都发生在这一层,而镜像本身保持不变。

镜像和容器:镜像是静态的模板,容器是基于镜像创建的动态实例。一个镜像可以创建多个容器。

6.4. CI/CD

Gitlab+jenkins

6.5. 阿里云(云计算,重点)

基础设施/服务/中间件技术平权。产品太多,不赘述。从基础计算资源到基础数据库资源到存储资源再到更细化的日志、消息队列等服务。足以支撑企业级项目所有技术支撑需求

其核心目的之一解决了我们本地部署的复杂基础设施、环境、网络连接等的搭建成本,以及后续带来的一系列问题。通过上云,可以让我们更关注业务系统的搭建。把基础保证托付给阿里云

更上一层次的解决方案(一站式):低代码建站、云上应用解决方案(多端,with域名/DNS/CDN/证书四件套)、AI相关等等很多

  • ECS云服务器

阿里云弹性计算十余年深厚技术积淀,为企业与开发者提供稳如磐石、性能优异的计算服务,满足上百种场景的业务诉求。IaaS(Infrastructure as a Service)级别云计算服务。

稳定性:SLA(Service Level Agreement,服务等级协议)是阿里云与客户之间就ECS服务的质量和可用性达成的正式承诺。它规定了阿里云在提供ECS服务时必须满足的具体性能指标、可用性标准以及相应的赔偿方案等。

弹性保障、全球云设施、软硬一体架构

安全保障:安全涵盖的范围广泛,阿里云保证自身云基础设施和服务的安全,例如机房、虚拟化平台、网络安全、数据安全等,但在使用云产品过程中遵循安全实践同样重要,例如阿里云账号安全、机密信息保管、权限控制等。网络安全、存储安全、计算安全。

阿里云 云服务器 ECS为例:
云服务器 ECS

典型场景通用Web应用: CDN分发与缓存(结合OSS)-> slb1负载均衡(主备) -> 前端ECS 实例-> slb2负载均衡(服务)-> 后端应用ECS实例 -> RDS
再结合一个ESS做自动弹性

  • ACK, Alibaba Cloud Kubernetes Engine

ECS提供了基础的计算资源,而容器化解决方案则在这些资源上提供了更高效、更轻量、占用更少资源的应用部署和管理方式(体现在应用打包镜像,快速部署与迁移)。阿里云的容器服务Kubernetes版(ACK)就是基于ECS构建的,它使用ECS实例作为Kubernetes集群的节点,用户可以在这些节点上部署和管理容器化应用。

最佳实践案例:大规模微服务架构(容器化技术为微服务架构提供了理想的部署平台。微服务可以被打包成独立的容器,每个容器运行一个微服务,它们之间相互隔离,可以独立部署、扩展、更新、收缩、故障恢复)、弹性、DevOps(容器化解决方案与CI/CD流程紧密结合)、混合云

我认为,比直接租用ECS裸机的基础上,这结合了容器化技术,再再再次优化资源利用和方便部署,但更多是企业级

  • Simple Application Serve 轻量应用服务器

更更轻量的解决方案,也支持docker容器化部署。轻量应用服务器基于性能稳定的ECS实例规格,适用于小型Web应用、轻量应用等低负载应用场景。甚至也能结合Dify(AI)

  • OSS对象存储
  • SLB负载均衡
  • RDS云数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值