news 2026/10/19 13:24:15

LoRA微调实战指南:原理、数据准备与训练避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LoRA微调实战指南:原理、数据准备与训练避坑

1. 为什么一定要学会微调,而不是换个模型

1.1 通用底座解决不了“你的问题”

先聊一个我最近真实遇到的场景。我手里有一批内部资料,格式基本上是“问题-结论-依据”三件套,比如客户问“这个功能是不是支持批量导出”,标准回答是“支持,但单次上限2000条,超过需要分批”。这种问题扔给通用大模型,能答对方向,但细节全是它自己编的。它的知识截止时间、对业务术语的理解、对表达口径的把握,都跟我们的实际要求差着一大截。

很多人第一反应是换模型,换一个更大、更智能的底座。但请记住一个基本事实:大模型的知识来自训练语料,语料里没有你们公司的业务口径、没有你自己的写作风格、没有你积累的那几百条问答经验。换更大的模型也解决不了“你私有数据没有被学进去”这个根本问题。这时候能做的只有一件事:微调,把模型的通用能力往你的数据分布上拉一拉。而提到微调,绕不开的就是LoRA,全称Low-Rank Adaptation,低秩适配。它现在是参数高效微调里最主流、最省资源、也最容易上手的一种方案。

1.2 全量微调为什么劝退大多数人

按直觉想,要让模型懂我的数据,最直接的办法就是拿这些数据继续训练整个模型,把每一层权重都更新一遍。这就是全量微调,效果上限确实高,但代价吓人:一个70亿参数的模型,光把参数副本和优化器状态放在显存里,就需要上百GB级别的显存,个人开发者基本直接劝退。而且全量微调会把原始模型学到的通用知识弄丢一部分,业内叫灾难性遗忘。你为了让它学会你的业务话术,它同时忘了基础的推理能力,这种“拆东墙补西墙”的情况非常常见。

另一条路是冻结大部分层,只微调最后几层或部分层。这个办法省资源,但效果一般,因为大模型的知识分布在整个网络里,不是你只动末尾几层就能扭转的。LoRA走的是第三条路:模型原有参数完全冻结不动,在旁边额外挂一组极小的可训练参数,通过训练这些小参数来改变模型的行为。它不修改原模型,所以通用能力几乎没有损失;小参数规模让它非常省显存,消费级显卡就能跑;训练完还能随时把修复拆掉。

1.3 LoRA到底在业界为什么流行

我说几个实际数字,你就有概念了。对常见的中型开源底座模型做LoRA微调,可训练参数量通常只有原模型的0.1%到1%。比如一个70亿参数的模型,LoRA可能只训练几百万到上千万参数。这意味着你用一张24GB显存的显卡就能训练,甚至某些小模型在16GB显存上也能跑起来,而全量微调同样规模至少需要8张这类显卡才能周转。

除了省钱,LoRA还有一个隐藏优势:因为修改值是一组独立的小适配器,你可以为不同任务训练不同的LoRA,然后在同一个底座模型上自由切换。今天挂上“客服话术适配器”,明天摘下来换“文章润色适配器”,模型还是那个模型,但行为完全不同。这对个人开发者、小型团队来说,几乎是白送的多任务能力。我在实际项目里就是把多个适配器轮流加载,比维护多个完整模型副本省了几十倍的磁盘空间。

2. LoRA原理:参数不大,作用不小

2.1 从“直接改模型”到“改的增量”

要理解LoRA,先忘掉“训练模型”这个说法,改成“训练模型的增量”。假设微调前模型的某个线性层权重是W,训练后的权重是W',那么两者之差就是增量ΔW,公式写作:

W' = W + ΔW

全量微调做的事情,是直接在W的基础上逐步修改,最后变成W'。LoRA做的事情,是让ΔW自己拉一支小队伍出来训练,训练结束后再并回W。换句话说,全量微调是在改造一栋房子的承重墙,LoRA则是在不碰承重墙的前提下,往房子里塞了一套可拆卸的装修模块。房子的结构完全没动,但使用体验变了。

这个思路带来的直接好处是:原有模型的知识被视为“已经学好的固定资产”,LoRA只学差异。差异往往比整体简单得多,所以可用更少的参数表达,也更容易训练。

2.2 低秩分解的直观理解

