学习

第13章云端的MySQL

第13章 云端的MySQL

许多人在云中使用MySQL,有时候规模还非常庞大,这并不奇怪。从我们的经验来看,大多数人使用的是Amazon Web Services平台(AWS):特别是Amazon的弹性计算云(Elastic Compute Cloud,EC2),弹性块存储(Elastic Block Store,EBS),以及更小众的关系数据库服务(Relational Database Service,RDS)。

为了便于讨论MySQL在云中的应用,可以将其粗略分为两类。

IaaS(基础设施即服务)

Iaas是用于托管自有的MySQL服务器的云端基础架构。可以在云端购买虚拟的服务器资源来安装运行MySQL实例。也可以根据需求随意配置MySQL和操作系统,但没有权限也无法看到处于底层的物理硬件设备。

DBaaS(数据库即服务)

MySQL本身作为由云端管理的资源。用户需要先收到MySQL服务器的访问许可(通常是一个连接串)才能访问。也可以配置一些MySQL选项,但没有权限去控制或查看底层的操作系统或虚拟服务器实例。例如 Amazon运行MySQL的RDS。其中一些服务器并非真的使用MySQL,但它们能兼容MySQL协议和查询语言。

我们讨论的重点主要集中在第一类:云托管平台,例如AWS、Rackspace Cloud以及Joyent(1)。有许多很好的资源介绍如何部署和管理MySQL及其运行所需要的资源,并且也有非常多的平台来完全满足这样的需求,所以我们不会展示代码样例或讨论具体的操作技术。因此,本章关注的重点是,在云端运行MySQL还是在传统服务器上部署MySQL,它们在最终经济上和性能特性上的关键区别是什么。我们假定你对云计算很熟悉。这里不是对云计算概念的简单介绍,我们的目的只是帮助那些还不熟悉在云端部署MySQL的用户在使用时避免一些可能遇到的陷阱。

一般来说,MySQL能够在云中很好地运行。在云中运行MySQL并不比在其他平台困难,但有一些非常重要的差别。你需要注意这些差别并据此设计应用和架构来获得好的效果。某些场景下在云端托管MySQL并不是非常适合,有时候则很适合,但大多数时候云仅仅是另外一个部署平台而已。

云是一个部署平台,而不是一种架构,理解这一点很重要。架构会受平台的影响,但平台和架构明显不同。如果你把架构和平台搞混了,就可能会做出不合适的选择而给以后带来麻烦。这也正是我们要花时间讨论云端的MySQL到底有什么不同的原因。

13.1 云的优点、缺点和相关误解 #

云计算有许多优点,但很少是为MySQL特别设计。有一些书籍已经介绍了相关的话题(2),这里我们不再赘述。不过我们会列出一些比较重要的条目供参考,因为接下来会讨论到云计算的缺点,我们不希望你认为我们是在过分苛求云计算。

  • 云是一种将基础设施外包出去无须自己管理的方法。你不需要寻找供应商购买硬件,也不需要维护和供应商之间的关系,更无须替换失效的硬盘驱动器等。
  • 云一般是按照即用即付的方式支付,可以把前期的大量资本支出转换为持续的运营成本。
  • 随着供应商发布新的服务和成本降低,云提供的价值越来越大。你自己无须做任何事情(例如升级服务器),就可以从这些提升中获益;随着时间推移你会很容易地获得更多更好的选择并且费用更低。
  • 云能够帮助你轻松地准备好服务器和其他资源,在用完后直接将其关闭,而无须关注怎么处理它们,或者怎么卖掉它们收回成本。
  • 云代表了对基础设施的另一种思考方式——作为通过API来定义和控制的资源——支持更多的自动化操作。从“私有云”中也可以获得这些好处。

当然,不是所有跟云相关的东西都是好的。这里有一些缺点可能会构成挑战(在本章稍后部分我们会列出MySQL特有的缺点)。

  • 资源是共享并且不可预测的,实际上你可以获得比你支付的更多的资源。这听起来很不错,但却导致容量规划很难做。如果你在不知情的情况下获得了比理应享受到的更多的计算资源,那么就存在这样的风险:别人也许会索要他们应得的资源,这会使你的应用性能退化到应有的水平。一般来说,很难确切地知道本来应该得到多少(资源),大多数云托管服务提供商不会对此给出确切的答案。
  • 无法保证容量和可用性。你可能以为还可以获得新实例,但如果供应商已经超额销售了呢?这在有很多共享资源的情况下会发生,同样也会发生在云中。
  • 虚拟的共享资源导致排查故障更加困难,特别是在无法访问底层物理硬件的情况下无法检查并弄清到底发生了什么。例如,我们曾经看到过一些系统的iostat显示的I/O很正常或者vmstat显示的CPU很正常,而当实际衡量完成一个任务需要的时间时,资源却被系统上的其他东西严重占用了。如果在云平台上出现了性能问题,尤其需要去仔细地分析检测。如果对此并不擅长,可能就无法确认到底是底层系统性能差,还是你做了什么事情导致应用出现不合理的资源需求。

总的来说,云平台上对性能、可用性和容量的透明性和控制力都有所下降。最后,还有一些对云的误解需要记住。

云天生具备更好的可扩展性

应用、云的架构,以及管理云服务的组织是不是都是可扩展的。云并不是天生可扩展的,云也仅仅是云而已,选择一个可扩展的平台并不能自动使应用变得可扩展。的确,如果云托管提供商没有超售,那么你可以根据需求来购买资源,但在需要时能够获得资源仅仅是扩展性的一个方面而已。

云可以自动改善甚至保证可用时间

一般来说,个别在云端托管的服务器比那些经过良好设计的专用基础设施更容易发生故障或运行中断。但是许多人并没有意识到这一点。例如,有人这样写道:“我们将基础设施升级到基于云构建的系统以保证100%的可用时间和可扩展性”。而就在这之前AWS遭受了两次大规模的运行中断故障,导致很大一部分用户受影响。好的架构能够用不可靠的组件设计出可靠的系统,但通常更可靠的基础设施可以获得更高的可用性。(当然不可能有100%的可用时间的系统。)

另一方面,购买云计算服务,实际上是购买一个由专家构建的平台。他们已经考虑了许多底层的东西,这意味着你可以更专注于上层工作。如果构建自己的平台而对其中的那些细枝末节并不精通,就可能犯一些初学者的错误,早晚会导致一些宕机时间。从这一点来说,云计算能够帮助改善可用时间。

云是唯一能提供[这里填入任意的优点]的东西

事实上,许多云的优点是继承自构建云平台所用到的技术,即使不使用云也可以获得(3)。例如,通过管理得当的虚拟化和容量规划,可以像任何一个云平台那样简单快速地启动(spin up)一台新的机器。完全没必要专门使用云来做到这一点。

云是一个“银弹”(silver bullet)

虽然大部分人会认为这很荒谬,但确实有人会这么认为。实际上完全没有这回事。

无可否认,云计算提供了独特的优点,随着时间的推移,关于云计算是什么,以及它们在什么情况下会有帮助,我们会获得更多的共识。但有一点非常肯定:它是全新的,我们现在所做的任何预测都未必经得起时间的考验。我们会在本书讨论相对安全的部分,而将剩下的部分留给读者讨论。

13.2 MySQL在云端的经济价值 #

在一些场景下云托管比传统的服务器部署方式更经济。以我们的经验来看,云托管比较适合尚处于初级阶段的企业,或者那些持续接触新概念并且本质上是以适用为主的企业,例如移动应用开发者或游戏开发者。这些技术的市场随着移动计算的扩张出现了爆炸式增长,并且仍然是快速发展的领域。在许多情况下,成功的因素并不为开发者所控制,例如口口相传的推荐或者恰逢重要国际事件的时机。

我们已经帮助很多公司在云中构建移动应用、社交网络以及游戏应用。其中一个他们大量使用的策略是尽可能又快又便宜地开发和发布应用。如果一个应用碰巧变得流行了,公司将投入资源扩大其规模;否则就会很快终结这些应用。一些公司构建并发布的应用的生命周期甚至只有几个星期,在这样的环境下,可以毫不犹豫地选择云托管。

如果是一个小规模的公司,可能无法提供足够的硬件来自建数据中心以满足一个非常流行的Facebook应用的发展曲线。我们也协助过一些大型的Facebook应用进行扩展,它们能够以今人惊讶的速度增长——有时甚至会快到让一个主机托管公司耗尽资源。更为严重的是,这些应用的增长是完全无法预测的;它们可能只有极少量的用户(也可能突然有了爆炸性的用户数量增长)。我们在数据中心和云中都遇到过这样的应用。如果是一个小公司,云可以帮你避免前期快速注入大量的资金来获得更快更大规模的风险。

云的另一种潜在的大用途是运行不是很重要的基础设施,例如集成环境、开发测试平台,以及评估环境。假设部署周期是两个星期。你会每天每个小时都测试部署一次,还是只在项目最后的冲刺时测试?许多用户只是偶尔需要筹划和部署测试环境。在这种场景下,云可以帮助节约不少钱。

以下是我们使用云的两种方式。第一个是作为我们对技术职员面试的一部分,我们会询问如何解决一些实际的问题。我们使用AMI(Amazon Machine Images)来模拟一些被“破坏”的机器,然后让求职者登录并在服务器上执行一系列任务。我们不必开放他们到内部网络的授权,这种方案显然要方便得多。另一个是作为新项目的工作平台和开发服务器。有一个这样的项目已经在一台云端开发服务器上运行了数个月,而花费不足一美元!这在我们自己的基础设施上是不可能做到的。单是发送一封邮件给系统管理员申请开发服务器的时间价值就不止一美元。

但是另一方面,云托管对于长期项目而言可能会更加昂贵。如果打算长远地使用云,就需要花时间来计算一下(它是否划算)。除了猜想未来的创新能给云计算和商用硬件带来什么,还需要做基准测试以及一个完整的总体持有成本(TCO)账单。为了理清事情的本质并考虑全面所有相关的细节,你需要把所有的事情最终归结为一个数字:每美元的业务交易数。事情变化得太快,所以我们将这个留给读者思考。

13.3 云中的MySQL的可扩展性和高可用性 #

正如我们之前提到的,MySQL并不会在云端自动变得更具扩展性。事实上,如果机器的性能较差,会导致过早使用横向扩展策略。况且云托管服务器相比专用的硬件可靠性和可预测性要更差些,所以想在云端获得高可用性需要更多的创新。

但是总的来说,在云端中扩展MySQL和在其他地方扩展没有太多的差别。最大的不同就是按需提供服务器的能力。但是也有某些限制会导致扩展和高可用实现起来有点麻烦,至少在有些云环境中是这样的。例如,在AWS云平台中,无法使用类似虚拟IP地址的功能来完成快速原子故障转移。像这种对资源的有限控制意味着你需要使用其他办法,例如代理。(ScaleBase也值得去看看。)

云另外一个迷惑人的地方是梦想中的自动扩展——就是根据需求的增加或减少来启动或关闭实例。尽管对于诸如Web服务器这样的无状态部分是可行的,但对于数据库服务器而言则很难做到,因为它是有状态的。对于一些特定的场景,例如以读为主的应用,可以通过增加备库的方式来获得有限的自动扩展(4),但这并不是一个通用的解决方案。实际上,虽然许多应用在Web层使用了自动扩展,但MySQL并不具备在一个无共享(Shared Nothing)集群中的对等角色服务器之间迁移的能力。你可以通过分片架构来自动重新分片并自动增长或收缩(5),但MySQL本身是无法自动扩展的。

事实上,因为数据库通常是一个应用系统中主要或唯一的有状态并且持久化的组件,所以把应用服务迁移到云端是很普遍的事情,因为除数据库之外的所有部分都可以从云中收益——Web服务器、工作队列服务器、缓存等——而MySQL只需要处理剩下的东西。毕竟,数据库并非世界的中心。如果应用系统其他部分获得的好处,超过了让MySQL运行得足够好而投入的额外开销和必需的工作量,那这不是一个是否会发生的问题,而是怎么发生的问题。要回答这个问题,最好先了解你在云中可能碰到的额外的挑战。这些通常围绕着数据库服务器的可用资源。

13.4 四种基础资源 #

MySQL需要四种基础资源来完成工作:CPU周期、内存、I/O,以及网络。这四种资源的特性和重要程度在不同的云平台上各不相同。可以通过了解它们的不同之处和对MySQL的影响,以决定是否选择在云中托管MySQL。

...

第12章高可用性

第12章 高可用性

本章将讲述我们提到的复制、可扩展性以及高可用性三个主题中的第三个。归根结底,高可用性实际上意味着“更少的宕机时间”。然而糟糕的是,高可用性经常和其他相关的概念混淆,例如冗余、保障数据不丢失,以及负载均衡。我们希望之前的两章已经为清楚地理解高可用性做了足够的铺垫。跟其他两章一样,这一章也不仅仅是关注高可用性的内容,一些相关的话题也会综合阐述。

12.1 什么是高可用性 #

高可用性实际上有点像神秘的野兽。它通常以百分比表示,这本身也是一种暗示:高可用性不是绝对的,只有相对更高的可用性。100%的可用性是不可能达到的。可用性的“9”规则是表示可用性目标最普遍的方法。你可能也知道,“5个9”表示99.999%的正常可用时间。换句话说,每年只允许5分钟的宕机时间。对于大多数应用这已经是令人惊叹的数字,尽管还有一些人试图获得更多的“9”。

每个应用对可用性的需求各不相同。在设定一个可用时间的目标之前,先问问自己,是不是确实需要达到这个目标。可用性每提高一点,所花费的成本都会远超之前;可用性的效果和开销的比例并不是线性的。需要保证多少可用时间,取决于能够承担多少成本。高可用性实际上是在宕机造成的损失与降低宕机时间所花费的成本之间取一个平衡。换句话说,如果需要花大量金钱去获得更好的可用时间,但所带来的收益却很低,可能就不值得去做。总的来说,应用在超过一定的点以后追求更高的可用性是非常困难的,成本也会很高,因此我们建议设定一个更现实的目标并且避免过度设计。幸运的是,建立2个9或3个9的可用时间的目标可能并不困难,具体情况取决于应用。

有时候人们将可用性定义成服务正在运行的时间段。我们认为可用性的定义还应该包括应用是否能以足够好的性能处理请求。有许多方法可以让一个服务器保持运行,但服务并不是真正可用。对一个很大的服务器而言,重启MySQL之后,可能需要几个小时才能充分预热以保证查询请求的响应时间是可以接受的,即使服务器只接收了正常流量的一小部分也是如此。

