liu

Discourse论坛完整分页方案研究

前端分页实现

分页模式:Discourse 前端主要采用无限滚动(infinite scroll)而非传统分页。也就是说,当用户浏览主题帖时,帖子会在页面底部自动连续加载,而不是分成多页 (Is pagination impossible or just hard? – Dev – Discourse Meta)。无限滚动已成为业界常见标准,在 Discourse 中也被充分运用 (Is pagination impossible or just hard? – Dev – Discourse Meta)。传统的页码导航仅在特定情况下提供(如爬虫或禁用 JS 时的退化处理),普通用户界面并不呈现页码 (Is pagination impossible or just hard? – Dev – Discourse Meta)。无限滚动搭配了一个交互式时间轴滑块(timeline)供用户快速跳转帖子位置,这在一定程度上替代了页码功能,让用户始终清楚自己在帖子中的位置 (Infinite scrolling is a total pain – Support – Discourse Meta)。

虚拟滚动与技术原理:为了在前端高效处理海量帖子,Discourse 实现了虚拟滚动和内容懒加载。当主题帖很长时,Discourse 不会一次在 DOM 中渲染所有帖子。相反,它采取“cloaking”策略,根据用户当前位置动态加载或卸载帖子的 DOM 元素,以控制内存占用 (Infinite scroll – is discourse recycling dom elements? – Dev – Discourse Meta) (Infinite scrolling is a total pain – Support – Discourse Meta)。例如,用户直接跳转到结尾时,中间的帖子并未全部加载,而是仅加载最新的一批帖子 (Infinite scrolling is a total pain – Support – Discourse Meta)。这样即使有数千条回复,浏览器也只维护当前视窗附近的帖子元素,从而避免性能瓶颈。早期 Discourse 使用 Ember.js 框架渲染组件,后来针对大型帖子进行了优化,引入了自定义虚拟 DOM(Widget)系统来提高渲染速度 (Infinite scroll – is discourse recycling dom elements? – Dev – Discourse Meta) (Infinite scroll – is discourse recycling dom elements? – Dev – Discourse Meta)。每个帖子渲染为一个虚拟DOM部件,利用 Ember 的组件机制和 virtual-dom差分更新 (A tour of how the Widget (Virtual DOM) code in Discourse works – Dev – Discourse Meta) (A tour of how the Widget (Virtual DOM) code in Discourse works – Dev – Discourse Meta)。这使得当新帖子加载或某些帖子卸载时,只对变化部分进行 DOM 更新,显著提升大量元素滚动时的性能 (Infinite scroll – is discourse recycling dom elements? – Dev – Discourse Meta)。

高效渲染大量数据:Discourse 针对海量帖子采取多种优化措施:首先,JSON 数据增量加载避免了首次加载过多内容 (Understanding infinite scrolling – Using Discourse – Discourse Meta)。页面初始只渲染首屏必要的帖子,其余通过 AJAX 按需获取 (Understanding infinite scrolling – Using Discourse – Discourse Meta)。其次,URL 历史管理保证长列表的浏览体验:随着用户滚动,地址栏会动态更新为当前帖子的锚点URL(如.../topic/3153/4表示正在查看第4楼) (Infinite Scrolling that Works | Evil Trout’s Blog)。这利用了 HTML5 History API (replaceState) 来在不刷新页面的情况下更新URL (Infinite Scrolling that Works | Evil Trout’s Blog) (Infinite Scrolling that Works | Evil Trout’s Blog)。当用户使用浏览器后退/前进按钮或直接访问带有特定帖号的链接时,应用会根据URL中的帖号请求相应位置附近的帖子,确保回到之前的阅读位置 (Infinite Scrolling that Works | Evil Trout’s Blog)。再次,Discourse 前端组件会缓存已加载的帖子数据(存储在 Ember 数据模型中),滚动回已阅区域时无需重复请求,提升了流畅度。此外,用户的阅读进度(如已读到第几楼)也会记录,当用户下次进入同一主题时可以自动定位到上次停留的位置。这些前端缓存和状态保存策略使用户无需反复手动翻页,获得连续顺畅的阅读体验 (Infinite scrolling is a total pain – Support – Discourse Meta) (Infinite scrolling is a total pain – Support – Discourse Meta)。