关键来了:为什么这个增量ΔW可以很小?因为在大多数微调场景里,ΔW的信息密度其实不高。你让一个通用模型学会你的业务问答、学会某种写作风格,真正改变的语义方向是有限的,可能几十个维度就够表达了。矩阵论里有个概念叫“秩”,大致可以理解为一个矩阵里有多少个相互独立的维度方向。如果ΔW本身是低秩的,那么它就不需要用完整矩阵存储。

于是LoRA把ΔW分解成两个小矩阵的乘积:

ΔW = B × A

假设原权重矩阵W的尺寸是d×k,A是r×k,B是d×r,其中r就是那个“秩”,通常取8、16、32或64。r远小于d和k的时候,B和A的参数量加起来远小于直接存一个d×k的大矩阵。举个例子,d=4096、k=4096的层,原始ΔW有1600多万个参数;取r=16,A和B的参数合计是4096×16再加上16×4096,约13万个参数,缩到原来的1/128。

这还没完,训练前B矩阵会用高斯分布随机初始化,A矩阵则初始化为全零。为什么要这么设计?因为初始状态下B×A等于零,ΔW就是零,模型行为和微调前完全一致,然后训练开始后,A慢慢有值,B慢慢有值,增量逐渐成形。这个顺序保证了训练初期不会突然改变模型输出,训练过程更稳定。

2.3 超参数的直觉:rank、alpha、dropout

LoRA训练绕不开几个参数,我说人话解释一下。

rank(r)是低秩矩阵的宽度,直接决定增量表达能力的上限。r太小,比如2、4,增量太“窄”,很难学会复杂任务;r太大,比如128、256,又回到“几乎全量训练”的复杂度,还容易过拟合。我的经验是:任务风格转换类,比如让模型说话更简洁、更幽默,r=8到16足够;任务知识密度高,比如让模型学习大量专业问答,r=32到64更稳妥。从8开始调,效果不够就翻倍,这是最常见的做法。

alpha是缩放因子,它解决的是量纲问题。实际生效的增量是 alpha/r 乘以B×A。alpha值通常设置成r的两倍,比如r=16时alpha=32。这样缩放系数就是2,训练初期增量幅度温和,后续学习步伐也没那么激进。很多人不理解为什么alpha和r要联动,我的理解是:把缩放系数固定在一个小范围内,这样调整r时不需要重新精细调学习率,省事得很。

dropout是随机丢弃比例,放在LoRA层里用于抑制过拟合。训练数据少的时候,比如只有几百条,dropout设置在0.05到0.1之间就够;如果数据量上升到几千条,可以适当调高到0.15左右。我见过有人把dropout设成0.3,结果训练损失降得很慢,本质上是因为信息通路被堵太多,完全没有必要。

2.4 为什么LoRA不容易让模型“变傻”

这是很多人忽略的一个重点。全量微调时,backward过程会更新所有层,优化器会尽量让模型在当前数据上损失变小,这就不可避免地会“压过”模型原有的知识分布。LoRA不同,原权重W完全冻结,反向传播时只更新A和B,W一个比特都不动。这就保证了你花大价钱预训练出来的通用能力原封不动保留,模型只是在输出层附近多了一条受控的通路。

实践中这个特性非常有用。我把同一个底座模型分别做了三个LoRA:一个管文案风格、一个管客服问答、一个管关键词提取,三者在互相切换时几乎不影响对方。这是全量微调做不到的,或者说做不到这么干净。

3. 数据准备:决定上限的永远是样本质量

3.1 样本格式选型

LoRA微调常见的样本格式有这么几种:纯文本续写、指令-输入-输出三元组、对话多轮结构。我强烈建议如果不是做特殊实验,都用指令式的三元组结构,通俗讲就是“要求+素材+参考答案”。原因很现实:只有这种结构才能明确告诉模型“什么情况下应该给出什么输出”,模型学到的不是死记硬背,而是“面对某类请求时按某种风格回应”的行为模式。

一个标准的样本长这样:

{ "instruction": "把下面这句话改写成更口语的表达", "input": "本商品自签收之日起七日内,在不影响二次销售的情况下可申请退换。", "output": "东西到手七天内,没弄坏的话,不满意就能退换。" }