另一个需要考虑的问题是,即使应用并没有停止服务,但是否可能丢失了数据。如果服务器遭遇灾难性故障,可能多少都会丢失一些数据,例如最近已经写入(最新丢失的)二进制日志但尚未传递到备库的中继日志中的事务。你能够容忍吗?大多数应用能够容忍;因为替代方案大多非常昂贵且复杂,或者有一些性能开销。例如,可以使用同步复制,或是将二进制日志放到一个通过DRBD进行复制的设备上,这样就算服务器完全失效也不用担心丢失数据。(但是整个数据中心也有可能会掉电。)

一个良好的应用架构通常可以降低可用性方面的需求,至少对部分系统而言是这样的,良好的架构也更容易做到高可用。将应用中重要和不重要的部分进行分离可以节约不少工作量和金钱,因为对于一个更小的系统改进可用性会更容易。可以通过计算“风险敞口(risk exposure)”,将失效概率与失效代价相乘来确认高优先级的风险。画一个简单的风险计算表,以概率、代价和风险敞口作为列,这样很容易找到需要优先处理的项目。

在前一章我们通过讨论如何避免导致糟糕的可扩展性的原因,来推出如何获得更好的可扩展性。这里也会使用相似的方法来讨论可用性,因为我们相信,理解可用性最好的方法就是研究它的反面——宕机时间。接下来的小节我们会讨论为什么会出现宕机。

12.2 导致宕机的原因 #

我们经常听到导致数据库宕机最主要的原因是编写的SQL查询性能很差,真的是这样吗?2009年我们决定分析我们客户的数据库所遇到的问题,以找出那些真正引起宕机的问题,以及如何避免这些问题(1)。结果证实了一些我们已有的猜想,但也否定了一些(错误的)认识,我们从中学到了很多。

我们首先对宕机事件按表现方式而非导致的原因进行分类。一般来说,“运行环境”是排名第一的宕机类别,大约35%的事件属于这一类。运行环境可以看作是支持数据库服务器运行的系统和资源集合,包括操作系统、硬盘以及网络等。性能问题紧随其后,也是约占35%;然后是复制,占20%;最后剩下的10%包含各种类型的数据丢失或损坏,以及其他问题。

我们对事件按类型进行分类后,确定了导致这些事件的原因。以下是一些需要注意的地方:

  • 在运行环境的问题中,最普遍的问题是磁盘空间耗尽。
  • 在性能问题中,最普遍的宕机原因确实是运行很糟糕的SQL,但也不一定都是这个原因,比如也有很多问题是由于服务器Bug或错误的行为导致的。
  • 糟糕的Schema和索引设计是第二大影响性能的问题。
  • 复制问题通常由于主备数据不一致导致。
  • 数据丢失问题通常由于DROP TABLE的误操作导致,并总是伴随着缺少可用备份的问题。

复制虽然常被人们用来改善可用时间,但却也可能导致宕机。这主要是由于不正确的使用导致的,即便如此,它也阐明了一个普遍的情况:许多高可用性策略可能会产生反作用,我们会在后面讨论这个话题。

现在我们已经知道了主要宕机类别,以及有什么需要注意,下面我们将专门介绍如何获得高可用性。

12.3 如何实现高可用性 #

可以通过同时进行以下两步来获得高可用性。首先,可以尝试避免导致宕机的原因来减少宕机时间。许多问题其实很容易避免,例如通过适当的配置、监控,以及规范或安全保障措施来避免人为错误。第二,尽量保证在发生宕机时能够快速恢复。最常见的策略是在系统中制造冗余,并且具备故障转移能力。这两个维度的高可用性可以通过两个相关的度量来确定:平均失效时间(MTBF)和平均恢复时间(MTTR)。一些组织会非常仔细地追踪这些度量值。

第二步——通过冗余快速恢复——很不幸,这里是最应该注意的地方,但预防措施的投资回报率会很高。接下来我们来探讨一些预防措施。

12.3.1 提升平均失效时间(MTBF) #

其实只要尽职尽责地做好一些应做的事情,就可以避免很多宕机。在分类整理宕机事件并追查导致宕机的根源时,我们还发现,很多宕机本来是有一些方法可以避免的。我们发现大部分宕机事件都可以通过全面的常识性系统管理办法来避免。以下是从我们的白皮书中摘录的指导性建议,在白皮书中有我们详细的分析结果。

  • 测试恢复工具和流程,包括从备份中恢复数据。
  • 遵从最小权限原则。
  • 保持系统干净、整洁。
  • 使用好的命名和组织约定来避免产生混乱,例如服务器是用于开发还是用于生产环境。
  • 谨慎安排升级数据库服务器。
  • 在升级前,使用诸如Percona Toolkit中的pt-upgrade之类的工具仔细检查系统。
  • 使用InnoDB并进行适当的配置,确保InnoDB是默认存储引擎。如果存储引擎被禁止,服务器就无法启动。
  • 确认基本的服务器配置是正确的。
  • 通过skip_name_resolve禁止DNS。
  • 除非能证明有效,否则禁用查询缓存。
  • 避免使用复杂的特性,例如复制过滤和触发器,除非确实需要。
  • 监控重要的组件和功能,特别是像磁盘空间和RAID卷状态这样的关键项目,但也要避免误报,只有当确实发生问题时才发送告警。
  • 尽量记录服务器的状态和性能指数,如果可能就尽量久地保存。
  • 定期检查复制完整性。
  • 将备库设置为只读,不要让复制自动启动。
  • 定期进行查询语句审查。
  • 归档并清理不需要的数据。
  • 为文件系统保留一些空间。在GNU/Linux中,可以使用-m选项来为文件系统本身保留空间。还可以在LVM卷组中留下一些空闲空间。或者,更简单的方法,仅仅创建一个巨大的空文件,在文件系统快满时,直接将其删除。(2)
  • 养成习惯,评估和管理系统的改变、状态以及性能信息。

我们发现对系统变更管理的缺失是所有导致宕机的事件中最普遍的原因。典型的错误包括粗心的升级导致升级失败并遭遇一些Bug,或是尚未测试就将Schema或查询语句的更改直接运行到线上,或者没有为一些失败的情况制定计划,例如达到了磁盘容量限制。另外一个导致问题的主要原因是缺少严格的评估,例如因为疏忽没有确认备份是否是可以恢复的。最后,可能没有正确地监控MySQL的相关信息。例如缓存命中率报警并不能说明出现问题,并且可能产生大量的误报,这会使监控系统被认为不太有用,于是一些人就会忽略报警。有时候监控系统失效了,甚至没人会注意到,直至你的老板质问你,“为什么Nagios没有告诉我们磁盘已经满了”。

12.3.2 降低平均恢复时间(MTTR) #

之前提到,可以通过减少恢复时间来获得高可用性。事实上,一些人走得更远,只专注于减少恢复时间的某个方面:通过在系统中建立冗余来避免系统完全失效,并避免单点失效问题。

在降低恢复时间上进行投资非常重要,一个能够提供冗余和故障转移能力的系统架构,则是降低恢复时间的关键环节。但实现高可用性不单单是一个技术问题,还有许多个人和组织的因素。组织和个人在避免宕机和从宕机事件中恢复的成熟度和能力层次各不相同。

团队成员是最重要的高可用性资产,所以为恢复制定一个好的流程非常重要。拥有熟练技能、应变能力、训练有素的雇员,以及处理紧急事件的详细文档和经过仔细测试的流程,对从宕机中恢复有巨大的作用。但也不能完全依赖工具和系统,因为它们并不能理解实际情况的细微差别,有时候它们的行为在一般情况下是正确的,但在某些场景下却会是个灾难!

对宕机事件进行评估有助于提升组织学习能力,可以帮助避免未来发生相似的错误,但是不要对“事后反思”或“事后的调查分析”期待太高。后见之明被严重曲解,并且一味想找到导致问题的唯一根源,这可能会影响你的判断力(3)。许多流行的方法,例如“五个为什么”,可能会被过度使用,导致一些人将他们的精力集中在找到唯一的替罪羊。很难去回顾我们解决的问题当时所处的状况,也很难理解真正的原因,因为原因通常是多方面的。因此,尽管事后反思可能是有用的,但也应该对结论有所保留。即使是我们给出的建议,也是基于长期研究导致宕机事件的原因以及如何预防它们所得,并且只是我们的观点而已。

这里我们要反复提醒:所有的宕机事件都是由多方面的失效联合在一起导致的。因此,可以通过利用合适的方法确保单点的安全来避免。整个链条必须要打断,而不仅仅是单个环节。例如,那些向我们求助恢复数据的人不仅遭受数据丢失(存储失效,DBA误操作等),同时还缺少一个可用的备份。

...

第11章可扩展的MySQL

第11章 可扩展的MySQL

本章将展示如何构建一个基于MySQL的应用,并且当规模变得越来越庞大时,还能保证快速、高效并且经济。

有些应用仅仅适用于一台或少数几台服务器,那么哪些可扩展性建议是和这些应用相关的呢?大多数人从不会维护超大规模的系统,并且通常也无法效仿在主流大公司所使用的策略。本章会涵盖这一系列的策略。我们已经建立或者协助建立了许多应用,包括从单台或少量服务器的应用到使用上千台服务器的应用。选择一个合适的策略能够大大地节约时间和金钱。

MySQL经常被批评很难进行扩展,有些情况下这种看法是正确的,但如果选择正确的架构并很好地实现,就能够非常好地扩展MySQL。但是扩展性并不是一个很好理解的主题,所以我们先来理清一些容易混淆的地方。

11.1 什么是可扩展性 #

人们常常把诸如“可扩展性”、“高可用性”以及“性能”等术语在一些非正式的场合用作同义词,但事实上它们是完全不同的。在第3章已经解释过,我们将性能定义为响应时间。我们也可以很精确地定义可扩展性,稍后将完整讨论。简要地说,可扩展性表明了当需要增加资源以执行更多工作时系统能够获得划算的等同提升(equal bang for the buck)的能力。缺乏扩展能力的系统在达到收益递减的转折点后,将无法进一步增长。

容量是一个和可扩展性相关的概念。系统容量表示在一定时间内能够完成的工作量(1),但容量必须是可以有效利用的。系统的最大吞吐量并不等同于容量。大多数基准测试能够衡量一个系统的最大吞吐量,但真实的系统一般不会使用到极限。如果达到最大吞吐量,则性能会下降,并且响应时间会变得不可接受地大且非常不稳定。我们将系统的真实容量定义为在保证可接受的性能的情况下能够达到的吞吐量。这就是为什么基准测试的结果通常不应该简化为一个单独的数字。

容量和可扩展性并不依赖于性能。以高速公路上的汽车来类比的话:

  • 性能是汽车的时速。
  • 容量是车道数乘以最大安全时速。
  • 可扩展性就是在不减慢交通的情况下,能增加更多车和车道的程度。

在这个类比中,可扩展性依赖于多个条件:换道设计得是否合理、路上有多少车抛锚或者发生事故,汽车行驶速度是否不同或者是否频繁变换车道——但一般来说和汽车的引擎是否强大无关。这并不是说性能不重要,性能确实重要,只是需要指出,即使系统性能不是很高也可以具备可扩展性。

从较高层次看,可扩展性就是能够通过增加资源来提升容量的能力。

即使MySQL架构是可扩展的,但应用本身也可能无法扩展,如果很难增加容量,不管原因是什么,应用都是不可扩展的。之前我们从吞吐量方面来定义容量,但同样也需要从较高的层次来看待容量问题。从有利的角度来看,容量可以简单地认为是处理负载的能力,从不同的角度来考虑负载很有帮助。

数据量

应用所能累积的数据量是可扩展性最普遍的挑战,特别是对于现在的许多互联网应用而言,这些应用从不删除任何数据。例如社交网站,通常从不会删除老的消息或评论。

用户量

即使每个用户只有少量的数据,但在累计到一定数量的用户后,数据量也会开始不成比例地增长且速度快过用户数增长。更多的用户意味着要处理更多的事务,并且事务数可能和用户数不成比例。最后,大量用户(以及更多的数据)也意味着更多复杂的查询,特别是查询跟用户关系相关时(用户间的关联数可以用N×(N−1)来计算,这里N表示用户数)。

用户活跃度

不是所有的用户活跃度都相同,并且用户活跃度也不总是不变的。如果用户突然变得活跃,例如由于增加了一个吸引人的新特性,那么负载可能会明显提升。用户活跃度不仅仅指页面浏览数,即使同样的页面浏览数,如果网站的某个需要执行大量工作的部分变得流行,也可能导致更多的工作。另外,某些用户也会比其他用户更活跃:他们可能比一般人有更多的朋友、消息和照片。

相关数据集的大小

如果用户间存在关系,应用可能需要在整个相关联用户群体上执行查询和计算,这比处理一个一个的用户和用户数据要复杂得多。社交网站经常会遇到由那些人气很旺的用户组或朋友很多的用户所带来的挑战(2)。

11.1.1 正式的可扩展性定义 #

有必要探讨一下可扩展性在数学上的定义了,这有助于在更高层次的概念上清晰地理解可扩展性。如果没有这样的基础,就可能无法理解或精确地表达可扩展性。不过不用担心,这里不会涉及高等数学,即使不是数学天才,也能够很直观地理解它。

关键是之前我们使用的短语:“划算的等同提升(equal bang for the buck)”。另一种说法是,可扩展性是当增加资源以处理负载和增加容量时系统能够获得的投资产出率(ROI)。假设有一个只有一台服务器的系统,并且能够测量它的最大容量,如图11-1所示。

图11-1:一个只有一台服务器的系统

假设现在我们增加一台服务器,系统的能力加倍,如图11-2所示。

图11-2:一个线性扩展的系统能由两台服务器获得两倍容量

这就是线性扩展。我们增加了一倍的服务器,结果增加了一倍的容量。大部分系统并不是线性扩展的,而是如图11-3所示的扩展方式。

图11-3:一个非线性扩展的系统

大部分系统都只能以比线性扩展略低的扩展系数进行扩展。越高的扩展系数会导致越大的线性偏差。事实上,多数系统最终会达到一个最大吞吐量临界点,超过这个点后增加投入反而会带来负回报——继续增加更多工作负载,实际上会降低系统的吞吐量。(3)

这怎么可能呢?这些年产生了许多可扩展性模型,它们有着不同程度的良好表现和实用性。我们这里所讲的可扩展性模型是基于某些能够影响系统扩展的内在机制。这就是Neil J. Gunther博士提出的通用可扩展性定律(Universal Scalability Law,USL)。Gunther博士将这些详尽地写到了他的书中,包括Guerrilla Capacity Planning (Springer)。这里我们不会深入到背后的数学理论中,如果你对此感兴趣,他撰写的书籍以及由他的公司Performance Dynamics提供的训练课程可能是比较好的资源。(4)

