自己在Go项目开发中遇到的一些的一些规范问题,后续可以封装成Rules供AI编码工具使用
[开发笔记]避免数据库死锁之全局一致锁顺序
在电商平台开发中,往往涉及多种类型的订单结算以及并发结算的问题,例如这样的场景:
- 平台涉及国内官方订单、国内商户订单以及海外官方订单等多种订单
- 在各种订单完成时,又根据不同的订单类型,涉及冻结金额扣减、利润账户分润、经纪人分润、商户分润、预付回款、卡主回款等流程,期间将会涉及使用数据库事务,对多个账户钱包记录的行锁后变更
- 但由于项目早期开发的不规范,并没有固定加锁的顺序,并且又将入账出账的流程设计为串行,并没有设计为出账同步入账异步的功能,因此整体处理流程又较依赖于行锁
- 不同的完成订单流程中用户钱包的加锁顺序不一致,这里可能是冻结金额扣减->经纪人分润->利润账户分润,而另一处是冻结金额扣减、利润账户分润->经纪人分润;同时,经纪人也可以作为买家,在完成自己的某类订单时先进行冻结金额扣减
以上的几种条件组合,也就为后续业务的死锁埋下了种子。
[开发篇]检索增强生成(RAG)知识库部分的实现Part1-文档处理
大型语言模型 (LLM) 的知识来源于预训练数据,这使得它们容易给出过时甚至不准确的答案。而检索增强生成(RAG)技术在内容生成前为 LLM 提供信息参考,有效克服了这一局限性。
根据自己的学习路线和职业规划,我参与智能体平台开发已经有一段时间了。虽然的热度相比之前有所回落,市面上也陆续出现了不少成熟的智能体工作流平台和智能体开发框架,但作为智能体平台早期阶段的核心组成部分之一,RAG 依然值得系统梳理和实践总结。因此,也算是搭上一个“末班车”,记录一下自己在实现过程中的一些思路和经验。
这篇文章主要讲讲RAG技术知识库部分文档处理的实现,主要涉及文档解析和文档切片。
[运维篇]屏蔽Docker映射端口外部访问
某天排查服务器时,我意外发现自己用Docker部署的几个服务竟然能够被外部直接访问,而并没有被主机防火墙(UFW)拦截。换句话说,这些本应只在内网使用的服务,居然在公网“裸奔”了好几个月。
查阅资料后才知道,Docker的端口映射与防火墙的工作方式类似,它们都会通过修改 iptables 来控制流量。但关键在于:Docker会自动插入自己的iptables规则,而且这些规则的位置通常排在防火墙规则之前。结果就是——流量在到达UFW的过滤链之前,就已经被Docker自己的规则放行了。
因此,即使在UFW中明确设置了deny,也很可能无法真正阻挡通过Docker映射端口进入的访问。那么应该如何配置iptables规则来处理这个问题呢?
(当然很多云服务商在主机防火墙外,还有一系列的安全组规则,可以起到端口不对外暴露的效果)
[运维篇]仅能通过SSH隧道连接服务器内部服务的用户的配置和使用
在一些场景下,我们可能需要在本地连接到某些服务,但这些服务的端口并不对外暴露。例如,像Nacos这样的服务,需要在本地完成配置但是并不推荐将其暴露到公网。在这种情况下,SSH隧道是一种常用的解决方案,它允许我们通过加密的 SSH 连接将本地端口转发到远程服务器的私有端口。
然而,当需要其他人参与连接时,我们可能不希望他们获得过多的服务器操作权限。为了安全起见,我们可以为他们创建一个仅能使用SSH隧道的用户,限制他们的权限,确保他们只能通过隧道访问服务,而无法执行其他的服务器操作。
这里将介绍如何配置一个仅能使用 SSH 隧道的用户,并为他人提供安全的访问方式,避免不必要的权限泄露。
关于新版Minio管理面板的精简及Minio Client使用笔记
新版的Minio管理面板发生了什么变化?
最近把服务器部署的Minio升级到了6月的版本,登录9090后台管理的时候发现很多功能都被精简了,现在的管理面板更趋向于是一个简易版的OSS对象浏览器。
从一些现有的总结信息来看(来源:特别更新:MinIO社区版11万行代码被删除,Web管理功能全面移除) ),移除的内容涉及以下部分:
账户与策略管理: 原本控制台提供的用户账户创建、访问密钥管理、策略策略设置等功能被移除。更新后,用户无法通过图形界面创建新的访问凭证或管理用户权限,只剩管理员初始帐号可用。这也意味着 OpenID Connect(OIDC)单点登录等高级认证集成功能被砍掉,后续版本中只能使用内置的管理员凭证登录控制台。Cloudron 社区论坛的讨论也确认,「OIDC 身份认证在上游已被移除,升级后只能用管理员账户登录,无法再创建新的访问密钥」。
配置与集群管理: 控制台中用于查看和修改服务器配置、管理后端存储设置、监控 MinIO 集群状态的界面不复存在。用户无法在浏览器中方便地调整实例设置或查看服务信息,相关操作需改用命令行或 API。
存储桶管理: 原有用于新建 Bucket(存储桶)、设置 Bucket 策略、浏览和管理 Bucket 属性的界面被删除。现在 Web 界面仅保留对象浏览功能,即列出 Bucket 及其中对象的基本文件浏览操作。诸如一次性创建 Bucket、配置 Bucket 版本控制、生命周期规则等动作都无法通过 UI 完成。
其他管理控制台功能: 诸如服务器信息仪表盘、多节点模式下的集群管理视图、用户界面上的日志 / 通知配置等管理类选项也一并被移除。总体而言,新版的所谓「简化控制台」实际上已经不再是一个管理控制台,而退化为一个纯对象存储浏览器。
2025.4.22版本是最后一个保留完整控制台功能的版本,2025.05.24的版本则开始精简控制台的功能,目前大部分的管理功能只能通过mc(Minio Client)实现,不过相信后续还会有第三方的管理面板出现。
2025年5月阅读清单
微服务VS单体应用
文章地址:Microservices Are a Tax Your Startup Probably Can’t Afford / 微服务是您的初创公司可能无法负担的负担
一些摘录总结:
- 结构良好的单体应用可以让团队专注于交付,而不是处理紧急情况。通过一些“最佳实践(Best practice)”案例,避免单体应用内部糟糕的模块化
- 把微服务视为拓展工具,在遇到实际拓展瓶颈时考虑,而不是作为项目的初始模板。过早地引入微服务将遇到重复的基础设施、脆弱的本地设置和缓慢迭代的问题
- 按照业务逻辑拆分微服务,在早期产品阶段可能会过早地固化结构。这种随意的服务边界,最终会导致共享的数据库、服务间调用仅用来实现简单工作流、伪装成分离的耦合。因此又回到了第2点,将微服务视为拓展工具,按实际瓶颈拆分微服务
- 单个项目中通常会包括一些基础内容(代码风格检查Lint、测试基础设施、本地环境配置、文档、CI/CD配置),在处理微服务时这些内容将乘以服务的数量。早期可以利用共享设施的单代码库结构来简化工作
- 微服务引入了一些无形的网络:服务发现、API版本控制、重试熔断降级、分布式链路追踪、集中式日志和告警
- 微服务适用的情况:工作负载隔离、差异化的拓展需求、模块间使用不同的运行时
早期模拟微服务拆分:
使用内部标志或部署开关来模拟未来的服务拆分
单代码库的实践:
这里提到了一点Go语言项目从单体应用过渡到微服务的一种组织方式:
- 项目的早期开发时,如果已经拆分了(微服务)模块(module),可以多个模块使用单一的工作空间
- 同时,Go 的模块化设计允许我们在开发时在 go.mod 通过 replace 指令把依赖替换为本地路径,例如:
replace github.com/my-org/common-lib => ../common-lib即,把原本依赖的远程库 github.com/my-org/common-lib 替换为本地的 ../common-lib 文件夹。这样利用 replace 实现本地模块的替换,有利于前期软件项目的快速迭代和开发
- 后期扩展后,再将各模块独立出来放到不同的 Git 仓库,能够轻松地过渡成完整的分布式的架构
选择微服务需要关注的部分:
- 评估支撑你微服务架构的技术栈,投资于开发者体验工具:可能需要实现一些工具来实现生产和本地开发环境的配置。
- 专注于服务间通信的可靠通信协议:异步消息需要确保消息模式一致且标准化。REST需要关注 OpenAPI 文档。服务间通信客户端必须实现许多开箱即用的功能:指数退避的重试、超时。一个典型的基础 gRPC 客户端需要手动添加这些额外功能,以确保不会遭受瞬时错误。
- 确保单元测试、集成测试和端到端测试设置稳定,并且能够随着引入代码库中的服务级别分离数量而扩展。
- 尽量使微服务间共用的共享库(utils,可能是包含监控和通信的通用辅助工具)尽可能小,避免重大变更而导致整个依赖服务重建。
- 尽早注意服务日志观测:添加结构化 JSON 日志并创建各种关联 ID 以用于调试;或者早期能够利用一些基本的输出丰富日志信息的辅助工具。
线上故障应急处理要点
从先前某运营商的内网系统到现在社区化线上电商平台的开发,今后面临的是更高用户量和数据量的生产环境,故障时周末的随时响应可能也将成为常态。
- 故障止血优先:在故障发生时,首要任务是快速恢复服务,确保业务正常运行;立即追查责任归属在当前情况下时毫无意义的。
- 止血的最快手段:在服务侧发生的故障,通过识别系统产品的变动,能够快速定位问题并制定止血方案。
- 谨慎执行止血方案:即使止血方案明确,执行过程中仍需小心谨慎。设计新功能时需要考虑回滚无问题,故障止血时也应考虑灰度发布,逐步推向全网。
- 高效沟通:排查思路需要尽可能清晰地同步给相关研发;同时研发要敢于下判断,并说清楚自己的判断依据,才能达到集思广益
继续Go语言规范学习
继续go语言-传参何时使用指针
作为一个java转型go语言的程序员,以前用java时,直接将对象作为参数传递就可以了。而在go语言项目中,由于其保留了一些指针的特性,有时则推荐传递对象的指针,否则将因为拷贝新对象而造成额外的开销。
这里为自己整理一下需要使用指针类型或需要值类型作为参数传递的场景。
2025年3月阅读清单
RAG知识库搭建的一些想法
在完成知识库召回后,还可以结合重排序模型对初步检索的结果进行二次排序,确保相关信息的优先展示。
硅基流动提供了bge-m3嵌入模型和bge-reranker-v2-m3重排序模型的免费接入API。
对于表格这类数据的分析统计处理,知识库的片段信息则起不到太大的作用,需要配置MCP服务。
[K8S – Helm]近期开发Helm包的一些理解 – 202503
相比于一开始作为Web前端工程师入职公司,现在我的工作内容已经远远超出了当时的范畴,JAVA的后端开发到Linux单机、K8S云原生的运维,最近是go开发一些项目需要的Agent应用。
而在将公司项目开发的Agent应用通过Helm安装到客户正式环境集群时,遇到了要求标明资源限制和镜像拉取凭证的问题,我将在这篇文章里讲讲我对这两个问题的理解。