2025 年 Listen Notes 运营所需的技术与非技术栈

Listen Notes Company/Product Updates

[

2025 年 Listen Notes 运营所需的技术与非技术栈

我们如何运营 Listen Notes?

Wenbin Fang 2025 年 2 月 18 日

我曾在 2018 年初写过一篇关于 Listen Notes 技术栈的文章(2019 年略有更新),并在 Hacker News 上多次分享。现在是 2025 年,随着我们的产品线、我的思维方式和技术本身的发展(以及过时工具的衰退),我认为现在是时候进行一次更新了。

早在 2018/2019 年,在 Listen Notes 的早期,我专注于如何快速构建产品并使正确的产品落地。这就像开设一家新咖啡店,专注于室内设计、采购咖啡豆、设计菜单等,是我们的“建设阶段”。

现在到了 2025 年,Listen Notes 已经拥有成熟的产品线。我们的主要重点已转移到稳定性(目标是接近 100% 的正常运行时间)和可持续性(确保 Listen Notes 在未来 10 年或 20 年内仍然是播客领域的关键参与者),就像经营一家日复一日持续提供优质咖啡的咖啡店一样。

概述

什么是 Listen Notes?

Listen Notes, Inc. 是我于 2017 年 10 月创立的公司。最初,它是一个单页 Web 应用,可以通过关键字搜索播客剧集。这是 2017 年 listennotes.com 的样子:

2017 年的 ListenNotes.com v1

正如你所看到的,2017 年版本的 ListenNotes.com 非常基础。我希望这能激励你启动自己的 Web 项目。请记住,启动仅仅是开始,大部分工作都在之后。

现在到了 2025 年,Listen Notes 是一个数据库,具有三个用户界面 (UI):

我们还提供一些较小的产品。例如,我们有一个基于 Cloudflare 的开源 CMS,名为 microfeed 和一个快速播客转录/摘要工具,名为 Listen411(或 Transcript.New)。

目前,Listen Notes 不止一个人在工作(团队规模为个位数,甚至有些人是兼职)。确切的数字根据我们当前的技术和非技术任务而波动。我相信我们会看到更多这样的公司——精简、高效的团队,并非每个人都需要全职工作。我受到了 Gumroad 的运营方式 的启发。

我想公开分享我们如何运营 Listen Notes。但是,作为一家私营公司,我只能披露我感到舒服的内容。像其他公司(例如,37signals)一样,我们努力达到一定的透明度,但选择不分享收入或非常详细的统计数据。

虽然一些初创公司拥抱激进的透明度(向他们致敬!),但大多数公司(包括我们)更喜欢保持一些事情的私密性。我们感谢您的理解。

您可能会觉得这篇文章很有趣:开放型初创企业的黄金时代已经过去。人性的阴暗面是——当你试图变得透明时,有些人会批评你不够透明。这就像捐赠给某人,却被告知还不够。让我们看看情况如何。祈祷一切顺利。

这将是一篇很长的文章,但这里是 2025 年 Listen Notes 技术和非技术栈的快速摘要。(如果缺少您喜欢的一些很酷的新工具,请见谅!)

工程

非工程

我们如何构建 Listen Notes 软件

Listen Notes 的主要产品并非特别“技术性”,因为我们不做像 OpenAI 那样的深度 AI 研究,也不构建像 Anduril 那样的国防技术,也不治疗癌症。我们只是构建表面化的 CRUD 应用程序——就像当今的许多 Web 产品一样。如前所述,我们的主要 Web 应用程序由一个数据库和三个 UI 组成。我们的代码位于一个 monorepo 中,其中包含用于后端的 Django/Python、用于 Web 前端的 ReactJs 以及用于 DevOps 的各种 bash 脚本/Ansible YAML 文件。我们使用多个数据存储,包括 Postgres、Elasticsearch、Redis 和 ClickHouse。

其他较小的项目(如 microfeed 和 Listen411)有单独的存储库,但本文主要关注我们的主要 Listen Notes 业务——monorepo。

一个数据库

如果我没记错的话,最赚钱的 AWS 产品都与数据库相关。虽然我们在 AWS 上运行,但我们不为那些托管数据库产品付费——我们在 AWS EC2 实例上运行开源数据存储软件,以提高成本效益。可持续性是关键:我们希望提供卓越的服务而不会耗尽资金。

我个人喜欢购买新的 EC2 实例类型——比较规格、定价和基准测试——尤其是在每年 AWS re:Invent 之后。这有点像其他人喜欢购买手提包、手表或汽车。我不知道这是否是一个健康的(并且不可否认地昂贵的)爱好!

唯一的真理来源:Postgres

我们使用 Postgres 作为我们的主要数据存储,它已增长到超过 1.2 TB。在世界末日的情况下,即使代码库或服务器消失了,有了我们的 Postgres 转储,业务也可以恢复。这就是它的重要性。

当 Listen Notes 启动时,我们使用 Postgres 9.6;现在我们使用 Postgres 17.0(在 2025 年初撰写本文时)。我清楚地记得每次重大升级,就像翻阅家庭相册一样

我们的 Python 代码(在异步 worker 服务器上运行,这些服务器来自计算优化型 EC2 实例,如 c5 到 c6i 到 c7g)会提取和处理播客元数据,然后将其流入 Postgres。与网站(例如,用户信息)和 API 相关的大多数数据也存储在 Postgres 中。

我们的 Postgres 集群通常有 3 个(有时是 4 个或 5 个)实例:一个主实例(用于写入和一些读取)和多个具有短查询超时(例如,30 秒)的只读副本。这些服务器在存储优化型 EC2 实例上运行(例如,i3 → i3en → im4gn & is4gen)。我们避免使用 AWS RDS 是出于成本和控制原因(例如,缺乏 root 访问权限)。

随着时间的推移,我们积累了许多自定义 bash 脚本,用于例行的 DBA 任务,其中一些是计划好的,另一些是临时的。

搜索引擎:Elasticsearch

Listen Notes 的核心是 我们的播客搜索引擎。我们索引世界上所有公共播客和剧集——现在总共有超过 2 亿个文档。(相比之下,1998 年 Google 索引了约 2500 万个网页,当时这已经很多了。)

我们的 Elasticsearch 集群在存储优化型 EC2 实例上运行。每当添加、更新或删除播客或剧集时,我们都会将相应的文档从 Postgres 同步到 Elasticsearch。我们运行定期作业,以使两份数据几乎完全同步。

搜索查询(无论是在网站上、通过 Podcast API 触发,还是来自内部脚本)都会从我们的 Python 代码路由到 Elasticsearch 集群。

分析:ClickHouse

我们将分析数据(如 API / 侦听 / 搜索日志)存储在我们自己的 ClickHouse 安装中。ClickHouse 在 2020 年左右添加到我们的技术栈中,已被证明对于数据仓库来说是可靠且快速的。向 ClickHouse 团队致敬!

快速且短暂的数据存储:Redis

我们依靠 Redis 作为速率限制、功能开关和其他性能关键功能的缓存。我们的 Redis 实例托管在内存优化型 EC2 实例上,是生产环境中运行时间最长的服务器之一,有时在实例升级之前会运行 2-3 年——还记得我喜欢购买新的 EC2 实例类型吗?:)