简而言之,USL说的是线性扩展的偏差可通过两个因素来建立模型:无法并发执行的一部分工作,以及需要交互的另外一部分工作。为第一个因素建模就有了著名的Amdahl定律,它会导致吞吐量趋于平缓。如果部分任务无法并行,那么不管你如何分而治之,该任务至少需要串行部分的时间。

增加第二个因素——内部节点间或者进程间的通信——到Amdahl定律就得出了USL。这种通信的代价取决于通信信道的数量,而信道的数量将按照系统内工作者数量的二次方增长。因此最终开销比带来的收益增长得更快,这是产生扩展性倒退的原因。图11-4阐明了目前讨论到的三个概念:线性扩展、Amdahl扩展,以及USL扩展。大多数真实系统看起来更像USL曲线。

图11-4:线性扩展、AmdahI扩展以及USL扩展定律

USL可以应用于硬件和软件领域。对于硬件,横轴表示硬件的数量,例如服务器数量或CPU数量。每个硬件的工作量、数据大小以及查询的复杂度必须保持为常量(5)。对于软件,横轴表示并发度,例如用户数或线程数。每个并发的工作量必须保持为常量。

有一点很重要,USL并不能完美地描述真实系统,它只是一个简化模型。但这是一个很好的框架,可用于理解为什么系统增长无法带来等同的收益。它也揭示了一个构建高可扩展性系统的重要原则:在系统内尽量避免串行化和交互。

可以衡量一个系统并使用回归来确定串行和交互的量。你可以将它作为容量规划和性能预测评估的最优上限值。也可以检查系统是怎么偏离USL模型的,将其作为最差下限值以指出系统的哪一部分没有表现出它应有的性能。这两种情况下,USL给出了一个讨论可扩展性的参考。如果没有USL,那即使盯着系统看也无法知道期望的结果是什么。如果想深入了解这个主题,最好去看一下对应的书籍。Gunther博士已经写得很清楚,因此我们不会再深入讨论下去。

另外一个理解可扩展性问题的框架是约束理论,它解释了如何通过减少依赖事件和统计变化(statistical variation)来改进系统的吞吐量和性能。这在Eliyahu M. Goldratt所撰写的The Goal(North River)一书中有描述,其中有一个关于管理制造业设备的延伸的比喻。尽管这看起来和数据库服务器没有什么关联,但其中包含的法则和排队理论以及其他运筹学方面是一样的。

...

第10章复制

第10章 复制

MySQL内建的复制功能是构建基于MySQL的大规模、高性能应用的基础,这类应用使用所谓的“水平扩展”的架构。我们可以通过为服务器配置一个或多个备库(1)的方式来进行数据同步。复制功能不仅有利于构建高性能的应用,同时也是高可用性、可扩展性、灾难恢复、备份以及数据仓库等工作的基础。事实上,可扩展性和高可用性通常是相关联的话题,我们会在接下来的三章详细阐述。

本章将阐述所有与复制相关的内容,首先简要介绍复制如何工作,然后讨论基本的复制服务搭建,包括与复制相关的配置以及如何管理和优化复制服务器。虽然本书的主题是高性能,但对于复制来说,我们同样需要关注其准确性和可靠性,因此我们也会讲述复制在什么情况下会失败,以及如何使其更好地工作。

10.1 复制概述 #

复制解决的基本问题是让一台服务器的数据与其他服务器保持同步。一台主库的数据可以同步到多台备库上,备库本身也可以被配置成另外一台服务器的主库。主库和备库之间可以有多种不同的组合方式。

MySQL支持两种复制方式:基于行的复制和基于语句的复制。基于语句的复制(也称为逻辑复制)早在MySQL 3.23版本中就存在,而基于行的复制方式在5.1版本中才被加进来。这两种方式都是通过在主库上记录二进制日志(2)、在备库重放日志的方式来实现异步的数据复制。这意味着,在同一时间点备库上的数据可能与主库存在不一致,并且无法保证主备之间的延迟。一些大的语句可能导致备库产生几秒、几分钟甚至几个小时的延迟。

MySQL复制大部分是向后兼容的,新版本的服务器可以作为老版本服务器的备库,但反过来,将老版本作为新版本服务器的备库通常是不可行的,因为它可能无法解析新版本所采用的新的特性或语法,另外所使用的二进制文件的格式也可能不相同。例如,不能从MySQL 5.1复制到MySQL 4.0。在进行大的版本升级前,例如从4.1升级到5.0,或从5.1升级到5.5,最好先对复制的设置进行测试。但对于小版本号升级,如从5.1.51升级到5.1.58,则通常是兼容的。通过阅读每次版本更新的ChangeLog可以找到不同版本间做了什么修改。

复制通常不会增加主库的开销,主要是启用二进制日志带来的开销,但出于备份或及时从崩溃中恢复的目的,这点开销也是必要的。除此之外,每个备库也会对主库增加一些负载(例如网络I/O开销),尤其当备库请求从主库读取旧的二进制日志文件时,可能会造成更高的I/O开销。另外锁竞争也可能阻碍事务的提交。最后,如果是从一个高吞吐量(例如5000或更高的TPS)的主库上复制到多个备库,唤醒多个复制线程发送事件的开销将会累加。

通过复制可以将读操作指向备库来获得更好的读扩展,但对于写操作,除非设计得当,否则并不适合通过复制来扩展写操作。在一主库多备库的架构中,写操作会被执行多次,这时候整个系统的性能取决于写入最慢的那部分。

当使用一主库多备库的架构时,可能会造成一些浪费,因为本质上它会复制大量不必要的重复数据。例如,对于一台主库和10台备库,会有11份数据拷贝,并且这11台服务器的缓存中存储了大部分相同的数据。这和在服务器上有11路RAID 1类似。这不是一种经济的硬件使用方式,但这种复制架构却很常见,本章我们将讨论解决这个问题的方法。

10.1.1 复制解决的问题 #

下面是复制比较常见的用途:

数据分布

MySQL复制通常不会对带宽造成很大的压力,但在5.1版本引入的基于行的复制会比传统的基于语句的复制模式的带宽压力更大。你可以随意地停止或开始复制,并在不同的地理位置来分布数据备份,例如不同的数据中心。即使在不稳定的网络环境下,远程复制也可以工作。但如果为了保持很低的复制延迟,最好有一个稳定的、低延迟连接。

负载均衡

通过MySQL复制可以将读操作分布到多个服务器上,实现对读密集型应用的优化,并且实现很方便,通过简单的代码修改就能实现基本的负载均衡。对于小规模的应用,可以简单地对机器名做硬编码或使用DNS轮询(将一个机器名指向多个IP地址)。当然也可以使用更复杂的方法,例如网络负载均衡这一类的标准负载均衡解决方案,能够很好地将负载分配到不同的MySQL服务器上。Linux虚拟服务器(Linux Virtual Server,LVS)也能够很好地工作,第11章将详细地讨论负载均衡。

备份

对于备份来说,复制是一项很有意义的技术补充,但复制既不是备份也不能够取代备份。

高可用性和故障切换

复制能够帮助应用程序避免MySQL单点失败,一个包含复制的设计良好的故障切换系统能够显著地缩短宕机时间,我们将在第12章讨论故障切换。

MySQL升级测试

这种做法比较普遍,使用一个更高版本的MySQL作为备库,保证在升级全部实例前,查询能够在备库按照预期执行。

10.1.2 复制如何工作 #

在详细介绍如何设置复制之前,让我们先看看MySQL实际上是如何复制数据的。总的来说,复制有三个步骤:

  1. 在主库上把数据更改记录到二进制日志(Binary Log)中(这些记录被称为二进制日志事件)。
  2. 备库将主库上的日志复制到自己的中继日志(Relay Log)中。
  3. 备库读取中继日志中的事件,将其重放到备库数据之上。

以上只是概述,实际上每一步都很复杂,图10-1更详细地描述了复制的细节。

图10-1:MySQL复制如何工作

第一步是在主库上记录二进制日志(稍后介绍如何设置)。在每次准备提交事务完成数据更新前,主库将数据更新的事件记录到二进制日志中。MySQL会按事务提交的顺序而非每条语句的执行顺序来记录二进制日志。在记录二进制日志后,主库会告诉存储引擎可以提交事务了。

下一步,备库将主库的二进制日志复制到其本地的中继日志中。首先,备库会启动一个工作线程,称为I/O线程,I/O线程跟主库建立一个普通的客户端连接,然后在主库上启动一个特殊的二进制转储(binlog dump)线程(该线程没有对应的SQL命令),这个二进制转储线程会读取主库上二进制日志中的事件。它不会对事件进行轮询。如果该线程追赶上了主库,它将进入睡眠状态,直到主库发送信号量通知其有新的事件产生时才会被唤醒,备库I/O线程会将接收到的事件记录到中继日志中。

MySQL 4.0之前的复制与之后的版本相比改变很大,例如MySQL最初的复制功能没有使用中继日志,所以复制只用到了两个线程,而不是现在的三个线程。目前大部分人都是使用的最新版本,因此在本章我们不会去讨论关于老版本复制的更多细节。

备库的SQL线程执行最后一步,该线程从中继日志中读取事件并在备库执行,从而实现备库数据的更新。当SQL线程追赶上I/O线程时,中继日志通常已经在系统缓存中,所以中继日志的开销很低。SQL线程执行的事件也可以通过配置选项来决定是否写入其自己的二进制日志中,它对于我们稍后提到的场景非常有用。

图10-1显示了在备库有两个运行的线程,在主库上也有一个运行的线程:和其他普通连接一样,由备库发起的连接,在主库上同样拥有一个线程。

这种复制架构实现了获取事件和重放事件的解耦,允许这两个过程异步进行。也就是说I/O线程能够独立于SQL线程之外工作。但这种架构也限制了复制的过程,其中最重要的一点是在主库上并发运行的查询在备库只能串行化执行,因为只有一个SQL线程来重放中继日志中的事件。后面我们将会看到,这是很多工作负载的性能瓶颈所在。虽然有一些针对该问题的解决方案,但大多数用户仍然受制于单线程。

10.2 配置复制 #

为MySQL服务器配置复制非常简单。但由于场景不同,基本的步骤还是有所差异。最基本的场景是新安装的主库和备库,总的来说分为以下几步:

  1. 在每台(3)服务器上创建复制账号。
  2. 配置主库和备库。
  3. 通知备库连接到主库并从主库复制数据。

这里我们假定大部分配置采用默认值即可,在主库和备库都是全新安装并且拥有同样的数据(默认MySQL数据库)时这样的假设是合理的。接下来我们将展示如何一步步配置复制:假设有服务器server1(IP地址192.168.0.1)和服务器server2(IP地址192.168.0.2),我们将解释如何给一个已经运行的服务器配置备库,并探讨推荐的复制配置。

10.2.1 创建复制账号 #

MySQL会赋予一些特殊的权限给复制线程。在备库运行的I/O线程会建立一个到主库的TCP/IP连接,这意味着必须在主库创建一个用户,并赋予其合适的权限。备库I/O线程以该用户名连接到主库并读取其二进制日志。通过如下语句创建用户账号:

...

附录-附表-后记

附录 #

西周金文“初吉”之研究 #

一、传统解说难于否定

西周行用朔望月历制,朔与望至关重要。朔称初吉、月吉,或称吉,又叫既死霸(取全是背光面之义,死霸指背光面),或叫朔月。这种种名称,反映了周人对月相的重视以及朔日在历制中的特殊地位。

传统的解说,初吉即朔。

《诗·小明》“正月初吉”,毛传:初吉,朔日也。

《国语·周语》“自今至于初吉”,韦昭注初吉:二月朔日也。

《周礼》“月吉则属民而读邦法”,郑注月吉:每月朔日也。

《论语》“吉月必朝服而朝”,孔曰:吉月,月朔也。

《诗·十月之交》“朔月辛卯”,唐石经作“朔日辛卯”。

《礼记·祭义》:“朔月月半,君巡牲。”

《礼记·玉藻》“朔月大牢”,陈澔《礼记集说》:朔月,月朔也。

日本竹添光鸿《毛诗会笺》云:古人朔日称朔月。《仪礼》《礼记》皆有朔月之文。《尚书》或称元日、上日而不曰朔日。即望亦但曰月几望或既望而不曰望日,故知经文定当以朔月为是也。凡月朔皆称朔月。《论语》亦以月吉为吉月。古人多倒语,犹《书》之“月正元日”乃正月元日也。

《周礼》“正月之吉”,郑注:吉谓朔日。

《周礼》“及四时之孟月吉日”,郑注:四孟之月朔日。

郑玄作为两汉经学之集大成者,对朔为吉日的认识是十分明确的,或称月吉,或称吉日,或称吉,都肯定了朔为吉日这一点。

朔即月初一,故称初吉,亦属自然,这与望为吉日亦相对应。朔望月历制,朔为吉日,望亦为吉日。《易·归妹》“月几望,吉”可证。

毛传释初吉为朔日,韦昭注《国语》“初吉”为朔日,反映古人对“初吉”的正确认识。

尤其当注意的是,初吉为朔的解说,两千年来没有任何一位严肃的学者持有异议。

我们没有理由不尊重文献。应当说,传统对于初吉的解说是难于否定的,是不容否定的。

二、朔望月历制

西周是明白无误的朔望月历制,绝对不是什么“朏为月首”。

我们从载籍文字中可以找到若干证据:

《周礼·大史》“掌建邦之六典,以逆邦国之治。……正岁年以序事,颁之于官府及都鄙。(郑注:中数曰岁,朔数曰年。中朔大小不齐,正之以闰若今时历日矣。定四时,以次序授民时之事。)颁告朔于邦国。(郑注:天子班朔于诸侯,诸侯藏之于祖庙。至朔,朝于庙,告而受行之。郑司农云,以十二月朔布告天下诸侯。)”

这里的告朔之制,当然也包括西周一代。依郑玄说,岁指回归年长度(阳历),年指十二个朔望月长度(阴历),两者不一致,添加闰月来协调,这就是周代的阴阳合历体制。

西周一代,“保章氏掌天星以志星辰日月之变动”,强调天象的观察与记录;“冯相氏掌十有二岁,十有二月,十有二辰”(《周礼》),侧重在历术的推求。

《礼记·玉藻》:“天子听朔于南门之外。闰月则阖门左扉,立于其中。”陈澔《集说》引“方氏曰:天子听朔于南门,示受之于天。诸侯听朔于太庙,示受之于祖。原其所自也”。

