用 Go、Redis 与 PostgreSQL 搭建隐私优先的自托管短链接服务

2026-09-03 45 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

短链接服务看似只是一次重定向,真正上线后却会同时面对链接查询、身份认证、访问记录、缓存一致性和数据隐私等问题。shrl.io 的架构把这些职责拆成四个 Go 微服务,并用 PostgreSQL、Redis、分析 worker 与 SvelteKit 前端组合成一套可以通过容器启动的自托管系统。

这类设计的价值不只是“自己部署一个短网址”,而是让链接数据和访问分析留在自己的基础设施中,减少对第三方短链平台的依赖。

四个服务,各自处理一类问题

shrl.io 将系统拆分为四个微服务:内部 API、公开认证服务、Redis 驱动的重定向器,以及分析 worker。

内部 API 负责管理短链接、修改目标地址以及提供后台需要的数据。它通常是业务规则最集中的位置,也适合放置权限检查、链接有效期和别名冲突处理。

公开认证服务面向浏览器或外部客户端,承担登录、会话或令牌相关流程。将认证入口独立出来,可以让内部 API 不必直接暴露所有认证细节,也便于后续替换认证策略。

重定向器位于访问链路的最前端。当用户访问短链接时,服务优先查询 Redis 中的映射,找到目标地址后直接返回 HTTP 重定向。高频读取不必每次访问 PostgreSQL,这对短链接这种读多写少的场景尤其重要。

分析 worker 则负责异步处理访问记录。重定向请求不需要等待完整的分析写入流程,访问事件可以先进入 Redis,再由 worker 流式消费并持久化或聚合。这样能够缩短用户感知到的重定向延迟,也能把分析处理与在线流量隔离开。

PostgreSQL 与 Redis 的分工

PostgreSQL 是系统的数据源,适合保存短链接的规范记录,例如短码、目标 URL、创建者、状态和创建时间。需要修改链接或执行管理查询时,应以 PostgreSQL 中的数据为准。

Redis 更适合作为两个角色使用:

  • 缓存短码到目标 URL 的映射,加速重定向。
  • 暂存或流式传递访问事件,供分析 worker 消费。

缓存带来的关键问题是失效策略。创建或修改短链接后,应用需要同步更新或删除对应 Redis key;删除短链接时也必须清理缓存,否则用户可能在短时间内继续被重定向到旧地址。一个可以实践的 key 命名方式如下:

shortlink:{code} -> https://example.com/target

访问事件则可以包含短码、时间戳和必要的请求上下文。隐私优先并不意味着完全不做分析,而是应避免默认收集不必要的个人信息,例如完整 IP 地址、长期可识别的用户标识或未经说明的跨站追踪字段。具体保留哪些字段,应根据业务目的和当地法规确定。

可以这样用 Podman Compose 启动本地栈

摘要说明整个栈通过 Docker 部署,也可以使用 Podman Compose 以一条命令启动。下面是一个最小化的实践示例,服务名、镜像名和环境变量需要根据实际项目调整:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: shrl
      POSTGRES_USER: shrl
      POSTGRES_PASSWORD: change-me
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

  api:
    image: your-registry/shrl-api:latest
    depends_on:
      - postgres
      - redis
    environment:
      DATABASE_URL: postgres://shrl:change-me@postgres:5432/shrl
      REDIS_URL: redis://redis:6379/0

  redirector:
    image: your-registry/shrl-redirector:latest
    depends_on:
      - redis
    environment:
      REDIS_URL: redis://redis:6379/0

  analytics-worker:
    image: your-registry/shrl-analytics-worker:latest
    depends_on:
      - postgres
      - redis
    environment:
      DATABASE_URL: postgres://shrl:change-me@postgres:5432/shrl
      REDIS_URL: redis://redis:6379/0

volumes:
  pgdata:

将内容保存为 compose.yml 后,可以这样启动:

podman compose up -d
podman compose ps
podman compose logs -f redirector

生产环境不应继续使用示例密码。还需要补充数据库迁移、备份策略、TLS 终止、日志脱敏、容器资源限制以及服务健康检查。depends_on 只能表达启动顺序,不能保证 PostgreSQL 或 Redis 已经可以接受请求,服务本身仍应实现重试和健康探测。

一次访问请求会经过什么路径

用户访问 /{code} 时,典型流程可以是:

  1. 重定向器从请求中解析短码。
  2. 查询 Redis 缓存。
  3. 命中后返回 301302,并异步记录访问事件。
  4. 未命中时查询 PostgreSQL,确认链接状态后回填 Redis。
  5. 分析 worker 消费事件,按需要写入统计数据。

缓存未命中时,必须处理并发回填问题。热点短码可能在同一时间触发大量数据库查询,可以通过 Redis 锁、请求合并或短暂的负缓存降低压力。对于不存在的短码,也可以缓存一个较短 TTL 的未找到结果,避免恶意扫描持续打到 PostgreSQL。

重定向状态码需要结合业务选择。短链接目标如果经常修改,302307 更容易保留调整空间;目标永久稳定时才考虑 301308。这不是单纯的性能参数,因为浏览器和代理可能缓存永久重定向。

SvelteKit 前端与自托管边界

SvelteKit 前端可以提供短链接创建、链接列表、认证和访问分析页面。前端展示的数据应来自内部 API 或公开认证服务,而不是直接访问 PostgreSQL 或 Redis。这样可以把凭据、权限和数据格式控制集中在服务端。

自托管系统的隐私优势依赖实际配置,而不是仅依赖技术栈名称。部署时应明确:

  • 访问日志保留多久,是否包含完整 IP。
  • 分析数据是否需要聚合或匿名化。
  • 管理 API 是否只允许内网或经过反向代理访问。
  • Redis 是否启用密码、网络隔离和持久化策略。
  • PostgreSQL 备份是否加密,恢复流程是否经过演练。

采用前的检查清单

这套架构适合希望掌控链接数据、需要可定制分析,或不想把重定向流量交给第三方平台的团队。它也会带来运维成本:数据库升级、Redis 故障、认证安全、监控告警和公网防护都需要自行负责。

落地时可以按以下顺序推进:

  • 先用 PostgreSQL 保存规范链接数据,再引入 Redis 缓存。
  • 让重定向路径保持短小,分析写入异步化。
  • 为新增、修改、删除链接定义明确的缓存失效规则。
  • 对访问事件实施字段最小化和保留期限控制。
  • 用 Compose 完成本地验证,再补齐生产环境的密钥、备份、TLS 和监控。

短链接服务的核心不是生成一段更短的字符串,而是围绕一次重定向建立清晰的数据边界。Go 微服务负责职责拆分,Redis 负责低延迟访问和事件流转,PostgreSQL 保持数据可靠性,SvelteKit 提供管理界面;组合起来,才能形成一套真正可维护的隐私优先自托管服务。


相关推荐