什么是“一个数据库”?

从技术上讲,我们的“一个数据库”是逻辑上的“播客数据库”。在实践中,各种数据类型分布在 Postgres、Elasticsearch、ClickHouse 和 Redis 中。甚至像 API / 侦听 / 搜索日志这样的数据也间接贡献(例如,对我们的侦听分数)。在任何 CRUD 应用程序中,数据层都至关重要——对于我们的业务尤其如此。

三个用户界面

在当今世界,UI 不一定是图形化的——API 甚至语音界面(例如,Amazon Echo)都算。对于 Listen Notes,我们的三个 UI 是:

UI #1:网站 (listennotes.com)

我们的网站是一个典型的 Django 应用程序,具有 Views、Models、Celery 任务等。当我第一次编写 Listen Notes(2016 年底)时,我使用了 Django 1.9 和 Python 2.7;今天,我们运行 Django 5.1 和 Python 3.13。

我们将 Django 代码组织成“应用程序”(例如,播放列表、剧集、数据集),其中包含标准文件,如 views.py、models.py 和 admin.py。由于某些文件变得很大,我们将它们分解为多个视图文件(例如,views_xxx.py、views_yyy.py、views_zzz.py 等)。

我们过去使用 virtualenv 和 pip,但自 2025 年初以来,我们已切换到 uv。我们发现 uv 对于管理各种版本的多个 Python 项目非常有用——即使某些依赖库尚不支持 Python 3.13。

ListenNotes.com 上的大多数网页都是部分服务器端渲染(Django 模板)和部分客户端渲染(通过 Webpack 编译的 React 单页应用程序,并使用 Volta 来固定 NodeJs 版本)。虽然 有些人批评 JS 捆绑并喜欢 vanilla JavaScript,但我们没有发现当前方法存在重大问题。我们不能仅仅基于互联网上的随机博客文章就承诺进行为期数周的迁移项目——对其他人来说效果最好的实践可能不适合我们的需求。

对于由用户事件触发的异步任务(例如,发送事务性电子邮件),我们会卸载到 Celery 异步 worker。

在生产环境中,Django 通过 uwsgi(由 supervisord 管理)在 nginx 负载均衡器 后提供服务。我们对 uwsgi 进程进行分组,以防止一种缓慢的页面类型(例如,搜索)影响其他页面类型(例如,feed)。

UI #2:Podcast API (PodcastAPI.com)

几年前,我写了一篇关于构建我们的 Podcast API 的文章。虽然核心保持不变,但我们添加了更多的 API 端点、数据属性、多种语言的 SDK,甚至是一个自托管的代码游乐场。

我们在 2017 年 12 月推出了该 API,现在它已集成到数千个应用程序和网站中。

最初,我们使用 RapidAPI(当时是 Mashape)来管理和货币化该 API。但是,在经历了多次 RapidAPI 中断后,我们花了一个月的时间构建了自己的 API 网关。这不仅提高了我们的可靠性,还使我们免于支付 RapidAPI 的 20% 佣金。虽然支付 20% 对于一个副项目来说可能是可以接受的,但对于一个严肃的 API 业务来说,它太高了。