训练时,模型读到前面两段,尝试预测后面那段,预测错了就更新LoRA参数,预测对了就奖励它继续往这个方向走。几百条高质量的“要求-回应”对,就能把模型的行为拉向你的目标方向,这就是所谓“让大模型真正懂你”的物理过程。

3.2 让数据体现“你自己的业务”

很多人的误区是:直接把过去积累的问答记录整理成JSON就开训。我踩过这个坑,结果非常惨。原始问答记录里大量重复、口语碎片、上下文缺失,训练出来的模型不仅没变聪明,反而学会了答非所问。

正确的做法是精炼重组。每一条样本的instruction要写清楚任务边界,比如“根据给定的产品参数,回答用户是否支持该功能”,不要把任务描述写成“请回答”;input要给足背景,但不能给无关信息;output要是你心中最完美的标准答案,宁可写得规范一些、完整一些,也绝不要把有瑕疵的原始记录直接丢进去。

数据数量上,我建议起步600到2000条。少于300条,模型很容易过拟合到几十个固定句式的套路上,换个问法就听不懂;多于5000条,除非你的数据特别杂,否则边际收益越来越低,训练时间却线性上涨。记住一句我在项目里反复验证的话:条条精炼的1000条,胜过乱七八糟的10000条。

3.3 清洗与去重的具体操作

操作层面,先说格式化问题。所有样本的JSON结构必须先统一,instruction、input、output三个字段缺一不可,不要在本该是“无输入”的样本里塞空字符串以外的奇怪占位符。我会写一个简单的脚本扫描所有样本,检查三个字段是否都有非空内容、instruction里是否包含input里的内容、output是否太短或太长。太短(少于5个字)的样本丢掉,太长(超过2000字)的样本拆分,因为模型上下文窗口有限。

然后做语义去重。直接比较字符串相似度,用常见的文本相似度算法就行,相似度超过0.8的只留一条。注意保留覆盖更多表达方式的样本,不要只保留最短的那条。

最后做分布检查。统计一下你的样本覆盖了几大类场景。拿客服场景举例,让我看看有多少条是问售后的、多少条是问功能使用的、多少条是问价格的。如果某个场景占80%,模型学完就会偏心,碰到其他场景也按主流场景的套路回答。我倾向于每个大场景控制在15%到40%之间,不够就再补几条,刚性均衡数据不是玄学,这是控制模型偏好的基本盘。

3.4 隐私和合规红线

自己数据微调,百分之百要过一遍隐私。训练数据一旦进入模型参数,就再也无法精确删除了。所以凡是含个人身份信息、账号信息、内部敏感内容的样本,一律脱敏或丢掉。我个人的处理方法是:清洗阶段先跑一遍脱敏脚本,把手机号、身份证号、地址这些模式替换成占位符;再人工抽检10%的样本,确认没有明显敏感内容才进入训练阶段。这一步偷懒,后面上线服务和模型输出审查时你会加倍还债。

4. 实操:从零跑通LoRA微调

4.1 环境与模型底座选择

先讲硬件的最低门槛。以常见的中型开源底座模型为例(大概70亿参数规模),LoRA训练的显存主要花在三个方面:模型权重本身、输入激活值、LoRA参数的梯度和优化器状态。前两项是大头。用24GB显存,开启梯度检查点之类的省显存功能,序列长度控制在1024左右,批量大小调到4,是可以跑出不错效果的。你要是只有16GB显存,就把模型规模换小一号,或者把序列长度压到512,也能勉强转起来。再说得直白一点:显存不够不是绝路,LoRA的优势本来就是你不需要“撑起”完整训练流程。

底座模型选什么?我个人的建议是:优先选训练数据覆盖中文足够广、指令遵循能力强的开源底座,不要选一个纯粹的基座模型从头硬调。基座模型只学过文本续写,并不懂什么叫“回答问题”,LoRA只能在它的认知边界内做调整,很难补上“没学过指令”这种根本差距。

4.2 训练配置逐一解读

直接给一份我反复调过、比较稳的训练配置,先看这份配置,我再逐行讲原因。

{ "base_model": "./weights/base_model", "output_dir": "./lora_out/consumer_v1", "lora_rank": 16, "lora_alpha": 32, "lora_dropout": 0.05, "learning_rate": 2e-4, "num_epochs": 3, "max_seq_len": 1024, "train_batch_size": 4, "gradient_accumulation_steps": 8, "warmup_ratio": 0.03, "lr_scheduler_type": "cosine", "weight_decay": 0.01, "logging_steps": 20, "save_steps": 200 }