历术是皇权的象征,掌握在周天子手中,天子于南门从冯相氏得每年十二个月朔的安排,然后颁朔于诸侯,诸侯藏之祖庙。至朔,朝于庙(即“听朔于太庙”),告而受行之。历术推求的依据是天象,所以“示受之于天”,“原其所自也”。

《逸周书·史记解》“朔望以闻”,是记周穆王时事。朔望月历制是明明白白的。

《礼记·祭义》“朔月月半,君巡牲”,这当然是说,初一与十五,人君巡视之。这难道不是朔望月的明证?

《吕氏春秋》保存了先秦的若干旧说,上至三皇五帝,史料价值不可忽视。《贵因》载:“夫审天者,察列星而知四时,因也。推历者视月行而知晦朔,因也。”

视月行,就是月相的观察。干什么?确定晦朔而已。很明白,观察月相就是为了确定一年十二个月朔的干支,以“颁告朔于邦国”。

《逸周书·宝典解》“维王三祀二月丙辰朔”,历日清清楚楚。过去说此篇是记武王的。事实上,历日唯合成王亲政三年,《宝典解》反映了西周初期朔望月历制。《逸周书》成书于西周以后,而这个历日当是前朝的实录,绝不是后人的伪造或推加。这是“朏为月首”说无法作出解释的。

《汉书·世经》云:“古文《月采》篇曰‘三日曰朏’。”师古注:《月采》,说月之光采,其书则亡。——这也许是记录月相的专著,可惜我们已不能见到了。刘歆是见过的,他持定点说当有充分依据。《月采》明确朏是初三。“朏为月首”是没有依据的。

大量出土的西周器物证实,西周历制是朔望月而不是“朏为月首”。

《作册令方彝》:隹八月辰在甲申……丁亥……;隹十月月吉癸未……甲申……乙酉……”“辰在××”是周人表达朔日的一种固定格式,出土器物已有二十余例,校比天象无一不是朔日。推比历朔知:八月甲申朔,初四丁亥;九月甲寅朔(或癸丑朔);十月癸未朔,甲申初二,乙酉初三。“月吉癸未”即朔日癸未,与文献记载亦相吻合。《令方彝》的八月、十月,中间无闰月可插,一个月就只有一个朔日即一个月吉,这怎么能“说明西周时代每个月都可能有若干个吉日”呢?

西周金文记载初吉尤多,初吉即朔,也只能证明西周是朔望月制而不是“朏为月首”。

常识告诉我们,历术是关于年月日的协调。日因于太阳出没,白昼黑夜,是计时的基本单位;年以太阳的回归年长度为依据,表现为寒来暑往,草木荣枯,《尧典》“期三百有六旬有六日,以闰月定四时成岁”;而月亮的隐现圆缺,只能靠肉眼观察。西周制历,尚未找到年月日的调配规律,只能随时观察随时置闰,一年十二个月朔的确定也靠“观月行”。这就是西周人频频记录月相的缘由。

日与年易于感知,观象授时的主要内容是观察月相,两望之间必朔,两朔之间必望,朔望月也是不难掌握的。何况司历专职,勤劬观察,不会将初一说成初二,更不会说成初三。肉眼观察的失朔限度也只在半日之内。

董作宾先生以为,知道日食就会知道朔,知道月食就会知道望。朔望月历制当追溯到殷商。

持“朏为月首”说者以为,“朔”字在西周后期才出现,猜想西周前期当是“朏为月首”。殊不知,殷商后期以来,朔望的概念十分明确,表达朔日的词语甚多,初吉为朔,既死霸为朔,月吉(吉月)为朔,“辰在××”为朔,并非一定要用“朔”字不可。

西周一代,未找到协调年月日的规律,月相的观察就显得特别重要,文献以及出土器物有关月相的记载也就特别的多。到了春秋中期以后,十九年七闰已很明确,连大月设置也逐渐有了规律,朔日的推演已不为难事。所以,鲁文公“四不视朔”,“子贡欲去告朔之饩羊”,不仅证实西周以来的告朔礼制已经走向衰败没落,还反映出四分术的推演已为司历者大体掌握。历术已由观象授时上升到推步制历,已从室外观月步入室内推算。这样,月相的观察与记录自然就不那么重要了。这就是春秋以后,作为月相的“既死霸”“既生霸”“既望”在金文中基本消失的原因。

三、初吉即朔

西周金文大量使用“初吉”,凡可考知的,无一不是朔日。

有的器铭,年、月、月相、日干支俱全,校比天象,十分方便。利用张培瑜先生《中国先秦史历表》,便可一目了然。

例1,攸从鼎:隹卅又一年三月初吉壬辰。(郭沫若:《两周金文辞大系图录考释》,下简称《大系录》,118)

校比公元前848年厉王三十一年天象,丑正,三月壬辰朔。

例2,无其簋:隹十又三年正月初吉壬寅。(《大系录》107)

校比公元前829年共和十三年天象,丑正,正月壬寅朔。

例3,虢季子白盘:隹王十有二年,正月初吉丁亥。(《大系录》88)

校比公元前816年宣王十二年天象,子正,正月丁亥朔(定朔戊子03h49m,合朔在后半夜,失朔不到四小时)。

例4,叔尃父:隹王元年六月初吉丁亥。(《考古》65.9)

校比公元前770年平王元年天象,丑正六月丁亥朔(定朔戊子02h01m,失朔仅两小时)。

厉王以前的若干铜器,因王年尚无共识的结论,仅举几例说明。

例5,谏簋:隹五年三月初吉庚寅。(《大系录》101)

校比公元前889年夷王五年天象,丑正,三月庚寅朔。

例6,王臣簋:隹二年三月初吉庚寅。(《文物》80.5)

校比公元前915年懿王二年天象,丑正,三月庚寅朔。

例7,柞钟:隹王三年四月初吉甲寅。(《文物》61.7)

校比公元前914年懿王三年天象,丑正,四月甲寅朔。此器与王臣簋历日前后连贯,丝毫不乱,列为同一王世之器,更可证初吉即朔。

总之,初吉即朔,这是金文历日明确记载的,绝不是泛指某月中的任何一日。

四、关于静簋

刘雨先生在《再论金文“初吉”》(《中国文物报》,1997-04-20)中把静簋历日作为立论的主要依据,以此否定初吉为朔,这就有必要重点讨论了。

刘先生说:西周金文中……只有静簋记有两个“初吉”,而且相距不到三个月,没有历律和年代等未知因素干扰,是西周金文中最能说明“初吉”性质的珍贵资料。——这就是他为什么特别重视静簋的原因。

过去我将静簋视为厉王三十五年器,“六月初吉丁卯”合公元前844年天象,“八月初吉庚寅”合公元前843年天象,两个初吉间隔一年,与何幼琦先生的认识暗合。刘雨先生此文给我以启发,两初吉确实当为一年之内的两初吉,不必间隔一年。不过,两初吉的解说都当指朔日,而不是泛指某月中任何一日。

排比静簋历朔知:六月丁卯朔,七月当丙申朔(或丁酉朔),八月丙寅朔。

...

第6讲-第7讲

第六讲四分历的应用 #

四分历法是观象授时高度发展的产物,古人制定四分历法就是为了取代观象授时,服务于人类社会的生产和生活,这是毫无疑义的。因此,年代学的基础课题就是掌握四分历法,用它来推算上古历点,为解决有关的学术问题服务。特别是近代,出土文物越来越多,古史古事的考订,都需要我们确定其年代及月日。我们依据四分历法仍可以求得密近的实际天象,解决其中的疑难。这正是文史工作者学习古天文历法的目的之一。

一、应用四分历的原则 #

明确了殷历甲寅元(即《历术甲子篇》)创制于公元前427年,就可以将四分历在实际考证中普遍应用,推算古代典籍及出土的地下器物所载的历点,并在推算中验证殷历甲寅元的正确性。

四分历是战国初期创制并行用,大体到三国时期的蜀汉废止。如果将四分历广泛应用,必须明确几个问题。

第一,殷历甲寅元一经创制行用,就成为中华民族的共同财富,通行于当时各国。战国纷争,诸侯力征,不统于王,各国用历也标新立异,所以后人总认为“战国时代各国历法不同”。这只看到了问题的表象。四分历于战国初期行用,这一法则在当时就是不可改变的了。各国用历虽花样繁多,名号各殊,或岁首不同,或建正有异,都只能在四分历法则内改头换面,实质不变也变不了。我们用四分历推算有关历点,是掌握了一个普遍的原则,所得结果自然不会有误。

战国时代,各国是否一致行用四分历法呢?

不难明白,历法不是产生于某国某君某人之手,而是历代星历家血汗的结晶。可能经过某些君王(比如魏文侯)的提倡归功于某些星历家(比如楚人甘德、魏人石申)的勤劬。但历法一旦创制就不可能为某国某君所垄断,必然普施于华夏人民足迹之所至。谁会舍先进的历法不用而去吃观象授时的苦头?且战国初期,朝秦暮楚的士大夫比比皆是,历法一经行用自然不受国界的约束。因此四分历必能普施于战国时期各诸侯国。

再说,经商周至战国初年,干支纪年已千百年不紊,各国都使用一个共同的干支日历,月球的朔望又人人可见,日与月的一致自不待言。有这样一个共同的月历、日历作为基础,历法普施于战国才有可能。

从现有文献资料看,《孟子》所记时令与《楚辞》所记,仅只是岁首不同而已。据《孟子》载:“七八月之间雨集,沟浍皆盈”(《孟子·离娄下》);又“七八月之间旱则苗槁矣,天油然作云沛然下雨,则苗浡然兴之矣”(《孟子·梁惠王上》)。讲的是下暴雨。我国山东一带下暴雨的时间,当是夏历五、六月。因《孟子》一书的用历是取建子为正,所以与建寅为正的夏历有两月之差,究其实则是指同一天象,《孟子》用的也是四分历。

据《楚辞·怀沙》载:“滔滔孟夏兮,草木莽莽。”孟夏即四月,草木繁茂,与建寅为正的夏历合。又《楚辞·抽思》:“望孟夏之短夜兮,何晦明之若岁。”讲初夏昼长夜短明显起来,正合夏历。

秦用四分历,从《史记·秦本纪》中也有反映:“(昭襄王)四十八年十月韩献垣雍。……正月兵罢复守上党,其十月五大夫陵攻赵邯郸。又四十九年正月益发卒佐陵。陵战不善,免,王龁代将,其十月将军张唐攻魏。”此两处,先记秦十月、正月,再记“其十月”(它的十月)。因为兵入赵魏之地,故用赵魏之月序记。足证秦与赵魏同用四分历,只不过秦以十月为岁首,三晋用夏正罢了。

燕国僻远,用历无考,以理推之,密近三晋。一句话,《历术甲子篇》通用于七国,战国时代实际全用四分历。

由于齐鲁建子为正,秦历又建亥为首,与楚、晋各异,似乎战国有多种历法了,这便给“三正论”者以生事的机会,造成后世的惑乱。

战国用历原本四分术,然而为什么名目如此繁多呢?

首先,列强出于政治斗争的需要,在用历上往往变换一些手法,以示与周王朝分庭抗礼,尽管都用四分历却有意标新立异,独树一帜。

其次,自封为王,欲兼天下,必然要利用“君权神授”的观念,这就是历志上“改正朔,易服色”的记载,用以表明“受命于天”,从而威天下而揽民心。

再次,托古作伪以自重,也是列强君王惯用的手法。四分历创制之初,就曾伪称“成汤用事十三年”把创立之功归于前代圣王。秦历托名“颛顼”,也同样出于托古自重。战国时代所谓“周历”“夏历”,莫不如此。汉代有“古六历”之说(黄帝历、颛顼历、夏历、殷历、周历、鲁历),那虽是后人的附会,实际也可见托古作伪的痕迹。

战国用历从表现形式看,或建正不同(齐鲁建子为正,秦楚三晋建寅为正),或岁首不同(齐以子月为岁首,楚三晋以寅月为岁首,秦以十月为岁首),或历名不同(秦称颛顼历,以别于殷历),如此而已。而其所宗之“法”,也都为四分术。在当时的条件下四分历的周密与完整是无法取代的。

这种种名目,却给“三正论”制造者以可乘之机。按照“三正论”者对“周正建子、殷正建丑、夏正建寅”的解释,夏、商、周三代使用了不同的历法,即夏代之历以寅月为正,殷代之历以丑月为正,周朝之历以子月为正。夏商周三朝迭相替代,故“改正朔”以示“受命于天”。秦王迷于“三正论”,继周之后以十月为岁首,也有绍续前朝,秉天所命之意。实际上,四分历产生之前,还只是观象授时,根本不存在完整的行用于夏时之夏历,行用于殷商时代之殷历,行用于西周之周历,所谓夏历、殷历、周历,纯然是后人的概念。

懂得了战国用历的实质,排除“三正论”的干扰,就可以运用四分历进行具体历点的推算。

第二,四分历取岁实36514日,与实际回归年长度必有误差,307年盈一日。如果将一日化为940分,940÷307=3.06(分/年),即每年有3.06分的误差。这样,以公元前427年四分历行用之时为基点,在它以后的年份每年有+3.06分的误差,在它以前的年份,每年有-3.06分的误差。因此,在推算实际天象时,公元前427年之前的年份,每年要加3.06分;公元前427年之后的年份,每年要减3.06分。这就是前加后减的原则。只有这样,才能得出密近的实际天象。3.06分就是推求实际天象的改正值。

在四分历行用的年代,由于时人不了解这个误差,自然不可能将误差计算进去。所以,典籍中总有历法与天象不符的记载,汉初“日食在晦”的文字就属此类。我们在考究战国至汉末这段时期的历点时,除了顾及朝代交接和改历等重大问题外,应用四分历进行推算时,不必使用“前加后减”的原则。因为追求实际天象除了验证朔望,反而与实际用历相违。实际用历还不知道这个3.06分。

第三,公元前427年之前的年份,仍可用四分历推算月日。公元前427年之前,未行用四分历法,还是观象授时阶段。但月相在天,有目共睹,干支纪日从殷商时代已延续不断,人皆遵用。这就构成了历法推算的基础。前代学者依据《春秋》所载月日干支,编制出春秋时代的历谱。张汝舟先生《西周经朔谱》《春秋经朔谱》就立足于殷历的朔闰,取密近的实际天象,将古代文献所记这两个时期的年、月、日一一归队入谱,贯穿解说,对前人之误见逐次加以澄清。因此,“两谱”既是对两周文献纪日的研究成果,也是广大文史工作者研究两周文史的极好工具。