前端缓存策略:除了上述 Ember 模型缓存,Discourse 还通过浏览器本地存储和内存维护一些临时数据。例如,当用户浏览主题列表并点进某个主题后,返回列表页面时,上次加载的列表内容通常仍在内存中,无需重新请求。对于长帖子的滚动,前端持有该主题的帖子 ID 列表(下文详述后端如何提供),所以知道哪些帖子已加载,哪些尚未加载,从而避免重复获取 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。此外,为改善移动端和低性能设备上的体验,Discourse 针对大量 DOM 元素渲染做了专项优化(如前述自定义虚拟DOM和内容折叠),确保前端在高并发元素场景下依然平稳渲染 (Infinite scroll – is discourse recycling dom elements? – Dev – Discourse Meta)。总的来说,前端通过按需加载+虚拟化+缓存的组合,实现了对大量帖子数据的高效呈现。

后端分页逻辑

数据库分页查询实现:Discourse 后端采用多种分页技术相结合。对于主题列表(如分类页或最新主题列表),使用OFFSET/LIMIT的传统分页方式,根据页面参数提取相应的记录集。例如,请求/latest.json?page=1返回最新30个主题及一个more_topics_url指向第2页,有下一页时提供URL,没有则表示末页 (Latest Topics API pagination – Dev – Discourse Meta)。当请求page=2时再查询下一批主题,如此通过 OFFSET 翻页。这种方式简单直观,但当页数很大时数据库开销会增大。

对于帖子列表(主题中的回复帖),Discourse 优化采用了Keyset Pagination(基于游标/索引的分页)。每个主题内的帖子有顺序号post_number,后端利用它实现高效查询:例如获取某帖号附近的帖子时,不使用偏移,而通过条件筛选。若要加载某主题中比帖号 X 大的后续 N 条帖子,SQL 会用WHERE post_number > X ORDER BY post_number LIMIT N (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)(内部实际用sort_order或帖子ID达到相同效果)。这种 Keyset 查询通过已索引的键直接定位记录,不需要扫描和跳过之前的所有记录,性能更好且稳定 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub) (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。同样地,向上滚动加载上一屏内容时,后端用WHERE post_number < X ORDER BY post_number DESC LIMIT N拿到前 N 条,再倒序呈现 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub) (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。因此无论帖子总数多大,每次增量加载的查询成本主要与单页大小相关,而不会因偏移量增长而线性变慢。这对有上千帖的大主题尤为重要。

当然,Discourse 也保留了 OFFSET 模式用于某些场景(例如禁用 JS 时的传统分页)。后端 TopicView 对象中有一个 filter_posts_paged(page) 方法,当提供page参数时,会根据页码计算偏移量并提取对应帖子 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。但正常情况下这个路径很少用到,因为前端默认使用无限滚动而不是直接请求第几页数据。

API 接口分页支持:Discourse 提供完整的 JSON API,返回结果通常是分页的。以获取单个主题帖为例,GET /t/{topic_id}.json 默认只返回前20条帖子 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。响应中包含一个 post_stream 哈希,其中posts数组是已返回的帖子列表,而stream数组则是该主题内所有帖子ID的列表 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。借助这个ID流,客户端可以按需请求更多帖子。例如,收到前20条后,前端发现还有更多ID未加载,就可以调用 /t/{id}/posts.json?post_ids[]=... 接口,一次提交一批 post_ids 来获取对应帖子数据 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。Discourse 建议每次请求20条左右,以免单次数据过大 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。这种设计避免了像传统page=2那样需要记录偏移状态,前端完全按照需要的ID抓取,有点类似显式的cursor分页。对于特殊需求,API 还提供print=true参数,可让单次返回最多1000条帖子 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)(用于打印或导出场景)。此外,主题列表的 JSON(例如/latest.json)也带有 more_topics_url 字段指向下一页URL,客户端可检查该字段决定是否继续请求下一页 (Latest Topics API pagination – Dev – Discourse Meta)。值得注意的是,Discourse API 的分页多通过链接和参数提示,而非直接在header中给出cursor,这与一般REST分页略有不同,但逻辑上类似。