先说学习率。LoRA因为只训练少量参数,可以用比全量微调更高的学习率,常见范围是1e-4到3e-4。我用2e-4起步,如果loss震荡厉害就降到1e-4,如果训练过程过于平稳但效果不足就加到3e-4。这里没有绝对的“正确答案”,训练曲线会告诉你答案。

全局批量大小是train_batch_size乘以gradient_accumulation_steps,这里就是4乘以8等于32。不要小看这个参数。批量太小,比如纯batch size等于4,梯度方向噪声大,效果容易波动;批量太大,显存又撑不住,所以用梯度累积是比较通用的折中方案。我对纯新手有个建议:梯度累积步数别超过8,数值稳定性更好控制。

epoch轮次我建议3到5轮就够了。LoRA训练旧容易过拟合,因为你能训练的参数少,学完一遍样本里的模式之后再多练,就会开始记住噪音和特例。我这里的样本规模大概在1500条左右,3轮跑完loss已经掉到平台期,再加轮次反而会让验证指标的准确率下降。

序列长度max_seq_len是1024,这是很多开源基座的常用上限。不要盲目拉长到2048甚至4096,序列长度直接决定显存占用和训练速度。你的样本如果普遍几百字,1024完全够;如果样本里有一批上千字的长文档,可以单独把长样本截断或拆分,比整体调高序列长度划算得多。

优化器我用的是带权重衰减的AdamW,权重衰减设成0.01,这是最稳的组合。热身warmup_ratio设成3%,意思是前3%的训练步数里学习率从0慢慢爬到设定值。别省这一步,它能让训练初期的损失曲线平滑得多,尤其是你换了新数据集、底噪不确定的情况下。

4.3 训练、保存与权重合并

训练过程没有太多玄学,核心是盯着两个信号:训练损失(train loss)在稳步下降,没有剧烈震荡;验证集表现没有出现“下降后又反弹”的过拟合曲线。我一般会把训练日志保存下来,每20步看一眼loss数值,做到心里有数。

训练完成后,保存的不是完整模型,而是一个很小的LoRA适配器文件,里面只有那些低秩矩阵的参数。实际部署时可选择两种方式:第一种是动态加载,即把底座模型和LoRA适配器叠加使用,推理时相当于先走完底座模型再接一个修正分支;第二种是合并权重,直接把W加上B×A的结果算出来,生成一个完整的新模型文件,后续推理跟普通模型没有区别。前者灵活,后者方便。我的习惯是:实验阶段用动态加载,因为可以同时挂好几个适配器对比效果;确认某个适配器要上线了,就把它合并成独立模型,省去每次推理都加载适配器的麻烦。

合并过程涉及的计算量不大,底座的每一层线性权重都执行一遍“原权重加低秩增量”,完成后保存为新的权重文件。合并时记得查一下CPU和GPU内存足够,不然合并到一半资源不够会直接中断。

4.4 推理验证的几种方式

训练完先别急着感慨,验证才是见真章的时候。我通常会做三类测试。

第一类是直接复述训练样本。把训练集里的样本拿给模型重新生成,如果连训练过的内容都答不对,说明训练过程有bug,先修。

第二类是改写泛化测试。把训练样本的问题换个说法、换个数字、换个场景,看看模型能不能给出正确逻辑。这一步是检验模型“学没学到模式”的关键。

第三类是冷启动压力测试。拿一个训练集里完全没有出现过的硬问题,直接问模型,看它的输出是否仍然保持合理。这一轮可能会暴露模型的幻觉问题,也就是遇到没见过的指令时,它会不会硬编一个离谱的答案。出现这种情况不全是LoRA的锅,但可以通过在训练数据里加上“不知道就明说”的样本,缓解一部分。

5. 训练踩坑实录与排查速查表

5.1 过拟合和“复读机”现象

最典型的失败情况:训练loss降得很漂亮,但模型回答任何问题都只会给你训练数据里的几个标准句式,换了个问法它就拗不过来。原因几乎可以锁定在三条路线上:数据太少或太单一是最常见的元凶;rank开太大,模型记忆能力太强,把个别样本的死记当成学习;epoch太多,模型反复捊同一批数据,把模板焊死进了参数。