要之,编定历谱或考释历点,都得以《历术甲子篇》为依据,将四分历普遍地应用于文史研究工作中。

二、失闰与失朔 #

年、月、日能够有规律地进行调配的真正历法(四分历)产生于战国初期,有历法之前都还是观象授时。观象授时就是制历。制历的主要内容就是告朔和置闰两件大事。告朔是定每月朔日的干支,朔日干支一经确定,其余日序自有干支。置闰是定节气,一年之气,冬至最要紧。冬至一经确定,闰与不闰及全年月序就自然清楚。

在观象授时阶段,告朔就全凭月相。古人凭月相告朔,承大月二日朏,月牙初见,承小月三日朏,月牙初见(见《说文》)。同理,承大月十五日望,月满圆,承小月十六日望,月满圆。月相分明,只在一天。

在观象授时阶段,置闰须观斗柄所指方位,观二十八宿中天位置,验之气象、物象,加以土圭测影。随着长年的经验积累,观测仪器的精当,测定气节的准确程度必然逐有提高。前已述及,到春秋中期,十九年七闰的规律就已完全掌握了。

四分历的回归年长度定为36514日,且使用平朔、平气,所以失闰,特别是失朔还不能完全避免。更何况春秋、西周还处在观象授时的时代,失闰与失朔当是屡见不鲜的。比如,实际是乙丑朔,因为分数小,司历定为甲子朔。如果乙丑分数大,司历定为丙寅朔。这叫失朔。

失闰,说得确切些,就是失气。实际是子月初冬至,司历错到亥月末,亥月就成了岁首(建亥)。冬至若在下旬,司历错到丑月,丑月就成了岁首(建丑)。失闰由失气而起,我们还叫失闰。

失朔,失闰,《春秋》有宝贵资料。例如,昭公十五年经朔:

子月大,己未623分合朔

丑月小,己丑182分合朔

寅月大,戊午681分合朔

卯月大,戊子240分合朔

辰月大,丁巳740分合朔

……

《春秋》载:“二月癸酉,有事于武宫。”“六月丁巳朔,日有食之。”以此二条验谱,己未朔,癸酉乃十五日,子月实《春秋》所书“二月”。“六月丁巳朔”正合辰月。这一年必是建亥为正,子月顺次定为“二月”,辰月顺次定为“六月”,全合。大量材料证实,春秋后期建子为正,现在正月到了亥月,这就是失闰之铁证。

将一部《春秋》进行研究,可以发现:

隐、桓、庄、闵共63年49年建丑,8年建寅,6年建子;

僖、文、宣、成共87年58年建子,16年建丑,13年建亥。

这说明,前四公,即春秋前期,建丑为正,建子、建寅都算失闰,而没有建亥的。后四公,即春秋后期,建子为正,建亥、建丑都算失闰,而没有建寅的。这又说明,失闰不会超过一个月。按平气计算,一般失闰都在半月之内,只有周幽王六年失闰十七天(据《诗经·十月之交》所给历点推算)。

《春秋》记37次日食,有5个书月日不书朔。《左传》认为“史失之”,未免武断。因为食不在朔,所以《公羊传》云“或失之前,或失之后”,是正确的。失朔一般在半天之内,只有鲁文公元年“二月癸亥,日有食之”,失朔508分,超过半天(一日940分)。

为什么要掌握一个失闰限、失朔限呢?这是应用四分历推演经朔考订古籍古器历点必须遵循的准则。如果历点与实际天象所确定的朔、闰相差甚远,失闰超过一月,失朔超过一天,就宁可存疑也断不可硬套,去企求得出一个相合的结论。如果没有一个失闰、失朔限,古器物上的历点就可左右逢源,安在哪一年都会大致相符。记有历点的出土文物,一到专家的手里,考证出的结论往往大相径庭,其道理就在这里。可见,确定失闰限、失朔限是多么重要。它提醒你,要严谨,不可信口雌黄。

有没有“再失闰”的情况?古籍中确有记载。《汉书·律历志》载,襄公二十七年“九月乙亥朔,是建申之月也。鲁史书:‘十二月乙亥朔,日有食之。’传曰:‘冬十一月乙亥朔,日有食之,於是辰在申,司历过也,再失闰矣。’言时实行以为十一月也,不察其建,不考之于天也”。

《春秋》经文杜注:“今长历推为十一月朔,非十二月。传曰辰在申,再失闰。若是十二月,则为三失闰,故知经误。”

《左传》杜注:“谓斗建指申,周十一月今之九月,斗当建戌而在申,故知再失闰也。文十一年三月甲子至今七十一岁应有二十六闰,今长历推得二十四闰,通计少再闰。释例言之详矣。”

杜预这两条注,将《春秋》经传所记,辨析明白,断定经误传是。传文“再失闰”是可信的。杜以自编《经传长历》验证,确为“再失闰”。《汉书·律历志》解释说,当时是记为十一月的,这种“再失闰”是不观察斗柄所指,不考之于天象的原因。可见,观象授时阶段失闰是不足为怪的,但已不可能在春秋时代出现“再失闰”的怪现象。

如果用《历术甲子篇》推演,襄公二十七年(公元前546年)朔闰如次。

是年入辛卯蔀(蔀余27)第三十四年。

太初三十四年:前大余四十八,小余五百五十二先天+364分

子月朔己卯552分916己卯十五

丑月朔己酉111分475己酉 四十五

寅月朔戊寅610分34 己卯 十五

卯月朔戊申169分533戊申 四十四

辰月朔丁丑668分92 戊寅 十四

巳月朔丁未227分591丁未 四十三

...

第4讲-第5讲

第四讲二十四节气 #

古代劳动人民在认识自然、改造自然的过程中,创造了先进的耕作制度,形成了精耕细作的优良传统,推动了农业生产不断发展。在漫长的岁月中,对与农业生产紧密相关的农业气象条件,进行过精细的观察、深入的研究,逐步形成了二十四节气,概括了黄河中下游地区农业气候特征。它利用简要的两个字,把这一地区的日地关系、气候特点以及相应的农事活动恰当地表达出来。可以说,二十四节气是古代天文、气候和农业生产实践最成功的结合,从古到今都起着一种简明而又切合农业生产需要的农事历的作用。

二十四节气一旦形成,劳动人民就因时、因地加以发展,它的应用就不仅仅局限于黄河中下游地区了,而是逐步推广到全国各地,几乎渗透到我们这个农业大国的各个领域,甚至涉及人们的衣食住行。所以,对依据古代天文而形成的这样一部农事历——二十四节气进行一番研究,就是很有必要的了。

一、先民定时令 #

有了年、月、日的时间概念,并不等于就能得心应手地安排好时令。汉枚乘诗:“野人无历日,鸟啼知四时。”讲的是当时的“野人”,亦可想见先民的时令观念。《后汉书·乌桓鲜卑传》云“见鸟兽孳乳,以别四节”,道理亦同。《魏书》卷一百一讲到宕昌羌族“俗无文字,但候草木荣枯,记其岁时”。宋代洪皓《松漠纪闻》亦云:“女真……其民皆不知记年,问之则曰我见草青几度矣。盖以草青为一岁也。”据此推知,先民的时令,最早主要是靠物象——动植物的表象来确定的。

《山海经》记载了先民观察太阳升落位置以定季节的材料。《大荒东经》上记有六座日出之山:

东海之外,大荒之中,有山名曰大言,日月所出。

大荒之中,有山名曰合虚,日月所出。

大荒之中,有山名曰明星,日月所出。

大荒之中,有山名曰鞠陵,于天东极离瞀,日月所出。

大荒之中,有山名曰猗天苏门,日月所出。

大荒之中,有山名曰壑明俊疾,日月所出。

《大荒西经》上记有六座日入之山:

西海之外,大荒之中,有方山者,上有青树,名曰柜格之松,日月所出入也。

大荒之中,有山名曰丰沮玉门,日月所入。

大荒之中,有龙山,日月所入。

大荒之中,有山名曰日月山,天枢也。吴姖天门,日月所入。

大荒之中,有山名曰鏖鏊钜,日月所入者。

大荒之中,有山名曰常阳之山,日月所入。

大荒之中,有山名曰大荒之山,日月所入。

这是在不同季节、不同月份,观察到的太阳出山入山的不同位置。这种观察方法同观察鸟啼、鸟兽孳乳、草木荣枯的方法一样,是凭着经验,凭着目睹耳闻的感受,其粗疏是自不待言的。因为观察者的地域毕竟狭小,局限性很大,以此定季节势必误差很大。

观察太阳运行的另一种方法是观察日影长度的变化。最早当是利用自然的影长,进一步发展就是人为的立竿测影。

太阳视运动的轨迹无法在天空中标示,反映到地面上就是事物的投影。高山、土阜、树木、房舍,晴日白昼都会留下或长或短的影子。《吕氏春秋》“审堂下之阴,而知日月之行,阴阳之变”,就是这个意思。根据这些影子的长短可以判明时间的早晚,有经验的老人往往判断得十分精确,这无疑是依靠长期的经验积累。

如果要有意测影以确定时令,这得人为地在平地上立一根规定长度的竿子,把它的影子在地面上标示出来。这根竿子就是“表”,《周髀算经》中称之为“髀”。“表”的影子,古字写作“景”。这就是土圭测景。

从出土的甲骨文中考察殷商文化,可以明白地看到,殷商时代测定方向、时刻都已比较准确。卜辞中将一天的时刻分为:明(旦)、大采、大食、中日、昃、小食、小采、暮等时间段落。甲骨文中的“昃”字,就是人侧影的象形。作为时段,日侧之时为昃。发掘出的殷代宫殿基址是南北方向的,其方向所指与今天的指南针方向无异。这种方向的确定及中日、昃等时刻的测定,显然和观测日影紧密相关。

这都说明,殷商时代已有了早期的圭表。实践证明,通过长期测日影的实践就会认识到冬至、夏至、春分、秋分。甲骨卜辞中,有一些文字很可能就是至日的记录。

有了圭表,就能够比较准确地确定分、至,就可以对闰月的设置(闰在岁末)加以规律化的安排。所以,推知殷商之历应该比较规整,岁首应该比较固定,误差不会大于一个月。有人统计了记有月名的“今何月雨”“田”,其他农事季节及其他天文气象卜辞,证明了殷代月名和季节基本上已有了固定关系。《尧典》“期三百有六旬有六日,以闰月定四时成岁”的记载,大体符合这个时代的情况。

二、土圭测景 #

日影的长短与寒暑变化有关,这是先民积累的生活常识。要准确地测量寒来暑往的季节变化,很自然地就产生了立竿测影的方法。这是用最简易的天文仪器来研究历法、确定时令,是天文学发展的一次飞跃。

立竿测影又称土圭测景、圭表测景。表是直立的竿子,圭是平放在地上的玉版。《说文》云:“圭,瑞玉也。上圆下方。”日影长短就从平放的圭上显示出来。土,度也,测量的意思。土圭,就是度圭,测量圭上日影的长短以定时令。远在周代,“表”就规定为八尺,已有了长度标准。《周礼·考工记》云:“土圭尺有五寸,以致日,以土地。”致是推算义,土是量度义。土圭长一尺五,来推算节气日期,量度土地远近。《周礼·夏官司马》云:“土方氏,掌土圭之法以致日景。以土地相宅而建邦国都鄙。”注曰:土方氏,主四方邦国之土地。可见,周代已有人家来掌管土圭测景了。

《周礼·地官大司徒》云:“日至之影,尺有五寸。”这是说,夏至时,圭上影子有一尺五寸长。这样看来,圭长一尺五寸就远远不够了。《周礼·春官冯相氏》郑玄注云:“冬至,日在牵牛,景丈三尺;夏至,日在东井,景尺五寸。此长短之极,极则气至。冬无潜阳,夏无伏阴。春分,日在娄;秋分,日在角;而月弦于牵牛东井,亦以其景知气至不。春秋冬夏气皆至,则是四时之叙正矣。”圭有多长?当在一丈三尺以上。

根据《史记》记载,圭表测景当更早在传说中的黄帝时代。《史记·历书》“索隐”说:“黄帝使羲和占日,常仪占月,臾区占星气,伶纶造律品,大挠造甲子,隶首作算数,容成综此六术而著调历也。”不仅有专门测定日影的专家,并在测量日、月、星有关数据的基础上,利用甲子推算,创制时历。《尚书·尧典》“期三百有六旬有六日,以闰月定四时成岁”,可看作是远古时代测量日、月、星而后制历的发展。这就是以岁实366日为基本数据的我国有文字记载的最早的阴阳历。

制历调历是一件神圣的工作,《尧典》说“允厘百工,庶绩咸熙”,起到一个信治百官、兴起众功的作用。正因为这样,圭表测景就不可能是民间百姓的事,只能在天子或君王旨意下由专职官员负责进行。周代的测景遗址——周公测景台还保留在今天河南登封告成镇(古称阳城)这个地方。

阳城地处中原,物产丰富,文化发达。周公想迁都中原,视阳城为“地中”,居天下九州中心的意思。《周礼·地官大司徒》云:“以土圭之法测土深,正日景,以求地中。日南则景短,多暑。日北则景长,多寒。日东则景夕,多风。日西则景朝,多阴。日至之景,尺有五寸,谓之地中。天地之所和也,四时之所交也,风雨之所会也,阴阳之所合也。然则百物阜安,乃建王国焉。”如此详细地叙述求地中的方法,“地中”地理位置如此重要,占尽地理之便。这就是周公为迁都造下的舆论。实际上,所谓地中,是指当时国土南北的中心线而已。

告成镇的周公测景台,有一个高耸的测量台,相当于一个坚固的“表”,平铺于地面的是“量天尺”,也就是一个放大了的石“圭”。现今遗留的测景台,元代初建,明代重修。重修的测景台是正南正北走向,高出圭面8.5米,下面的圭长30.3米。

从周公在这里主持测景后,历代都在这里进行过测量,至今还有公元724年唐代所立的石“表”,上面刻有“周公测景台”五字。

三、冬至点的测定 #

我国古代以冬至作为一个天文年度的起算点,冬至的时刻确定得准不准,关系着全年节气的预报。古代天文学家的一项重要任务就是测定准确的冬至时刻。测出两次冬至时刻,就能得到一年的时间长度。这样定出的年,就是回归年,古代称为“岁实”。《后汉书·律历志》说:“日发其端,周而为岁,然其景不复。四周,千四百六十一日而景复初,是则日行之终。以周除日,得三百六十五四分日之一,为岁之日数。”四分历的岁实36514日就是这样测出来的,这是利用冬至日正午日影长度四年之后变化一周这一实测得出的数据。这样的数据,四年之后误差积累才有0.0312日,即不到45分钟。这已是测得很精确的了。可以认为,过四年后,冬至日正午影长大体复回到最初的长度。