我们的 API 网关现在是我们单体 Django 应用程序的一部分,处理速率限制、身份验证、授权、缓存和实际的请求处理。

为了让用户无需编写代码即可试用该 API,我们使用 Docker 构建了自己的多语言代码游乐场,以实现隔离环境。

UI #3:“自带 UI”

我们允许客户导出原始播客元数据并在他们喜欢的工具(Excel、Google Sheets 等)中进行探索。

作为一家为许多其他小型企业服务的小型企业,我们倾向于按需定价模式。小型客户可能每年多次花费 10-20 美元来访问他们需要的数据,而大型客户可以购买整个播客数据库作为 SQLite 文件交付

我们有广泛的 Python 脚本来处理批量数据导出和自动删除先前订单中的重复记录

设计

当我们最初启动 Listen Notes 时,我们使用 Sketch 来处理我们所有的设计资产。

在 2018 年年中,在与设计师一起进行网站重新设计时,我们被介绍给 Figma。从那时起,它已成为我们所有设计资产的首选工具。

我们如何赚钱?

我知道一些理想主义的开发人员认为互联网上的所有内容都应该是免费的,或者唯一的道德赚钱方式是通过朝九晚五的工作或捐赠。Listen Notes 是一家营利性公司——就像一家咖啡店一样,我们有运营成本,Listen Notes 背后的人需要谋生。如果钱不是问题(例如,也许在我的下一生中成为一个信托基金的孩子?:),Listen Notes 可能会 100% 免费。

我们通过前面提到的三个 UI 进行货币化:

UI #1(网站):对 99.9% 的用户免费(带有广告),一些高级功能在付费墙后面(没有广告)。我们不强制长期订阅,而是默认提供一次性“2 天通行证”(想想迪士尼乐园门票),许多客户会在几年内重复购买。

UI #2(API)以免费增值模式运营。有一个免费计划用于副项目,一个自服务 PRO 计划(价格合理——如果您使用零个请求,则无需付费)以及一个涉及销售流程的企业计划

UI #3(数据导出)自服务选项允许用户按需购买一小部分数据,而企业客户则遵循完整的销售流程

我们使用 PandaDoc 进行合同管理,并使用 Stripe 和 PayPal 进行收款。使用两个支付处理器可以在其中一个出现故障或禁止我们时提供保障。

我们感谢 Stripe 非常友好和称职的客户支持,以及其出色的开发人员体验。但是,在处理争议费用时,PayPal 的表现明显优于 Stripe。

任何接受信用卡付款的企业都将不可避免地面临客户争议——恶意索赔是不可避免的。幸运的是,Listen Notes 每年只遇到一两次争议。通过 PayPal 处理时,我们的胜诉率接近 100%,而通过 Stripe 处理时约为 15%。需要明确的是,这并非 Stripe 的错;最终决定结果的是信用卡网络(Visa、MasterCard、American Express),Stripe 仅充当中间人。

为了最大程度地减少争议,我们遵循一些最佳实践:提供出色的产品、提供出色的客户服务以及确保客户在付款前清楚地了解条款。对于我们的自服务工具,我们会显示一个突出的模式,其中概述了条款,并要求客户在继续之前单击“我同意”按钮。虽然这可能会阻止一些用户,但它可以有效地降低未来争议的风险——这是我们愿意做出的权衡。

此外,我们的自服务工具会自动将 PDF 发票发送给客户。这些发票是通过使用 headless ChromePuppeteer 截取 HTML 版本发票的屏幕截图来创建的。

内部工具

运营数据库业务意味着不断维护和清理数据。

我们的内部工具可以帮助我们:

这些内部工具内置于我们的单体 Django 应用程序中,包括一个 Web 门户以及 ChatOps(Slack 中的命令行工具),用于快速操作。

AI / 机器学习

我们维护着几个用于 AI/ML 项目的小型存储库,主要用于诸如“人们也喜欢这些播客”之类的功能。但是最近,我们不得不使用 AI 来对抗 AI -

有了像 NotebookLM 这样的工具,大规模生产虚假播客比以往任何时候都更容易,垃圾邮件发送者已经开始将赌场链接插入 AI 生成的播客中,并将它们分发到各个平台上。Listen Notes 是第一个打击这个问题的人。我们开发了多个模型来检测 AI 生成的虚假播客,甚至开源了一个简单的模型:notebooklm-detector

几个月前,我们联系了 Notebook LM 的首席 PM,询问他们是否有用于检测 Notebook LM 生成的音频的工具。她最初说是的,但挣扎了几个星期才跟进,然后最终与几位同事离开了 Google。目前尚不清楚 Google 对这个项目的重视程度如何

无论如何,对抗 AI 生成的虚假播客仍然是一项持续的努力。我们投资了一台配置最高的 带有 M4 芯片的 Mac Mini 来训练模型并完善我们的检测和审核流程。我们还将一些生成的虚假播客上传到 Kaggle