排查顺序是:先把epoch降到2或3,看是否缓解;然后降rank,比如从64降到16,牺牲一定的表达能力换泛化能力;最后回到数据侧,补充更多不同表述方式的样本。不要在rank和epoch两个变量上同时动手,一次只改一个,否则你不知道是哪个起的作用。

5.2 训练loss不降或震荡

训练一开始loss就不动,先检查数据加载逻辑是不是把样本对错误配对了。常见错误是input字段和output字段顺序搞反,模型在学会把要求倒着输出。其次检查学习率是不是过大,2e-4对某些数据仍然偏激进,降到5e-5看loss能不能开始降。

如果loss震荡严重,也就是每步的数值上下跳动剧烈,优先看批量大小是否太小。train_batch_size只有1或2的情况下,单条样本的梯度噪声非常大,这时候把gradient_accumulation_steps调高,效果比盲目调学习率好。

5.3 显存不够甚至训练中断

显存不足的报错是训练中最烦人的问题。我的建议按成本从低到高排列:先开梯度检查点(省激活值显存);再把max_seq_len降低,从1024降到512;再缩小train_batch_size到1或2,配合梯度累积找回批量大小;最后再看无需改模型结构,直接换一个更小的底座模型。

还有一类情况是CUDA内存碎片化导致的OOM,发生在训练中段而不是开始在加载模型时。这种时候重启环境,把批量调小一点,基本能解决。不要把显存用到99%的极限状态,训练过程随时可能出现峰值波动,预留10%到15%余量是保守但正确的做法。

5.4 常见问题速查表

我把高频问题整理成一张表,你训练时碰到可以对着查。

现象最可能的原因优先尝试的处理
loss不降数据配错或任务过于复杂检查样本配对,调高rank
loss震荡批量太小或学习率太大减小学习率,加大梯度累积
过拟合/复读机数据少、epoch多降低epoch,降rank,补数据
中文效果差底座本身中文能力弱更换中文数据占比更高的底座
显存OOM序列过长或批量过大开梯度检查点,缩短序列
输出格式混乱样本格式不统一统一指令写法,检查分隔符
保留通用能力下降alpha过大或rank过高降低alpha,恢复原始模型权重

5.5 一个容易被忽略的坑:学习率与目标层

LoRA通常会作用在注意力层的Q、K、V、O投影矩阵上,但很多实现也允许你选择作用在MLP层。我的经验是:Q、K、V、O都开,效果最均衡;只开Q和V,参数更少,适合快速试验;如果单独开MLP层,有时在风格转换任务上有意外的好效果。这个没有定论,建议你在小数据上做两三轮A/B测试再决定,不要凭感觉定。

还有个隐藏坑:训练时用到的最大序列长度是1024,但推理时模型可能遇到更长的文本,输出被截断,看起来就像是“模型没学会”。实际这不是LoRA的问题,是上下文窗口的物理限制。遇到这种需求,要么把推理样本切块,要么从一开始训练时就把序列长度统一加长。

6. 扩展:从实验到落地的一点点个人经验

6.1 多个LoRA的组合与管理

我前面提过,同一个底座可以挂多个LoRA适配器,这个是LoRA方案最大的工程红利。你可以把团队的产品拆成几个子任务:基础客服一个适配器、内容创作一个适配器、代码辅助一个适配器,全部共存于一份底座模型中。磁盘上多占几个几十MB的小文件,换来的是多套垂直能力随时切换。

但注意一个坑:多个适配器同时叠加使用时要小心。某些框架支持多个LoRA叠加生效,但不是加得越多越强。我试过同时叠加三个适配器,结果模型输出变得四不像,词汇风格一会儿像客服、一会儿像小说。原因很简单:不同任务训练的增量方向不同,叠加时互相干扰。我的建议是:默认一次只挂一个;如果确实需要混合能力,你得专门做一次组合训练,而不是靠推理期临时拼接。

6.2 部署时的量化与资源控制

LoRA合并后的模型部署,跟普通对话模型没有本质区别。如果你想着省资源,把合并后的模型做量化(比如把权重从16位压缩到8位),推理速度能提升不少,显存占用也能同时下降。但有个细节:量化最好在“合并完成之后”做,不要先量化底座再合并LoRA,那样会引入双重精度损失,效果可能更差。