下面介绍祖冲之测刘宋武帝(刘骏)大明五年(公元461年)十一月冬至时刻的方法。文载《宋书·历志》。

十月十日影一丈七寸七分半

十月十日影长10.7750尺

十一月二十五日一丈八寸一分太

十一月二十五日影长10.8175尺

二十六日一丈七寸五分强

二十六日影长10.7508尺

折取其中,则中天冬至

冬至应在十月十日与十一月二十五日之间

应在十一月三日

正中那一天,即十一月三日

求其早晚

求冬至时刻在早晚什么时候

令后二日影相减,则一日差率也

一日差率=10.8175-10.7508=0.0667

倍之为法

法=0.0667×2=0.1334

前二日减,以百刻乘之为实

实=(10.8175-10.7750)×100刻=4.25刻

以法除实,得冬至加时,在夜半后三十一刻

冬至时刻=实÷法=4.25÷0.1334=31.86

因为十月十日和十一月二十五日正午之间的中点是在十一月三日的子夜,冬至时刻从子夜起算。又,古历计算中通常不进位,故31.86刻记为31刻。又,“太”即34;“强”即112。

不难看出,在只有圭表测影的时代,祖冲之测定冬至时刻的方法确实是大大进步了。

前已提到,冬至点是指冬至时太阳在恒星间的位置,现代天文学是以赤经、赤纬来表示,我国古代是以距离二十八宿距星的赤经差(称入宿度)来表示。四分历明确记载,冬至点在牵牛初度。冬至点这个数据如何测定,没有留下任何文字记录。《左传》上有两次“日南至”的记载:一是僖公五年“春王正月辛亥朔,日南至”;一是昭公二十年“春王二月己丑,日南至”。说明鲁僖公时代有过日南至的观测,可是没有留下如何观测的记录。唐代僧一行(张遂)在《大衍历议·日度议》提到,古代测定太阳位置的方法是测定昏旦时刻的中星,由此可以推算出夜半时刻中星的位置,在它相对的地方就是夜半时刻太阳的位置。这是间接推求冬至点的方法。《大衍历议》也提到,后来采用直接测量夜半时刻中星的办法。这就要求漏刻(计时工具)有比较稳定的精确度。利用太阳日行一度的规律,求出某日夜半时刻太阳在星空间的位置,就不难求得冬至时刻太阳所在位置,即冬至点的位置。

...

第1讲-第3讲

第一讲为什么要了解古天文历法 #

我国是世界上文明古国之一,先民出于农事需要,积累了丰富的天文学知识。随着文明的进化,这些丰富的天文学知识,必然反映到记载古代文化的书籍典册之中,遗留于后世。出土的殷商时代甲骨刻辞早就有了某些星宿名称和日食、月食记载。《周易》《尚书》《诗经》《春秋》《国语》《左传》《吕氏春秋》《礼记》《尔雅》《淮南子》等书更有大量的详略不同的星宿记载和天象叙述。《史记·天官书》《汉书·天文志》更是古天文学的专门之作。文史工作者随时接触古代典籍,势必常与古代天文历法打交道。如果对此一知半解或不甚了了,很难谈得上进行深入的研究。就是一般爱好文史的青年,有一定的古天文学知识,对阅读古书也是大有帮助的。

常识告诉我们,一切与古代典籍有关的学科,无不与时间的记载,也就是古代天文历法有关。清人汪日桢说:“读史而考及于月日干支,小事也,然亦难事也。欲知月日,必求朔闰;欲求朔闰,必明推步……盖其事甚小,为之则难。不知推步者,欲为之而不能为;知推步者,能为之而不屑为也。”(见《历代长术辑要》载《二十四史月日考序目》)可见,古人深知“推步”的重要和“推步”的甘苦。白寿彝教授也指出:“关于时间的记载,是历史记载必要的构成部分,年代学的研究是历史文献学研究的主要课题。”(《人民日报》,1980年12月30日)

当今的现状是,有关古天文之学众说纷纭,头绪繁杂,令人不知从何下手,欲读不能。一般著述往往博大疏浅,叙史而已,或者演算繁难,玄秘莫测,“不把金针度与人”。读者终书,竟无法找到打开古天文历法大门的钥匙,未免望之兴叹,视为畏途。此篇以基本的天文常识入手,依据本师张汝舟先生星历观点,深入浅出,意欲将古籍中需要涉及的古天文学问题,逐一展开讨论,希望能对校读古籍有所助益,且能由一般文史工作者自行独立推演年月日时,掌握一套基本的“推步”技术,为深入的研究打下扎实的基础。

一、时间与天文历法 #

中国古代,合天文历法为一事,历法以天象为依据,历法属于实用天文学的重要内容。所以,中国古代文学与年、月、日、时这些时间观念紧密相依。学习古代天文学,就从认识“时间”这个概念开头吧!

中央人民广播电台每日整点都发出“嘟——嘟——”的时间讯号,以此统一全国民用时间。全国各行各业都按这个统一的标准时间学习和工作。没有统一的时间观念,一切工作都无法正常进行,社会将发生混乱。可知,人类社会对于时间的首要要求,就是有统一的计量标准,不能各自为政,自行其是。远古时代,人类分为若干互不交往的群体,各有自己的一套计时方法。随着社会的进步,交流的频繁,彼此认识到生活在地球这个大家庭里,还必须有统一的国际标准时间来协调全人类的活动,才能促进社会的更大发展。

在古代,人们对于时间的精确度要求不高,最早是把一天分为朝、午、昏、夜四个时段,后来又分为十个时段、十二个时段,也就大体够用了。随着生产力的发展,要求时间的精确度越来越高。现代科学技术,更要求计量时间不能有一秒的误差。测定人造卫星的位置,如果误差1秒,就有7~8公里的差距。精密的电子工业,无线电技术,运输通讯,卫星、导弹的发射,要求的精确度都很高。因此,现代生活要求有精确的统一的时间计量标准,指导全人类的生产劳动。

时间不是人的主观臆造。时间是客观存在的与物质运动紧密相连的一种物质存在的形式。人们只能依据物质的运动来规定时间,寻找计时的单位。

我国古代,先民以太阳东升西落确定一天的时间,单位是日;以月亮的隐现圆缺定一月的时间,单位是月;以寒来暑往及草木禾稼的荣枯定一年的时间,单位是年。远古时代人们的时间计量单位之所以仍有作用,今天还在指导着人们的活动,就在于完全符合人类对时间计量方法的基本要求:既承认时间是物质存在的形式,又以有规律的、匀速的、周而复始的运动形式作为计量标准。这种从不间断的、匀速的、重复出现的物质运动形式,在人们的周围是存在着的,这就是日月星辰的出没所组成的若干天文现象。时间计量单位的确定完全以天象为依据,就是这个道理。尽管上古先民长期坚持“地心说”,认为日月星辰都在围绕着地球转动,但这种周而复始的物质运动形式却是古今一致的。

在所有的计时单位中,人们把地球自转一周作为计时的最基本单位——日,古人认为是太阳东升西落绕了地球一圈。月、年是比日更大的计时单位。时辰、小时、刻、分、秒,是比日小的计时单位。时、分是日的分数,古人称为日之余分。

明确了时间的计量单位,还有一个时段和时刻的问题。换句话说,通常所谓“时间”,包含着两个含义:一是指某一瞬间,即古人所谓“时刻”;一是指两个瞬时之间隔,即一个有始有终的长度。从时刻的含义出发,时间有早迟之分。从时段的含义出发,时间有长久与短暂之别。历法中的节气与节气的交替(交节),月亮运行在太阳、地球之间的平面上成一直线的天象(合朔),日与日的交接(夜半0点整)等都应该是指时刻而言,十分确切,具体到某时几分几秒的那一瞬间,毫无含糊。月亮最圆的时间,与合朔时间一样只有那么一瞬时。差一秒还不是最圆,过一秒也不可能最圆。电台报时的“嘟——嘟——”那最后特殊一响,就是时刻概念的具体化。而平常所说的几分、几小时、几日,都是指的一个时段,它必有一个起算时刻。计时的基本单位——日,是从夜半0点起算的,止于24点整。任何一个更长的时段,比如百年、千年,都必须明确它的起算时刻。任何历法都很强调它的起算点,都希望找一个理想的起算时刻作为它的初始,这就是历法之“元”,称“历元”。

我们的先民,十分重视时间,特别是与农事有关的天时,古籍中记载特多。其实,古人的“天时”,是指一年四季包括风、雨、雷、电等直接关系农事活动的自然现象,古人认为这些是上天主宰的,所以称为“天时”。

《孟子》云:“不违农时,谷不可胜食也。”

《荀子》云:“春耕、夏耘、秋收、冬藏,四时不失时,故五谷不绝而百姓有余食也。”

《韩非子》云:“非天时,虽十尧不能冬生一穗。”

《吕氏春秋》有:“夫稼,为之者人也,生之者地也,养之者天也。是故得时之稼兴,失时之稼约。”

《齐民要术》有:“顺天时,量地利,则用力少而成功多,任情返道,劳而无获。”

《农书》有:“力不失时,则食不困。……故知时为上,知土次之。”

这些典籍中所谓“时”“天时”,实际是指关系农事成败的气候。气候的变动,与时令的推移有关,也直接与天象关联着,所以也应视为古代天文历法的内容。

《说文解字》云:“时,四时也。”指的是春夏秋冬四季。据吴泽先生的研究,在殷墟甲骨文中,已出现春夏秋冬四字。春字字形像枝木条达的形状;夏字字形一像草木繁茂之状,一像蝉形,蝉是夏虫,被认为是夏的象征;秋字像果实累累,谷物成熟,正是收获之时;冬字则形如把谷物藏于仓廪之中。这四个字,都与农业有关。春种、夏长、秋收、冬藏,季节、时令都同农事密切相关。

时间,关系到人类社会的政治、生产、生活等各方面的活动。自古以来,我们的祖先就十分重视年、月、日、时的安排,创制了多种多样的历法;对各项活动发生的年、月、日、时也做了大量的准确记录,保存在浩如烟海的典籍之中。古史古事就靠这些年、月、日、时的记载有了一个清晰的脉络,我们据此研究古代人类社会生活的各个方面。如果没有年、月、日、时的记载,众多的典籍史料就成了一堆杂乱无章的文字记录,其价值也就可想而知。中国古代大量珍贵史料就是靠年、月、日、时的记载而保存下来的。我们还可以用后代的历法依据古籍中年、月、日、时的记载推演出当时的实际天象,解决历史上若干悬而未决的年代问题。如果没有关于时间的文字记载,这种推算也就无法进行。

二、天文与历法 #

什么是天文?什么是历法?这是首先应该弄清楚的问题。

《说文》云“文,错画也。象交文”,又说“仰则观象于天”。高诱注《淮南子·天文训》说:“文者象也。天先垂文象日月五星及彗孛,皆谓以谴告一人。故曰天文。”王逸注《楚辞》“象”字云“法也”。《易·系辞》:“天垂象见吉凶,圣人则之。”可见,天文就是天象,就是天法,就是日月星辰在天幕呈现的有规律的运动形式。它不以人的意志为转移,反而影响着支配着人类的各种活动。正因为这样,远古的人就视之为神圣,把天象看成是上帝、上天给人的吉凶预兆,敬若神明。历代君王重视天文,因为它是上天意旨的体现,它直接关系着人类的生产、生活,影响帝王统治权力的基础。

繁体曆法之曆,最早的写法是秝,后写作、厤,再后写作曆。《玉篇》曰:“稀疏秝秝然。”段玉裁以为:“从二禾,禾之疏密有章也。”《说文》释:“厤,治也。”“,和也。”《释诂》释:“厤,数也。”从这些释义看,就是均匀调治之义。从二禾,禾的生长受日月星辰运行的天象支配,即受日月运行所确定的季节的支配,所以秝、厤与天象有关。

秝,古书写作,表示人在有庄稼的地里行走,引申为日月运行及日月运行所确定的季节、时令等时间计量。首先,这种运行是有规律的,“疏密有章”;其次,还需要调治,要均匀地调治,使日月运行的时日彼此协调。所以,秝就是均匀地调治天象所显示的年、月、日、时等计量时间单位的手段。

《史记·历书》以厤为推步学,以象为占验学,把两者的区别说得清清楚楚。占验,当然指天象,指上天通过天象显示给人们的吉凶预兆。推步,就是对日月星辰,主要是日月的运行时间进行计算,使日绕地球一圈所形成的寒暑交替与月绕地球一圈所呈现的圆缺隐现彼此配合得大体一致。这就是制历,也就是推步学。

历是什么,简单说就是计量年、月、日的方法,就是年、月、日的安排。这种安排、计量的依据是天象变化的规律,是依据日月星辰有规律的运行来确定年、月、日、时和四季、节气,或者说推算天象以定岁时。作为一种纪时系统,目的只能是服务于人类的生产生活。

一般将历法之“法”,解释为制历的方法。不对。这个“法”,正如语法之“法”,指法则、规律。远古时代的夏商周,当然有它的年月日安排的方法,虽然还比较粗疏,但还有它那时的“历”以指导人的社会生产活动。这种历是否成“法”呢?如果确定一年为“三百有六旬有六日”(《尧典》),是不可能有规律地调配年月日的,还形不成“法”。只有到春秋中期以后,测量出一回归年为36514日,到战国初期创制、行用四分历,才可能有“法”可依,才称得上有了历法。有历法之前,都是根据天象的观测,调整年月日,随时观测,随时调整,这还是观象授时的时代。到了有“法”可依的时代,就有可能将天象的数据抽象化,就有可能依据日月星辰运行的规律,通过演算,上推千百年,下推千百年,考求、预定年、月、日、时。我国最早的一部历法——四分历,就具备了这种条件。 可见,历与历法不能混为一谈。什么是历法呢?历法就是利用天象的变化规律调配年、月、日、时的一种纪时法则。

历法与天象那么紧密不可分,正是我国古代历法独具的特点。在我国古代,历法就包含在古天文学之中,历法是古代天文学中一个很重要的领域。历法的普遍内容包括节气的安排,一年中月的安排,一月中日的安排以及闰月安插规则,等等。我国古代历法还有关于日食、月食的预报和五大行星运行的推算。总之,离开天文就无所谓历法,历法反映了大量的天文现象,历法中有丰富的天文学内容,历法就是古天文学的一个部分。我国古代合天文、历法为一事,就是这个道理。同样的原因,古人称天文历法为历算、星算、天算、星历……总是将天文、历法合在一起加以表述。