数据库查询性能优化:为支撑上述分页机制,后端在数据库层面做了多种优化。首先,索引设计:Discourse 在 Posts 表上对 (topic_id, post_number) 建立了唯一索引,这保证按主题ID和帖号查询有高效的查找路径 (FIX: unique index on topic_id, post_number · 1b03feacf8 – discourse …)。因此无论通过帖号范围还是帖子的全局ID查询,都能快速定位记录。其次,对于超大主题(Discourse 将帖子数>=10000定义为“mega topic” (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)),后端有特殊逻辑:默认情况下,请求一个主题会一次性获取该主题所有帖子ID用于 stream(哪怕几千条,也在可接受范围内),但若帖子数过多(上万),则不会一次取完所有ID,而是标记@contains_gaps为 true,仅获取部分 ID (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub) (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。接下来当用户滚动到未加载区域时,再动态去服务器请求更多ID。这个机制避免了初始加载超大数组和占用过多内存。再次,Discourse 使用预加载和批量查询技术减少查询频次。例如一次抓取帖子时,会用 ActiveRecord 的 includes 预先加载关联的用户、附件等数据 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)(这样前端拿到的数据已包含常用信息,不需要每条再单独查询)。对于 Topic 列表类查询,SQL 会尽量利用索引顺序而不进行复杂的排序计算,从而加快响应。

缓存机制的作用(Redis 等):除了数据库查询优化,Discourse 后端大量运用缓存来提升分页性能。Redis 被用作全局缓存和瞬态数据存储 (More details on how the Redis cache is utilized? – Dev – Discourse Meta)。对于匿名用户的请求,Discourse 会缓存整页响应,例如热门主题页或帖子页的HTML/JSON结果 (More details on how the Redis cache is utilized? – Dev – Discourse Meta)。当下一个匿名访客请求相同页面时,可以直接从 Redis 取出缓存结果,大幅减少数据库查询和渲染开销 (More details on how the Redis cache is utilized? – Dev – Discourse Meta)。这种页面级缓存对分页非常有利,因为访客往往会访问热门主题的第一页,而这些内容更新频率较低,缓存命中率高。另外,Redis 还用于消息总线(MessageBus)实现实时更新,但这属实时通知范畴,和分页加载略有不同 (More details on how the Redis cache is utilized? – Dev – Discourse Meta)。在缓存策略上,Discourse 区分登录用户和游客:游客命中更多缓存,而登录用户由于有个性化元素(已读状态等)缓存相对少 (More details on how the Redis cache is utilized? – Dev – Discourse Meta)。除了 Redis,应用层也有一些内存缓存,例如在一次请求中重复使用的查询结果会暂存。这些缓存手段确保了无论是通过分页接口批量获取数据,还是通过无限滚动实时加载,服务端都能快速响应,减少直接命中数据库的压力。

端到端流程分析

从用户滚动触发到页面展示,新旧数据在前后端的传递大致如下:

(image) 图:Discourse 无限滚动分页的数据流流程。用户滚动页面时,前端检测到接近底部,于是通过 AJAX 向服务器请求下一批帖子 JSON 数据;服务器收到请求后查询数据库(应用了 Limit 和必要的过滤条件,如获取ID大于当前最后一帖的后续帖子);查询结果以 JSON 格式返回前端;前端解析后将新帖子内容插入页面,并更新右侧时间轴和地址栏状态。整个过程在用户继续滚动时重复进行。