如果你不想合并,而是动态加载适配器,请确认推理服务的内存管理逻辑正确。适配器的加载和卸载是常见的翻车点,内存泄漏或没有正确释放会让服务越跑越慢。

6.3 持续迭代的正确姿势

模型微调不是一锤子买卖,业务数据会变、用户需求会变,LoRA适配器天然适合持续迭代。我的迭代流程是:每次上线新版本之前,用上一版适配器跑一遍固定的回归测试集,确保新增知识没有踩坏旧能力;然后带着新的训练数据增量训练,或者直接在数据池上重新训练一版。

这里有一个经验可以分享:每次训练都单独保存一份数据快照,记录干净、去重、脱敏后的最终版本。过两个月你再想复现当时的实验,或者排查一个线上问题是不是数据污染导致的,你就知道这个快照有多值钱了。没有数据快照的训练实验,等于白做。另外,如果数据量足够大,把验证集始终留出一部分,不要让训练集和验证集有重叠,否则效果指标只是自欺欺人。

最后说一点我个人的体会。LoRA的优势不在“省显存”这一件事上,而在于它把“改造一个模型”变成了“造一个可插拔的模块”,这让个人和小团队第一次有机会用自己的数据去定义模型行为。我见过太多人把时间花在纠结“该用多大的模型”上,其实真正应该纠结的是“我的数据能不能准确表达我想要的行为”。数据整理清楚了,LoRA的训练只是一个顺理成章的过程。下次你拿到一批业务数据,先别急着训练,把数据洗干净,把样本结构设计好,然后跑一个小秩的LoRA试水,你会很快感受到大模型在你自己的数据上“长出来”的那种可控感。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 13:20:08

WebCAD拥抱AI Agent:从自然语言到智能设计助理

1. 为什么WebCAD必须拥抱AI Agent:行业处境与破局点1.1 只把客户端搬到浏览器,远远不够我第一次在浏览器里打开唯杰WebCAD编辑平台时,第一反应是“这不就是把桌面CAD搬到了网页上吗”。界面布局、命令面板、图层管理,很多老用户都…

作者头像 李华
网站建设 2026/10/19 13:20:07

open-code-review:用自动化静态分析重塑代码评审流程

1. 为什么团队代码评审越来越像走过场做了这么多年开发,我发现一个特别现实的问题:代码评审这件事,几乎所有团队都知道重要,但真正做好的没几个。不是大家不愿意做,而是传统的评审模式在今天的研发节奏下,天…

作者头像 李华
网站建设 2026/10/19 13:18:48

Docker data-root迁移完整指南:停服复制改配置启动清理

如果你接手过一台跑了一段时间的服务器,多半会遇到“明明没装多少东西,系统盘却莫名其妙满了”的情况。打开 df -h 一看, /var/lib/docker 已经吃掉了几十 GB,镜像、容器层、命名卷和日志全堆在容量有限的分区里,而…

作者头像 李华
网站建设 2026/10/19 13:16:42

Vue3前端直连通义千问API:签名鉴权与生产部署实战

简介:本资源是一个基于 Vue 3 实现阿里通义千问 API 集成的可打包部署型聊天组件示例,面向中高级前端开发者,解决在生产环境快速嵌入智能对话能力的实际需求。项目已预置完整调用逻辑、响应式消息管理及轻量级聊天界面,支持构建后…

作者头像 李华
网站建设 2026/10/19 13:13:46

AI自主代理Agent从原理到实战:工具调用、规划与安全控制

最近我把自己一直在琢磨的一套“让大模型自己干活”的流程,真正在代码里跑通了。从最开始一个简单的问答接口,到后来能让模型自主决定调用哪个工具、处理哪一步任务,整个过程比想象中复杂,但也远比预想的有意思。今天这篇文章就是…

作者头像 李华
网站建设 2026/10/19 13:13:37

Linux服务器部署PostgreSQL 12.0完整教程:从yum源到远程访问配置

最近帮某项目组在一台Linux服务器上部署PostgreSQL 12.0,从环境准备到正式接入业务花了大半天。整个过程不算复杂,但因为细节比较多,坑也不少,所以整理一版详细步骤出来。如果你是第一次在Linux上部署PostgreSQL,照着这…

作者头像 李华