历法的内容,一部分属于实用天文学的范围,另一部分属于理论天文学的范围。测时与制历就是天文学为生产服务的主要工作。我国古代历法重视对天象的推算,不仅反映了对天文学的重视,也常常以此来考核历法的准确性。古代历法史上的多次改革,其直接原因之一就是由于日食等天象的预推出现了差误。从一定程度上来说,我国古代的编历工作,也就是一种编算天文年历的工作。由此可见,我国古代天文学家何等重视实践与理论的结合。

正因为这样,当我们谈到古代天文学,那实际已经包括了古代历法的内容。

三、天文常识 #

人类社会各个民族生活的地域不同,星象与季节的相应关系也不同,但是用天象定岁时都是共同的。古代埃及人重视观测天狼星,因为每年天狼星与太阳一起升起的时候,就预示着尼罗河要泛滥,而尼罗河泛滥带来的肥沃土壤,正是埃及人播种的需要。我国上古的夏朝,重视参宿三星的观察,每年三星昏见西方,就意味着春耕季节的开始,参宿就成了夏族主祭祀的星了。晚起的商族,着重观察黄昏现于东方地平线上的亮星,看中了心宿三星,最亮的心宿二就是“大火”。大火昏见东方,也正是春耕季节播种的日子。大火就成了商族主祭祀的星。所以《公羊传·昭公十七年》载:“大火为大辰,伐为大辰,北极亦为大辰。”何休《公羊解诂》云:“大火谓心星,伐为参星。大火与伐,所以示民时之早晚。”这里所谓“大辰”,就是观察天象的标准星,均指恒星而言。大火为大辰,是就商代而言;伐为大辰,是就夏朝而言;北极亦为大辰,当指以北极星为观察天象的标准的更古时代。于此可见,我国上古对于北极星的认识,起源更早。

现代天文学知识告诉我们,在太阳系里有水星、金星、地球、火星、木星、土星、天王星、海王星共八大行星围绕着太阳,按照各自的轨道和速度运行着。——古人凭肉眼观测,以地球为中心,早就认识了五大行星(金、木、水、火、土)并了解到它们绕地球一圈的时间,掌握了它们的运行规律。

地球绕太阳公转的同时,还在自转。公转一周为365.24219日,自转一周为24小时。由于地球自转轨道与公转轨道有23°26′的倾斜角,地球表面受到太阳照射的程度不同(直射或斜射,斜射还有角度的不同),便有了春夏秋冬四季冷暖的变化。

月球是地球的卫星,它围绕着地球旋转,运行一周为29.53059日,月球本身不发光,人们所见到的月相是月球对太阳光的反射。随着地球、月球与太阳相互位置的变化,月相也周期性变化着。当月亮的背光面对着地球,人们看不到有光的月面,即为朔日(阴历初一);当月亮的受光面全部对着地球,人们看到一轮满月,即为望日(阴历十五)。从朔日到望日,望日到朔日之间还有各种月相。人们根据月相变化和月亮出没时间,便知道阴历的日期。俗话说:“初三初四蛾眉月,初七初八月半边,十五十六月团圆。”这种以月相变化为依据,从朔到朔或从望到望的周期长度,叫朔望月,就是阴历的一个月。

每一个朔望月,月球都要行经地球和太阳之间的空间一次,如果大体在一个平面上,月球遮住了太阳射向地球的光线,就会发生日食;当地球运行到太阳和月球中间(每月有一次机会),如果大体在一个平面上,地球就会挡住太阳射向月球的光线,就要发生月食。因此,日食总是发生在朔日,月食总是发生在望日。古人特别重视日食的记载,认为是上天对君主的警告,是凶兆。古代天文学家还以日食检验历法的准确性,食不在朔,便据以调历。

前人是怎样以地球为中心表述日食、月食这些天象的?我们用曾运乾先生《尚书正读》注文来回答这个问题,至少可以给我们一些启发。注云:当朔而日为月所掩,是为日食。当望而月为日所冲,是为月食。又说,古人制字,“朔”“望”“有”均从月得义。朔字从月从屰(屰,不顺也)。月与日同经度而不同纬度,则相屰而为合朔。若同经度而又同纬度,则相屰而为日食。望,为月食专字。从月从壬(壬,朝廷也),取日月相对望也。从亡,遇食则有亡象焉。有,为日食专字。从月,月光蔽其明也。从又,一指蔽前,泰山不见也。则知日月食之由于蔽也。《说文》:“有,不宜有也。春秋传曰,日月又食之。从月又声。”段氏注云:“谓本是不当有而有之称,引申遂为凡有之称。”

古代先民只是直观地以地球为中心来观测天体的运行,这就是西方科学未传入中国之前我国古代长期行用的地心说。日月星辰的东升西落,实际是因为地球从西向东在转动。这种地心说并非全无道理。比如上和下,是一种比较的说法。在地球上的上与下,其实都是在和地球中心比较,拿地球中心做标准来比较是有道理的。舍此,就无所谓上与下。同样,国际通用的标准时自有好处,而各个地方时更为各地的使用者称便。道理都一样,地心说对观测者似更方便。古人想象,地球四周被巨大的天球包围着,所有的日月星辰都在天球上运行。太阳系八大行星,古人凭肉眼观测,以地球为中心,只能见到金、木、水、火、土五大行星,并掌握了它们各自绕地球一圈的时间及运行规律,记之甚详。古代典籍关于天象的记载,立足于地心说。古代星图、天球仪之类也据此成象。阅读古籍者不可不知。

四、历的种类 #

人类对天象进行观测以确定计时标准,其中观测的主要对象是日、月的运行,依据日、月的运行周期以制定各自的历法。迄今为止,世界上的历法可分为三类:太阴历、太阳历和阴阳合历。

甲,太阴历。它是以月球受光面的圆缺晦明变动为基础,利用月球运行周期(朔望月)为标准制定的历法。月亮运行的周期是29.53日,太阴历就用大月(30日)、小月(29日)相间,一大一小来调整。因为每两月有0.06日盈余,还需要配置连大月才能保证月初必朔,月中必望。太阴历以十二个朔望月为一年计算,共354日或355日。它把月相与日期固定地联系在一起,见月相而知日期,知日期亦知月相。这在上古,无疑给人们的生产和生活带来方便。其致命的弱点是,十二个朔望月(平年354日)与太阳的运行周期(即回归年长度365.2422日)不相吻合,太阴历每年与回归年有11日多的时差,积三年就相差34日。这就必将搅乱月份与回归年长度确定的春夏秋冬四季的关系,冷暖四季与月份的关系错乱,又会给人们的生产、生活带来困难。

从古代历史记载得知,世界上最早制历的国家都首先使用过太阴历,因为月球的盈亏变化对人类而言较为明显而又亲切。上古时代,日苦其短,年嫌其长,月的周期最能适应宗教仪式的需要,朔望月自然就占有了重要的地位。

伊斯兰教用于祭祀节日的回回历就是现存的唯一纯太阴历。回历以公元622年7月16日,即穆罕默德避难麦加的次日为元年元日,以朔望月计,十二月为一年,每月以月牙初见为第一日,单月30日,双月29日,大月小月相间,全年354日,不置闰月。由于十二个朔望月共354日8时48分34秒,每年多出8小时有余,积三年就多出一天有余。所以,回历每三十年共置十一个闰日。在三十年中,第2、5、7、10、13、16、18、21、24、26、29年为闰年,每年355日,闰日放在十二月。

由于太阴历和回归年的日差,回历的岁首和节日(如肉孜节、古尔邦节)寒暑不定,便是可以理解的了。

陈垣先生《二十史朔闰表》附有回历与公元历、阴历的日期对照,便于检查。

乙,太阳历。它是以太阳的回归年周期为基本数据制定的历法。欧洲太阳历是古罗马恺撒在公元前46年请埃及天文学家索西琴尼斯协助制定的,世称“儒略历”或“旧太阳历”。当时测得的回归年长度为36514日。因此,儒略历规定,每四年中前三年为平年365日,第四年为闰年366日,即逢四或逢四的倍数的年份为闰年。一年十二个月,单月为大月31天,双月为小月30天。起自3月,终于2月,与月相完全无关。因为罗马帝国每年2月(年终)处决犯人,视为不吉,所以减去一日,平年只有29日,闰年为30日。又因为恺撒养子屋大维(奥古斯都)生于8月(小月),又从2月减一日加到8月,变8月小为8月大(31日)。这样,2月即为28日(闰年为29日)。为了避免由于2月小、8月大而造成的7月、8月、9月三个月连大,又改为7月、8月连大,9月、11月为小月,10月、12月为大月。这都是人为的规定。

公元325年,罗马帝国召开宗教会议,决定统一采用儒略历,并依据当时的天文观测,定3月21日为春分日。

回归年长度为365.24219日,即365日5时48分46秒。而儒略历是以36514日,即365日6时为数据制定的。两者有11分14秒之差,长期积累就会形成明显误差(128年差1日),这在当时并不为人所知。到公元1582年,人们发现春分点竟在3月11日,与公元325年的春分点相差十日之多,即1258年间(325—1582)间差十日,相当于每400年误差3日。为此,罗马教皇格里高利十三世只好召集学者研究,改革儒略历,采取每400年取消3闰(即400年97闰)的方法,规定把1582年10月4日以后的一天算为1582年10月15日,所有百位数以上的年数能被400除尽者才能算闰年(如1600年,2000年)。这样,一方面纠正了儒略历的误差,另一方面又提高了太阳历的精度。改革以后的儒略历称为格里历,其精确度很高:

365×400+97=146097(日)

146097÷400=365.2425(日)

格里历这个回归年长度365.2425日比现代实测回归年长度只有0.0003日(即近26秒)之差,积累3320年才会有一日的误差。这对日用历来说,已是十分精确的了。

我国元代郭守敬至元十八年(公元1281年)制定的“授时历”,其回归年长度已达到365.2425日的精确度,比格里历早了三百年。

当今世界通用公元纪年,共同使用的就是格里历。而公元纪年并不开始于公元元年,而是开始于公元532年(据说基督就诞生在公元532年之前,532年正是我国南朝梁武帝中大通四年)。这是出于宗教的考虑。因为532这个数字正是星期日数7、闰年周期4和所谓月周(即一定历日的时间地球上看到月面形状变化的周期)19(年)的最小公倍数。每过532年,基督教的节日(比如复活节)又会是同一日期、星期和月相。因此,公元532年之前的公元纪年都是后来逆推而定的。

太阳历以回归年周期为依据,四季与月份的关系稳定。中国古历形成的二十四节气就比较固定地配合在太阳历的一些日子里。

埃及人在远古时代曾一度使用太阴历,后来因为尼罗河涨水对生产影响极大,需要预报涨水时期,而尼罗河水涨和夏至是在天狼星出现的第一天早晨同时来到。古埃及人知道太阳在天球上的运行与尼罗河的洪水期有关,所以特别注意太阳在一年中各时期的高度,以及日出、日没时间和方位。同时还精密地观测了天狼星及南河三等恒星的周年运动,发现了太阳运行周期——回归年长度为36514日。在公元前2000多年古埃及人就制定了以365日为一年的太阳历,而放弃了太阴历的使用。

格里历所代表的太阳历也有不便之处,一是每月天数不统一,二是完全排除了月相周期。因此,历法研究者曾提出不少改革格里历的方案,有代表性的方案有两种。

...

版权-序-前言

版权信息 #

图书在版编目(CIP)数据

古代天文历法讲座/张闻玉著.—2版.—桂林: 广西师范大学出版社,2017.10 (中华优秀传统文化名家讲座) ISBN 978-7-5495-9716-1

Ⅰ.①古… Ⅱ.①张… Ⅲ.①古历法-基本知识- 中国 Ⅳ.①P194.3

中国版本图书馆CIP数据核字(2017)第106428号

广西师范大学出版社出版发行( 广西桂林市中华路22号 邮政编码:541001 )

出版人:张艺兵

全国新华书店经销

开本:700 mm × 970 mm 1/16

印张:23 字数:280千字

2017年10月第2版 2017年10月第1次印刷

印数:0 001~4 000册 定价:59. 80元

目录

版权信息

《古代天文历法讲座》新版序

前言

第一讲为什么要了解古天文历法 一、时间与天文历法

二、天文与历法

三、天文常识

四、历的种类

五、古天文学与星占

六、古代天文学在阅读古籍中的作用

七、怎样学好古天文历法

第二讲纪时系统 一、纪年法

二、纪月法

三、纪日法

四、纪时法

第三讲观象授时 一、地平方位

二、三垣二十八宿

三、《尧典》及四仲中星

四、《礼记·月令》的昏旦中星

五、北极与北斗

六、分野

七、五星运行

八、《诗·七月》的用历

九、观象授时要籍对照表

第四讲二十四节气 一、先民定时令

二、土圭测景

三、冬至点的测定

四、岁差

五、节气的产生

六、二十四节气的意义

七、节气的分类

...

下篇

下篇 宏观现象 #

上篇介绍了地方政府推动经济发展的模式。这种模式的第一个特点是城市化过程中“重土地、轻人”,优点是可以快速推进城市化和基础设施建设,缺点是公共服务供给不足,推高了房价和居民债务负担,拉大了地区差距和贫富差距。第五章分析这些内容,并介绍土地流转和户籍改革等要素市场的改革。第二个特点是招商引资竞争中“重规模、重扩张”,优点是推动了企业成长和快速工业化,缺点是加重了债务负担。企业、地方政府、居民三部门债务互相作用,加大了经济整体的债务和金融风险。第六章分析这些内容,并介绍“供给侧结构性改革”,详述“去库存、去产能、去杠杆”及“防范化解重大金融风险”。第三个特点是发展战略“重投资、重生产、轻消费”,优点是拉动了经济快速增长,扩大了对外贸易,使我国迅速成为制造业强国,缺点是经济结构不平衡。对内,资源向企业部门转移,居民收入和消费占比偏低,不利于经济长期稳定发展;对外,国内无法消纳的产能向国外输出,加剧了贸易冲突。第七章分析这些内容,并介绍党的十九大重新定义“主要矛盾”后的相关改革,详述“形成以国内大循环为主体、国内国际双循环相互促进的新发展格局”所需要的改革。

第五章 城市化与不平衡 #