如上图所示,当用户在阅读主题时,前端会监听滚动事件。当接近页底时,JS 代码会自动发起一个 AJAX 请求(通常是/t/{topic_id}/posts.json?post_ids[]=...)来获取后续内容 (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。服务端根据请求参数确定需要返回哪些帖子(例如给出上次加载的最后一个 post_id,从而查询比它更新的下一批帖子)。查询使用预先优化的SQL(通过索引或键集定位),只取所需的条目数(默认20条) (Fetch All Posts from a Topic Using the API – Integrations – Discourse Meta)。然后服务端将帖子数据序列化为 JSON 发回。前端收到 JSON 后,Ember 应用将新帖子渲染并附加到现有帖子列表中,同时不会刷新整个页面。由于 Discourse 使用单页应用架构,页面上已有的帖子和新的帖子无缝拼接,而浏览器地址栏则通过 History API 更新为当前可见帖子的链接 (Infinite Scrolling that Works | Evil Trout’s Blog) (Infinite Scrolling that Works | Evil Trout’s Blog)。这样用户可以边滚动边加载数据,且可以自由使用浏览器的前进后退导航已加载的内容。值得一提的是,Discourse 前端的时间轴(滚动条旁的帖子序号指示器)也会更新,用户可以拖动滑块直接跳转帖子位置。若用户通过时间轴或直接点击某链接跳转到帖子中部,前端会计算目标帖附近的范围,并向服务器请求那一段范围内的帖子(利用之前提到的post_number定位查询) (Infinite Scrolling that Works | Evil Trout’s Blog)。加载后即刻呈现在视图中,保证跳转定位准确。整个过程中,网络传输采用 JSON 数据交换,在客户端解析为 HTML 片段插入,实现了端到端的增量分页加载

需要考虑无 JavaScript 情况以及SEO:Discourse 作为渐进增强应用,后端也能渲染基本的分页页面。当用户禁用 JS 或爬虫访问时,服务器会提供一个简化的只读视图,其中主题帖被分页为静态页面 (The effect of endless scrolling = Bad for Google / SEO – Feature – Discourse Meta)。例如访问/t/{slug}/{id}?page=2可获得该主题第二页的 HTML。这些页面通过 <noscript> 标签和标准链接供搜索引擎抓取 (The effect of endless scrolling = Bad for Google / SEO – Feature – Discourse Meta)。Discourse 会在首屏输出主题内容的 Noscript 版本,搜索引擎即使不执行 JS 也能索引完整帖子内容 (The effect of endless scrolling = Bad for Google / SEO – Feature – Discourse Meta)。同时,页面间还使用了 <link rel="next"><link rel="prev"> 提示爬虫有序地抓取分页。这样,虽然人性化界面采用无限滚动,SEO 并未受负面影响。换句话说,前端无限滚动并没有牺牲可索引性:真人用户享受无缝浏览体验,爬虫和无脚本环境则降级为传统分页确保内容可达。

分页策略对用户体验的影响显著。在 Discourse,看帖体验被设计得连贯且易于导航。无限滚动避免了人为翻页的中断,让用户专注于内容本身;搭配的时间轴提供了全局定位感,用户可以看到自己在全部回复中的进度,并快速跳转到开头或结尾等位置 (Infinite scrolling is a total pain – Support – Discourse Meta)。每当用户滚动时,地址栏即时更新帖号也方便了分享特定楼层链接和稍后返回原处 (Infinite Scrolling that Works | Evil Trout’s Blog) (Infinite Scrolling that Works | Evil Trout’s Blog)。相较之下,传统分页需要用户记住页码,分享时常常只能给出“第X页第Y楼”这样的说明,不够精确。而 Discourse 直接支持分享具体楼层链接,点开即加载上下文,非常便利 (Infinite Scrolling that Works | Evil Trout’s Blog) (Infinite Scrolling that Works | Evil Trout’s Blog)。在性能体验方面,Discourse 针对无限滚动做了优化使加载感觉自然。如果帖子很多,逐屏加载可能稍有延迟,但应用用加载指示和预取机制将其降到最低,而且用户也可以通过时间轴快速跳过中间部分而不必等待逐页加载 (Infinite scrolling is a total pain – Support – Discourse Meta)。不少资深用户反馈无限滚动比传统分页更加顺畅,结合 timeline 滑块后“至少不比分页差,而且更精确” (Infinite scrolling is a total pain – Support – Discourse Meta) (Infinite scrolling is a total pain – Support – Discourse Meta)。当然,一些惯用旧式论坛的人起初不适应无限滚动,但大多数用户习惯后都认可其优越性 (Infinite scrolling is a total pain – Support – Discourse Meta) (Infinite scrolling is a total pain – Support – Discourse Meta)。

技术原理分析

Discourse 的分页方案实则是对传统分页模型的重新思考,用现代 Web 技术加以改良。它将分页视为自动化的流程,让用户感觉不到“翻页”,仿佛是在一页中无限延伸 (Infinite scrolling is a total pain – Support – Discourse Meta)。实现上前后端紧密配合,通过增量数据流达到与分页相同的效果而无页码 UI。以下结合部分代码和实例进行解析:

  • 代码流程示例:当前端需要下一批帖子时,会调用 TopicViewfilter_posts_* 系列方法。假设用户跳转到帖子中部,应用会调用 filter_posts_near(post_number) 来获取附近的帖子 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。该方法内部计算需向前取多少条、向后取多少条,然后通过 ActiveRecord 生成两段查询:一段按sort_order < 当前帖排序值倒序取一定数量 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub);另一段按sort_order >= 当前值正序取余下数量 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。这样前后各取一部分帖子ID,然后再合并为完整结果集 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub) (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。这一过程利用了数据库的索引顺序扫描(即Keyset方法),避免了偏移跳过。对于一般连续下滚加载,下一个方法是 filter_posts_by_post_number(last_post_number, asc=true),逻辑类似:用WHERE sort_order > last_order LIMIT 20获取后20条帖子ID (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub),再根据这些ID去加载帖子内容 (discourse/lib/topic_view.rb at main · discourse/discourse · GitHub)。可以看到,核心查询并没有使用 OFFSET,而是通过条件筛选界定范围并 limit固定数量,性能不会随位置远近而骤降。

  • 对比 OFFSET 性能:传统 OFFSET/LIMIT 在页数很大时效率会降低,因为数据库需跳过大量记录。Discourse 在必要时仍支持 OFFSET,例如上文提到的 filter_posts_paged(page) 实现如下:
    “`ruby
    @filtered_posts.offset(min).limit(@limit).pluck(:id) ([discourse/lib/topic_view.rb at main · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/master/lib/topic_view.rb#:~:text=page%20%3D%20))“`可见它直接使用了 `.offset(min).limit(limit)` 获取该页帖子ID。但这个方法主要用于嵌入或只读模式。在正常无限滚动下,不会逐页累积 offset,而是根据已加载最后一条的标识进行“下页”查询。因此,Discourse 的方案相当于**避免了 “跳过”**,每次查询都从上次结尾直接查找下一段,这在数据量很大时更加高效 ([discourse/lib/topic_view.rb at main · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/master/lib/topic_view.rb#:~:text=if%20asc))。性能对比如下:OFFSET 分页查询第100页需要扫描前99页记录,而 Keyset 分页查询第100页只根据上一页最后一条记录直接取后续记录,耗时基本与取第一页相当。这对于动辄上千条回复的主题,避免了翻到后半段时查询变慢的问题。

  • 不同场景的分页方案选择:Discourse 的无限滚动+按需加载非常适合论坛讨论串这种需要顺序阅读、大部分用户会从头阅读到尾的场景。它保证了沉浸式体验和良好的交互(实时更新、进度保存等)。然而,对于内容检索数据浏览场景,传统分页有时更方便,例如在搜索结果、成员列表等,用户可能需要随机跳转某页或知道总页数。在这些场景下 Discourse 也提供了一些分页参数支持,或采用“显示更多”按钮一次加载一页数据的方式。总的来说:

    • 无限滚动适用于内容连续性强、用户倾向于一直浏览下去的场景(如社交动态流、论坛帖子流)。优点是用户体验流畅,缺少打断,特别是在移动端操作简便 (Infinite scrolling is a total pain – Support – Discourse Meta)。缺点是对用户直接定位中间位置不直观(但 Discourse 通过timeline解决了这个问题 (Infinite scrolling is a total pain – Support – Discourse Meta))。
    • 传统分页适用于用户需要随机访问精确跳转的场景,尤其当内容条目非常多且用户不可能全部浏览时。例如文章索引、搜索结果等。分页的存在让用户对内容规模有概念,并可根据页号二分查找。但它需要用户额外点击操作,连续阅读体验中断。
    • 加载更多(负载分页)是一种折中方案,常见于移动端:一次显示一页内容,在底部点击“加载更多”或自动加载下一页。相比严格的分页,它弱化了页的概念,但不像无限滚动那样彻底取消分页边界。Discourse 的主题列表在到底部时就是通过“加载更多”按钮按页增量加载的 (Latest Topics API pagination – Dev – Discourse Meta)。这种方案优点是用户有控制权,避免一次加载过多导致性能问题。
  • 性能比较与权衡:从技术角度看,不存在“一刀切”的最佳分页法,必须根据场景权衡。无限滚动在前端需要较复杂的状态管理和缓存,如不加优化大量DOM元素会导致内存和性能问题,这正是 Discourse 通过虚拟列表和内容卸载来解决的 (Infinite scrolling is a total pain – Support – Discourse Meta)。传统分页实现简单,服务器压力也可控(每页固定查询),但用户体验上不断跳转页面较繁琐,而且每次页面刷新浪费带宽。Keyset 分页性能好但实现复杂,需要有合适的排序键并处理好边界情况,而 OFFSET 简单但不适合深度分页。Discourse 采用的方案综合了多种技术,使得在实际使用中既保证性能又提供良好用户体验。正如有用户评价的那样:Discourse 的无限滚动更像是自动翻页,既保持了传统分页的功能,又省去了人工翻页的麻烦 (Infinite scrolling is a total pain – Support – Discourse Meta)。

综上,Discourse论坛的分页方案通过前端无限滚动+虚拟渲染、后端Keyset分页+缓存优化,达成了顺畅的浏览体验和高性能的数据传输。代码层面的精巧设计(如帖子流ID列表、History API利用)以及对不同场景的兼顾,使其成为分页技术在现代Web应用中的成功实践 (Understanding infinite scrolling – Using Discourse – Discourse Meta) (Infinite Scrolling that Works | Evil Trout’s Blog)。这一方案在大型社区中经过验证,既照顾了SEO等技术需求,又为用户提供了友好的交互界面。

GreenCloud注册似乎过于严格

  1. 第一次在GreenCloud填写的信息为非实名,使用网页代理,美国地址,并使用paypal进行支付,paypal为美区实名,购买后提示疑似欺诈

  2. 联系客服后,客服提示

We do not allow orders with fake information or placed through a proxy/VPN.
  1. 遂使用远程桌面(参见此文)+修改在GreenCloud填写的信息为实名后再次购买。

  2. 仍然使用paypal支付,扣款成功,但受到邮件,提示需要补全信息

Thank you for your order! Unfortunately, we regret to inform you that our order verification system has flagged your order.
To verify this order, please send us a copy of a utility bill that clearly shows the same name and address as your Paypal like ID, passport, electricity bill or bank statement..
We apologize for any inconveniences that may result from this process.
Thanks!
  1. 直接回复邮件,提供美卡银行对账单后,审批通过

中国联通连搬瓦工洛杉矶似乎翻车了

延迟从稳定150ms无丢包变成现在250+伴随丢包了,有类似的吗?

看这个内容比较像,但时间对不上。
https://hostloc.com/thread-1336975-1-1.html

20250117:貌似延迟回落到了180ms左右,没有丢包了。

自建新论坛“冷月清谈”简介

最近一段时间基于discourse上线了一个综合性论坛http://www.xinfinite.net.

目前初期是收集一些私域的数据,并进行加工(主要是导读和互动问答,起名为冷月清谈怜星夜思),并最终呈现。预计涵盖AI,航空、酒店常旅客、信用卡,开发技术,游戏等。

开发

站在巨人的肩膀上,原则就是尽量减少开发工作,主要做了以下几方面的事情。

  1. 数据采集+调度
  2. 数据加工,样式转换,导读和互动问答生成
  3. 数据发布+调度
  4. 自动评论
  5. discourse插件,主要是还原数据采集部分的样式

导读和互动问答,使用了GPT-4-tube,发现成本太高,后换为Gemini-pro-1.5。

部署

考虑到用户体验和成本,方案如下
1. 主站域名解析至香港搬瓦工机房(2C2G),转发请求至oracle cloud(2C12G,ARM)。
2. 对外正式访问的图片和视频使用阿里云的oss,基于discourse的能力,采用s3的api写入,cdn为阿里云的全站加速,源站为oss。
3. 采集的原始资源存储在家用nas上,使用minio方案,对外使用cloudflare的cdn访问。

关于家宽

显然,生产环境使用家宽的不确定性很大。

但由于成本和技术栈等方面因素,我不太想与discourse和阿里云过于耦合,所以采用了家宽这种方案,具体如下。

  1. 数据采集时,将资源上传至本地nas,使用minio提供的s3接口。
  2. 数据的原始html中存储cloudflare的cdn地址,源站指向家宽中的minio地址。
  3. 将html数据写入discourse,discourse会将资源上传至阿里云的oss,并进行优化、压缩和路径替换。

采用这种方案没有浪费阿里云的加速带宽,后期也可以灵活替换服务商。

以上简单介绍了相关工作,如果各位对某些部分感兴趣,欢迎留言讨论。

(北京直飞,公务舱)0元游香港

本文写自2023年7月

引言

相信大家都有信用卡,或者某呗某条,那么大家平时是如何进行支付的呢。

大家可能觉得不重要,反正最终都要还给银行/二马。

那么如果我说,选择一个好的支付方式,能够使我们实现每年免费公务舱出境畅游,大家会不会还这样认为呢?

Continue reading…

美卡申请全记录(一)

各位好,今天跟大家分享一下我申请美卡的情况,铺垫可能比较多,且尚未达到我的最终目的,所以起名为(一)。

前言

以前一直没有什么机会接触美卡。

一来胆子比较小:fearful:,没有想过去美国转转,没有签证;

二来也觉得所有的门槛都比较高,可能自身实力不足,够不到;

三来也没有细细了解过美卡的权益,包括返现、航司酒店联名等,觉得跟国内的信用卡可能差不多,毕竟国内也年年都有”神“卡。

Continue reading…