<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Serial · XB 现场笔记</title><link>https://www.xbcatm.com/zh/tags/serial/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://www.xbcatm.com/zh/tags/serial/index.xml" rel="self" type="application/rss+xml"/><item><title>Postgres 序列用一个缓存发号</title><link>https://www.xbcatm.com/zh/posts/postgres-sequence-caches/</link><pubDate>Mon, 02 Aug 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/posts/postgres-sequence-caches/</guid><description>序列缓存按后端预留数值；正常退出、回滚与预留边界可以解释空号，却不能单独判断业务是否丢数据。</description><content:encoded>&lt;p&gt;PostgreSQL 序列缓存为数据库后端预留数值，不属于某个应用对象，也不只属于一笔事务。理解这个边界，才能解释为什么序列保存的位置会领先于真正返回的号码，为什么重新连接也会留下空洞，以及为什么调小 CACHE 不能让标识连续。首先要区分分配器状态，与应用真正成功提交的业务记录，不能把两者当成同一个计数器。&lt;/p&gt;
&lt;h2 id="三个不同的数字"&gt;三个不同的数字&lt;/h2&gt;
&lt;p&gt;一个新建的升序序列使用 CACHE 5 时，第一次 nextval 可以返回一，而 last_value 已记录五。后者是预留边界，不是已插入行数，也不表示一到五都已经交给应用。currval 表示当前会话最近为该序列建立的值，其他连接取号不会替换它。监控时若不说明这些字段的作用域，就很容易把预留数量误当成业务数量。&lt;/p&gt;
&lt;p&gt;同一后端后续取号，可以使用已经预留的数值。PostgreSQL 实现中既有后端局部的快速路径，也有补充缓存时的缓冲锁；把每次 nextval 都说成对普通表记录加一把行锁并不准确。缓存减少反复访问序列状态，但不能据此认定某个应用的插入延迟主要来自序列竞争。修改参数前，应先测量真实瓶颈，而不是根据取号机制猜测整体性能。&lt;/p&gt;
&lt;h2 id="会话寿命也影响空号"&gt;会话寿命也影响空号&lt;/h2&gt;
&lt;p&gt;即使正常退出，会话结束时没有用完的预留值也会被放弃。因此，相同取号速率下，频繁建立数据库会话的服务，可能比使用长期连接池的服务放弃更多预留。缓存跟随服务器会话；应用看到一个连接对象，并不足以说明底层数据库会话是否一直存在，连接复用策略也是实验条件的一部分。&lt;/p&gt;
&lt;p&gt;不同会话还可以分别持有不同区间。一个先返回一，另一个返回六，第一个随后再返回二。这是分配交错，不代表提交顺序，也不能证明这些值已经丢失。即使 CACHE 为一，事务仍可能先取号后提交，顺序与另一个事务相反。提交之前写入的时间戳同样不能自动提供真实提交顺序，不能只给字段换个名字就获得新的保证。&lt;/p&gt;
&lt;h2 id="坏掉的样子"&gt;坏掉的样子&lt;/h2&gt;
&lt;p&gt;不要把 CACHE 当成崩溃后最大跳号数的公式。多个会话可以同时持有预留，而实现还会把一部分未来序列进度提前写入日志。事务回滚、走冲突处理分支的插入，以及取到但没有使用的值，都会增加空洞。缺号本身既不能证明丢了业务数据，也不能证明没有丢；发现故障时，应核对已提交记录和恢复证据，再判断是否只是分配器行为。&lt;/p&gt;
&lt;p&gt;正常运行期间，非循环分配在管理员没有把序列重置回已用范围时，会提供不同数值。但循环、手工重置，以及显式导入编号，都可能改变这个前提。表仍然需要主键或唯一约束保证存储完整性。减小缓存不能代替这些约束，不能找回已经删除的记录，也不会自动让业务编号流程具备可审计性。在数据库外持久使用一个号码之前，应先提交取号事务；崩溃可能使尚未提交的序列变化是否保留变得不确定。&lt;/p&gt;
&lt;p&gt;调整序列设置时，还要考虑活跃会话已经拿到的预留值。不要为了补洞，在并发写入期间把序列随意重置到表中最大编号。如果业务确实要求已签发号码连续，应先明确签发、回滚、取消和外部发布的边界，再评估事务计数器。没有经过实际负载测量，就不存在可以普遍承诺的最佳缓存大小或吞吐提升倍数。&lt;/p&gt;
&lt;h2 id="快速验证"&gt;快速验证&lt;/h2&gt;
&lt;p&gt;下面的无套接字练习，使用两个先后运行的单用户后端，访问同一个新初始化的可丢弃集群。以非 root 账户执行脚本，并把 PostgreSQL 18 的 initdb 与 postgres 放入 PATH。绝不能让单用户模式访问正在运行的集群。该模式具有隐式超级用户权限，不能验证并发客户端、真实进程间锁竞争或故障切换；本例只研究缓存预留的生命周期。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -eu
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;umask&lt;/span&gt; &lt;span class="m"&gt;077&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;lab&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TMPDIR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;/tmp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/xbcatm-sequence-cache.XXXXXX&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;initdb -D &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/data&amp;#34;&lt;/span&gt; --no-locale --encoding&lt;span class="o"&gt;=&lt;/span&gt;UTF8 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --auth-local&lt;span class="o"&gt;=&lt;/span&gt;trust --auth-host&lt;span class="o"&gt;=&lt;/span&gt;reject &amp;gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/init.log&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;postgres --single -j -D &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/data&amp;#34;&lt;/span&gt; -c &lt;span class="nv"&gt;io_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sync -c &lt;span class="nv"&gt;log_min_messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;notice postgres &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-a.log&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;SQL&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;CREATE SEQUENCE cache_probe CACHE 5;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SELECT nextval(&amp;#39;cache_probe&amp;#39;) AS first_value;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SELECT last_value AS reserved_through FROM cache_probe;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;BEGIN;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SELECT nextval(&amp;#39;cache_probe&amp;#39;) AS rolled_back_value;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;ROLLBACK;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SELECT nextval(&amp;#39;cache_probe&amp;#39;) AS after_rollback;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;DO $$ BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; IF currval(&amp;#39;cache_probe&amp;#39;) &amp;lt;&amp;gt; 3 OR
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; (SELECT last_value FROM cache_probe) &amp;lt;&amp;gt; 5 THEN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; RAISE EXCEPTION &amp;#39;cache reservation or rollback result wrong&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; END IF;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; RAISE NOTICE &amp;#39;cache_probe_a_ok&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;END $$;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;(ERROR|FATAL|PANIC):&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-a.log&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; 1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -q &lt;span class="s1"&gt;&amp;#39;cache_probe_a_ok&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-a.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;postgres --single -j -D &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/data&amp;#34;&lt;/span&gt; -c &lt;span class="nv"&gt;io_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sync -c &lt;span class="nv"&gt;log_min_messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;notice postgres &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-b.log&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;&amp;#39;SQL&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SELECT nextval(&amp;#39;cache_probe&amp;#39;) AS after_clean_session_end;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;DO $$ BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; IF currval(&amp;#39;cache_probe&amp;#39;) &amp;lt;&amp;gt; 6 OR
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; (SELECT last_value FROM cache_probe) &amp;lt;&amp;gt; 10 THEN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; RAISE EXCEPTION &amp;#39;unused cache values were unexpectedly reused&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; END IF;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; RAISE NOTICE &amp;#39;cache_probe_b_ok&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;END $$;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;DROP SEQUENCE cache_probe;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; grep -E &lt;span class="s1"&gt;&amp;#39;(ERROR|FATAL|PANIC):&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-b.log&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; 1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -q &lt;span class="s1"&gt;&amp;#39;cache_probe_b_ok&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-b.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-a.log&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;/session-b.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;retained_lab %s\n&amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$lab&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完整脚本已在 PostgreSQL 18.6 执行。第一个后端返回一，记录预留边界五，在随后回滚的事务中分配二，再返回三。断言核对缓存边界仍为五。单用户模式的 -j 使用空行划分命令，因此脚本保留必要的空行，确保事务边界没有因整段输入被视为同一条命令而改变。观察结果时，也需要区分真正执行的语句与后端输出的提示文字。&lt;/p&gt;
&lt;p&gt;第一个后端正常结束后，第二个返回六，并记录预留边界十。四和五从未返回给调用方，二则已经返回，但属于最后回滚的事务。这是在没有制造崩溃的情况下，演示两种不同空洞来源。两个成功通知都出现，序列最终被删除；脚本打印的目录保留可丢弃集群与日志，以便检查完整输出。&lt;/p&gt;
&lt;p&gt;脚本同时检查错误文本和进程状态，因为独立后端即使报告 SQL 错误，也可能以成功状态结束。这个练习验证预留与会话结束的关系，不是吞吐基准或持久性演练。它不能提供固定崩溃跳号上限，也不能据此推荐生产缓存大小。迁移结论时，必须保持实验覆盖范围与实际业务问题一致。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/18/sql-createsequence.html"&gt;PostgreSQL CREATE SEQUENCE&lt;/a&gt;，会话预留、顺序和未使用数值，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/18/functions-sequence.html"&gt;PostgreSQL 序列函数&lt;/a&gt;，回滚、会话值与完整性边界，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postgres/postgres/blob/REL_18_STABLE/src/backend/commands/sequence.c"&gt;PostgreSQL 18 序列实现&lt;/a&gt;，后端局部分配与预写日志，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/18/app-postgres.html"&gt;PostgreSQL 独立服务进程&lt;/a&gt;，单用户命令边界与限制，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>