教书久了,对年轻人不同阶段的心态深有体会。大一新生刚从中学毕业,无忧无虑,爱思考“为什么”;大四毕业生和研究生则要走向社会,扛起工作和生活的重担,普遍焦虑,好琢磨“怎么办”。大多数人的困境可以概括为:有心仪工作的城市房价太高,而房价合适的城市没有心仪的工作。梦想买不起,故乡回不去。眼看着大城市一座座高楼拔地而起,却难觅容身之所。为什么房子这么贵?为什么归属感这么低?为什么非要孤身在外地闯荡,不能和父母家人在一起?这些问题都与地方政府推动经济发展的模式有关。

城市化需要投入大量资金建设基础设施,“土地财政”和“土地金融”是非常有效的融资手段。通过出让城市土地使用权,可以积累以土地为信用基础的原始资本,推动工业化和城市化快速发展。中国特有的城市土地国有制度,为政府垄断土地一级市场创造了条件,将这笔隐匿的财富变成了启动城市化的巨大资本,但也让地方财源高度依赖土地价值,依赖房地产和房价。房价连着地价,地价连着财政,财政连着基础设施投资,于是经济增长、地方财政、银行、房地产之间就形成了“一荣俱荣,一损俱损”的复杂关系。

这种以土地为中心的城市化忽视了城市化的真正核心:人。地价要靠房价拉动,但房价要由老百姓买单,按揭要靠买房者的收入来还。所以土地的资本化,实质是个人收入的资本化。支撑房价和地价的,是人的收入。忽略了人,忽略了城市化本该服务于人,本该为人创造更好的环境和更高的收入,城市化就入了歧途。

1980年,我国城镇常住人口占总人口比重不足两成,2019年超过了六成(见图5-1)。短短40年,超过5亿人进了城,这是不折不扣的城市化奇迹。但若按户籍论,2019年的城镇户籍人口只占总人口的44%,比常住人口占比少了16个百分点。也就是说有超过2亿人虽然常住城镇,却没有当地户口,不能完全享受到应有的公共服务(如教育),因为这些服务的供给是按户籍人数来规划的。这种巨大的供需矛盾,让城市新移民没有归属感,难以在城市中安身立命,也让“留守儿童、留守妇女、留守老人”成为巨大的社会问题。近年来一系列改革措施的出台,都是为了扭转这种现状,让城市化以人为本。

图5-1 城镇人口占总人口比重

数据来源:万得数据库与国家统计局历年《国民经济和社会发展统计公报》。

本章第一节分析房价和土地供需间的关系,讨论高房价带来的日益沉重的居民债务负担。第二节分析地区间发展不平衡,其根源之一在于土地和人口等生产要素流动受限,所以近年来在土地流转和户籍制度等方面的改革非常重要。第三节分析我国经济发展过程中出现的贫富差距,这一现象也和房价以及要素市场改革有关。

第一节 房价与居民债务 #

1994年分税制改革(第二章)是很多重大经济现象的分水岭,也是城市化模式的分水岭。1994年之前实行财政包干制,促进了乡镇企业的崛起,为工业化打下了基础,但农民离土不离乡,大多就地加入乡镇企业,没有大量向城市移民。分税制改革后,乡镇企业式微,农民工大潮开始形成。从图5-1中可以清楚地看到,城镇常住人口自1995年起加速上涨,城市化逐渐进入了以“土地财政”和“土地金融”为主要推手的阶段。这种模式的关键是房价,所以城市化的矛盾焦点也是房价。房价短期内受很多因素影响,但中长期主要由供求决定。无论是发达国家还是发展中国家,房屋供需都与人口结构密切相关,因为年轻人是买房主力。年轻人大都流入经济发达城市,但这些城市的土地供应又受政策限制,因此房屋供需矛盾突出,房价居高不下。

房价与土地供需 #

现代经济集聚效应很强,经济活动及就业越来越向大城市集中。随着收入增长和生活水平提高,人们高价竞争城市住房。这种需求压力是否会推升房价,取决于房屋和住宅用地供给是否灵活。若政策严重限制了供给,房价上涨就快。一个地区的土地面积虽然固定,但建造住宅的用地指标可以调整;同一块住宅开发用地上,容积率和绿化面积也可以调整。 11 这些调整都受政策的影响。美国虽然是土地私有制,但城市建设和用地规划也要受政府管制。比如旧金山对新建住房的管制就特别严格,所以即使在20世纪90年代房价也不便宜。在21世纪初的房地产投机大潮中,旧金山的住房建设指标并没有增加,房价于是飙升。再比如亚特兰大,住房建设指标能够灵活调整,因此虽然也有大量人口涌入,但房价一直比较稳定。 22

我国的城市化速度很快,居民收入增长的速度也很快,所以住房需求和房价上涨很快。按照国家统计局的数据,自1998年住房商品化改革以来,全国商品房均价在20年间涨了4.2倍。但各地涨幅大不相同。三四线城市在2015年实行货币化棚改(见第六章)之前,房价涨幅和当地人均收入涨幅差不多;但在二线城市,房价就比人均收入涨得快了;到了一线城市,房价涨幅远远超过了收入:2015年之前的十年间,北、上、广、深房价翻了两番,年均增速13%。 33

地区房价差异的主要原因是供需失衡。人口大量涌入的大城市,居住用地的供给速度远赶不上人口增长。2006年至2014年,500万人和1 000万人以上的大城市城区人口增量占全国城区人口增量的近四成,但居住用地增量才占全国增量的两成,房价自然快速上涨。而在300万人以下尤其是100万人以下的小城市中,居住用地增量比城镇人口增量更快,房价自然涨不上去。从地理分布上看,东部地区的城镇人口要比用地增速高出近10%,住房十分紧张;而西部和东北地区则反过来,建设用地指标增加得比人口快。 44

中国对建设用地指标实行严格管理,每年的新增指标由中央分配到省,再由省分配到地方。这些指标无法跨省交易,所以即使面对大量人口流入,东部也无法从西部调剂用地指标。2003年后的十年间,为了支持西部大开发并限制大城市人口规模,用地指标和土地供给不但没有向人口大量流入的东部倾斜,反而更加向中西部和中小城市倾斜。2003年,中西部土地供给面积占全国新增供给的比重不足三成,2014年上升到了六成。2002年,中小城市建成区面积占全国的比重接近一半,2013年上升到了64%。 55 土地流向与人口流向背道而驰,地区间房价差距因此越拉越大。

然而这种土地倾斜政策并不能改变人口流向,人还是不断向东部沿海和大城市集聚。这些地区不仅房价一直在涨,大学的高考录取分数也一直在涨。中西部房价虽低,但年轻人还是愿意到房价高的东部,因为那里有更多的工作机会和资源。倾斜的土地政策并没有留住人口,也很难留住其他资源。很多资本利用了西部的优惠政策和廉价土地,套取了资源,又回流到东部去“炒”房地产,没在西部留下可持续发展的经济实体,只给当地留下了一堆债务和一片空荡荡的工业园区。

建设用地指标不能在全国交易,土地使用效率很难提高。地方政府招商引资竞争虽然激烈,也经常以土地作为手段,却很难持续提高土地资源利用效率。发达地区土地需求旺盛,地价大涨,本应增加用地指标,既满足需求也抑制地价。但因为土地分配受制于行政边界,结果却是欠发达地区能以超低价格(甚至免费)大量供应土地。这种“东边干旱,西边浇水”的模式需要改革。2020年,中央提出要对建设用地指标的跨区域流转进行改革,探索建立全国性建设用地指标跨区域交易机制(见第二节),已是针对这一情况的改革尝试。 66

房价与居民债务:欧美的经验和教训 #

居民债务主要来自买房,房价越高,按揭就越高,债务负担也就越重。各国房价上涨都是因为供不应求,一来城市化过程中住房需求不断增加;二来土地和银行按揭的供给都受政治因素影响。

在西方,“自有住房”其实是个比较新的现象,“二战”之前,大部分人并没有自己的房子。哪怕在人少地多的美国,1900—1940年的自有住房率也就45%左右。“二战”后这一比率才开始增长,到2008年全球金融危机之前达到68%。英国也差不多,“二战”前的自有住房率基本在30%,战后才开始增长,全球金融危机前达到70%。 77 正因为在很长一段时间里英美大部分人都租房,所以主流经济学教材在讲述供需原理时,几乎都会用房租管制举例。1998年,我第一次了解到房租管制,就是在斯蒂格利茨的《经济学》教科书中。逻辑虽容易理解,但并没有直观感受,因为当时我认识的人很少有租房的,农民有宅基地,城里人有单位分房。城市住房成为全民热议的话题,也是个新现象。

欧美自有住房率不断上升,有两个后果。第一是对待房子的态度变化。对租房族来说,房子就是个住的地方,但对房主来说,房子是最重要的资产。随着房子数量和价格的攀升,房产成了国民财富中最重要的组成部分。1950年至2010年,英国房产价值占国民财富的比例从36%上升到57%,法国从28%升到61%,德国从28%升到57%,美国从38%升到42%。 88 第二个变化是随着房主越来越多,得益于房价上涨的人就越来越多。所以政府为讨好这部分选民,不愿让房价下跌。无房者也想尽快买房,赶上房价上涨的财富快车,政府于是顺水推舟,降低了买房的首付门槛和按揭利率。

美国房地产市场和选举政治紧密相关。美国的收入不平等从20世纪七八十年代开始迅速扩大,造成了很多政治问题。而推行根本性的教育或税制等方面的改革,政治阻力很大,且难以在短期见效。相比之下,借钱给穷人买房就容易多了,既能缓解穷人的不满,让人人都有机会实现“美国梦”,又能抬高房价,让房主的财富也增加,拉动他们消费,创造更多就业,可谓一举多得。于是政府开始利用房利美(Fannie Mae)和房地美(Freddie Mac)公司(以下简称“两房”)来支持穷人贷款买房。“两房”可以买入银行的按揭贷款,相当于借钱给银行发放更多按揭。 99 1995年,克林顿政府规定“两房”支持低收入者的房贷要占到总资产的42%。2000年,也就是克林顿执政的最后一年,这一比率提高到50%。2004年,小布什政府将这一比率进一步提高到56%。 1010 “两房”也乐此不疲,因为给穷人的贷款利润较高,风险又似乎很低。此外,对购房首付的管制也越来越松。2008年全球金融危机前很多房贷的首付为零,引发了投机狂潮,推动房价大涨。根据Case-Shiller房价指数,2002年至2007年,美国房价平均涨了将近60%。危机之后,房价从2007年的最高点一直下跌到2012年,累积跌幅27%,之后逐步回升,2016年才又回到十年前的高点。

房价下挫和收入下降会加大家庭债务负担,进而抑制消费。消费占美国GDP的七成,全球金融危机中消费大幅下挫,把经济推向衰退。危机前房价越高的地区,危机中消费下降越多,经济衰退也越严重,失业率越高。 1111 欧洲情况也大致如此。大多数欧洲国家在2008年之前也经历了长达十年的房价上涨。涨幅越大的国家居民债务负担越重(绝大多数债务是房贷),危机中消费下降也越多。 1212

房地产常被称作“经济周期之母”,根源就在于其内在的供需矛盾:一方面,银行可以通过按揭创造几乎无限的新购买力;而另一方面,不可再生的城市土地供给却有限。这对矛盾常常会导致资产泡沫与破裂的周期循环,是金融和房地产不稳定的核心矛盾。而房地产不仅连接着银行,还连接着千家万户的财富和消费,因此影响很大。

房价与居民债务:我国的情况 #

2008年之后的10年,我国房价急速上涨,按揭总量越来越大,居民债务负担上涨了3倍多(图5-2)。2018年末,居民债务占GDP的比重约为54%,虽仍低于美国的76%,但已接近德国和日本。根据中国人民银行的信贷总量数据,居民债务中有53%是住房贷款,24%是各类消费贷(如车贷)。 1313 这一数据可能还低估了与买房相关的债务。实际上一些消费贷也被用来买了房,比如违规用于购房首付。而且人民银行的数据还无法统计到民间借贷等非正规渠道。

图5-2 居民债务占GDP比重

数据来源:IMF全球债务数据库。此处债务仅包括银行贷款和债券。

图5-2中债务负担的分母是GDP,这一比率常用于跨国比较,但它低估了居民的实际债务负担。还债不能用抽象的GDP,必须用实实在在的收入。2019年末,中国人民银行调查统计司调查了全国3万余户城镇居民(农民负债率一般较低,大多没有房贷)的收入和债务情况。接近六成家庭有负债,平均债务收入比为1.6,也就是说债务相当于1.6倍的家庭年收入。这个负担不低,接近美国。2000年,美国家庭负债收入比约为1.5,2008全球金融危机前飙升至2.1,之后回落到1.7左右。 1414

根据中国人民银行的这项调查,城镇居民2019年的负债中有76%是房贷。而从资产端看,城镇居民的主要财产也就是房子。房产占了家庭资产的近七成,其中六成是住房,一成是商铺。而在美国居民的财富中,72%是金融资产,房产占比不到28%。 1515 中国人财富的压舱石是房子,美国人财富的压舱石是金融资产。这个重大差别可以帮助理解两国的一些基本政策,比如中国对房市的重视以及美国对股市的重视。

总体看来,我国居民的债务负担不低,且仍在快速上升。最主要的原因是房价上涨。居民债务的攀升已然影响到了消费。以买车为例,这是房子之外最贵的消费品类,对宏观经济非常重要,约占我国社会商品零售总额的10%。车是典型的奢侈品,需求收入弹性很大,收入增加时需求大增,收入减少时需求大减。随着居民债务增加,每月还债后的可支配收入减少,所以经济形势一旦变差,买车需求就会大减。我国家用轿车市场经历了多年高速增长,2018年的私家车数量是2005年的14倍。但是从2018年下半年开始,“贸易战”升级,未来经济形势不确定性增大,轿车销量开始下降,一直到2019年底,几乎每个月同比都在下降。在新冠肺炎疫情影响之下,2020年2月份的销量同比下跌八成,3月份同比下跌四成,各地于是纷纷出台刺激汽车消费的政策。

房价与居民债务风险 #

按照中国人民银行的调查数据,北京居民的户均总资产(不是净资产,未扣除房贷和其他负债)是893万元,上海是807万元,是新疆(128万元)和吉林(142万元)的六七倍。这个差距大部分来自房价。房价上涨也拉大了同城之内的不平等。房价高的城市房屋空置率往往也高,一边很多人买不起房,一边很多房子空置。如果把房子在内的所有家庭财富(净资产)算在一起的话,按照上述中国人民银行的调查数据,2019年最富有的10%的人占有总财富的49%,而最穷的40%的人只占有总财富的8%。 1616

...