{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/cloud-native-db",
    "result": {"pageContext":{"blog":{"id":"Blogs_135","title":"云时代数据库的核心特点","tags":["Database"],"category":{"name":"观点洞察"},"summary":"最近几年，随着云计算相关技术的发展，各种不同类型的云层出不穷，服务越来越多不同类型的企业业务，传统企业也渐渐开始探索上云的道路。在云上，作为业务最核心的数据库，相比之前的传统方案会有哪些变化呢？在正式聊云时代的数据库特点之前，我们需要了解一下目前云时代架构发生的变化","body":"## 引言\n\n最近几年，随着云计算相关技术的发展，各种不同类型的云层出不穷，服务越来越多不同类型的企业业务，传统企业也渐渐开始探索上云的道路。在云上，作为业务最核心的数据库，相比之前的传统方案会有哪些变化呢？在正式聊云时代的数据库特点之前，我们需要了解一下目前云时代架构发生的变化。\n\n畅想一下，未来的服务都跑在云端，任何的服务资源都可以像水电煤一样按需选购。从 IaaS 层的容器/虚拟机，到 PaaS 层的数据库，缓存和计算单元，再到 SaaS 层的不同类型的应用，我们只需要根据自身业务特点进行资源选配，再也不用担心应用服务支撑不住高速的业务增长，因为在云上一切都是弹性伸缩的。有了可靠的基础软件架构，我们就可以把更多精力放到新业务的探索，新模式的创新，就有可能产生更多不一样的新场景，从而催生更强大能力的云端服务，这是一件多么 cool 的事情。\n\n当然，理想要一步一步实现，未来的基础软件栈到底会怎样呢？社区在这方面正在进行积极地探索，其中最有代表性的就是基于容器（以 Docker 为代表）的虚拟化技术和微服务（Microservice）。\n\n在云时代，一切都应该是可伸缩的，使用 k8s（Kubernetes）在保证资源平衡的前提下，通过 Docker 部署我们依托于容器的微服务模块，我们不用关心服务到底跑在哪里，只需要关心我们需要多少服务资源。Docker 提供了极大的便利性，一次构建，到处运行，我们可以很好地解决开发、测试和上线的环境一致性问题。（如果不能很好地保证测试和实际上线环境的一致性，则很有可能需要花费远超过开发的时间去发现和修复问题。）k8s 更是在 Docker 构建的基础上增加了更多的云特性，包括 Docker 的升级，高可用和弹性伸缩等等。 关于 Docker/k8s 相关的讨论已经很多了，因为时间关系，关于具体的细节就不再展开。我们只需要了解，有了它，可以很轻松地解决服务的安装和部署。\n\n下面再聊聊微服务，微服务将一个服务拆分成相对独立的更小的子服务单元，不同的子服务单元之间通过统一的接口（HTTP/RPC 等）进行数据交互。\n\n相比于传统的解决方案，这种架构有很多的优点。\n\n - 更好的开发效率和可维护性。微服务将一个单独的服务进行更细力度的拆分，每一个子服务单元专注于更小的功能模块，可以更好地根据业务建立对应的数据模型，降低复杂度，使得开发变得更轻松，维护和部署变得更加友好.\n - 更好的可扩展性。每个不同的子服务单元相互独立，彼此之间没有任何依赖，所以可以根据业务的具体需要，灵活地部署多个子服务单元进行水平扩展。\n - 更强的容错性。当其中一个子服务出现故障的时候，可以通过辅助的负载均衡工具，自动路由到其他的子服务，不会影响整体服务的可用性.\n\n当然，微服务也不是一个银弹，相对来说，这种方案会使整体系统的设计更加复杂，同时也加大了网络的延迟，对整个系统测试的复杂度也会更高。\n\nDocker 提供的隔离型和可移植性，与微服务是一种天然的契合，微服务将整个软件进行拆分和解耦，而通过 Docker/k8s 可以很自然地做到独立的部署，高可用和容错性，似乎一切都可以完美地运转起来。但是真的是这样么？我们是不是忽略了什么？\n\n是的，我们在讨论前面的问题的时候忽略了一个很重要的东西：状态。\n\n从整个技术发展的角度来看，微服务是一个非常有意义的探索。每个人都期望着每个微服务的子服务都是无状态的，这样我可以自由地启停和伸缩，没有任何的心智负担，但是现实的业务情况是什么样的呢？比如一个电商网站，用户正在下单购买一件商品，此时平台是通过订单子服务的 A 应用来提供服务的，突然，因为机器故障，订单子服务的 A 应用不可用了，改由订单子服务的 B 应用提供服务，那么它是必须要知道刚才用户的订单信息的，否则正在访问自己订单页面的用户会发现自己的订单信息突然不见了。虽然我们尽量想把子服务设计成无状态的，但是很多时候状态都是不可避免的，我们不得不通过存储层保存状态，业界最主要的还是各种数据库，包括 RDBMS 和 NoSQL，比如使用 MySQL、MongoDB、HBase、Cassandra 等，特别是有些场景还要考虑数据一致性问题的时候，更加重了对存储层的依赖。\n\n由此可见，云计算时代系统的架构发生了巨大的变化，这一方面为用户提供了更优秀的特性，另一方面也对云计算的组件提出了更高的要求。数据库作为云计算最基础的组件之一，也需要适应这种架构的变化。（这里我们主要关注 SQL 数据库，云时代的数据库以下简称云数据库。）\n\n## 那么云数据库主要有一些什么样的特点呢？我认为主要有以下几点。\n\n### 弹性伸缩\n\n传统的数据库方案，常见的会选用 Oracle，MySQL，PostgreSQL。在云时代，数据量的规模有爆发性的增长，传统的数据库很容易遇到单机的存储瓶颈，不得不选用一些集群方案，常见的比如 Oracle RAC、 MySQL Sharding 等，而这些集群方案或多或少都有一些不令人满意的地方。\n\n比如说，Oracle RAC 通过共享存储的硬件方案解决集群问题，这种方式基本上只能通过停机换用更大的共享内存硬件来解决扩容问题，RAC 节点过多会带来更多的并发问题，同样也会带来更高的成本。\n\n以 MySQL Sharding 为代表的数据分片方案，很多时候不得不提前对数据量进行规划，把扩容作为很重要的一个计划来做，从 DBA 到运维到测试到开发人员，很早之前就要做相关的准备工作，真正扩容的时候，为了保证数据安全，经常会选择停服务来保证没有新的数据写入，新的分片数据同步后还要做数据的一致性校验。当然业界大公司有足够雄厚的技术实力，可以采用更复杂的方案，将扩容停机时间尽量缩短（但是很难缩减到 0），但是对于大部分中小互联网公司和传统企业，依然无法避免较长时间的停服务。\n\n在云时代，理想中所有的资源都是根据用户业务需求按需分配的，服务器资源，应用容器资源，当然也包括数据库资源。添加或者减少新的数据库资源，完全就像日常吃饭那样稀疏平常，甚至用户基本感知不到。比如作为一个电商用户，在双 11 促销活动之前，可以通过增加数据库节点的方式，扩大更多的资源池，用来部署相应的容器服务，当活动结束之后，再将多余的资源移除去支持其他的服务，这样可以极大地提高资源的利用率，同样可以弹性地支撑各种峰值业务。\n\n### 高可用\n\n传统的 MySQL 方案，数据复制的时候默认采用异步的方式，对于一个写入的请求，主库写入成功后就会返回成功信息给客户端，但是这个时候数据可能还没有同步给从库，一旦主库这个时候挂掉了，启动从库的时候就会有丢失数据的风险。当然，也有人会选择半同步的复制方式，这种方式在正常情况下是同步的，但是在遇到数据压力比较大的时候，依然会退化为异步的方式，所以本质上来说，同样有丢失数据的风险。其他也有一些多主的同步方案，比如在应用层做数据同步，但是这种方式一是需要应用层的配合，二是在对网络超时的处理非常复杂，增加心智负担。\n\n在云时代，因为所有的数据库资源都是分布式存储的，每个数据库节点出现问题都是很正常的事情，所以就必须有一种可以实现数据一致性的数据复制方式来保证服务的高可用，业界给出的答案就是：Paxos/Raft（关于 Paxos 和 Raft 的实现细节我们不在这里展开）。PingCAP 在做的 TiDB 就是选择了 Raft 协议，Raft 协议看起来更像是一个多副本的自适应的主从复制协议，对于每次写请求，Raft 都会保证大多数写成功才会返回客户端，即使 Raft Group的Leader 挂掉了，在一个有限的时间范围内，会很快地选出一个新的 Leader 出来，继续提供服务。同样，对于一个 3 副本的 Raft Group，只要 2 个写入成功，就可以保证成功，而大多数情况下，最先写入成功的往往是与 Leader 网络情况最好的那个副本，所以这种 Majority 写的方式，可以很自然地选择速度最快的副本进行数据同步复制。另外，Raft 协议本身支持 Config Change，增加一个新的节点，可以很容易地做副本数据分布的变更，而不需要停止任何服务。\n\n同样，在云时代，数据库的 DDL 操作也会是一个非常有趣的事情。以一个常见的 Add Column 操作为例，在表规模已经很大的情况下，在传统的实现方案中，比较有参考意义的是，通过一些工具，创建类似表级别的触发器，将原表的数据同步到一个新的临时表中，当数据追平的时候，再进行一个锁表操作，将临时表命名为原表，这样一个 Add Column 操作就完成了。但是在云时代，分布式的数据存储方式决定了这种方案很难实现，因为每个数据库节点很难保证 Schema 状态变更的一致性，而且当数据规模增长到几十亿，几百亿甚至更多的时候，很短的阻塞时间都有可能会导致很大的负载压力变化，所以 DDL 操作必须是保证无阻塞的在线操作。值得欣慰的是，Google 的 F1 给我们提供了很好的实现参考，TiDB 即是根据 F1 的启发进行的研发，感兴趣的同学可以看下相关的内容。\n\n### 易用透明\n我们可以将云数据库想象成一个提供无限大容量的数据库，传统数据库遇到单机数据存储瓶颈的问题将不复存在。已有的程序基本上不怎么需要修改已有的代码，就可以很自然地接入到云数据库中来获得无限 Scale 的能力。增减数据库节点，或者节点的故障恢复，对于应用层来说完全透明。另外，云数据库的监控、运维、部署、备份等等操作都可以在云端通过高效的自动化工具来自动完成，极大地降低了运维成本。\n\n### 多租户\n云数据库本身应该是可以弹性伸缩的，所以很自然的，从资源利用率的角度来考虑，多个不同用户的数据库服务底层会跑在一个共享的云数据库中。因此多租户技术会成为云数据库的标配。但是这里面就有一个不得不面对的问题，如何做到不同用户的隔离性？用户数据隔离是相对比较容易的，比如还是以电商用户（这里说的是电商企业，不是顾客客户）为例，每个用户都有一个唯一的 ID，这样在云数据库的底层存储中，可以保证每个用户数据都带有自己 ID 前缀，用户登陆进来的时候可以根据这个前缀规则，获取他对应的数据，同时他看不到其他用户的数据。\n\n在一个真实的多租户环境下面，纯粹的数据隔离往往是不够的，你还需要做到资源公平性的隔离。比如有的用户写一个 SQL，这个 SQL 没有做优化，主要做的事情是一个全表描扫，这个表的数据量特别特别大，这样他会吃掉很多的 CPU、Memory、IO 等资源，导致其他用户很轻量级的 SQL 操作都可能会变得很慢，影响到其他用户实际的体验。那么针对这种情况怎么做隔离？与此类似的还有，网络带宽怎么做隔离？大家都是跑在一个云数据库上面的，如果一个用户存放的数据特别大，他把带宽都吃掉了，别人就显得非常慢了。\n\n还有一种情况，如果我本身作为一个租户，内部又怎么做隔离，大家知道 MySQL 可以建很多 Database，不同的 Database 给不同的团队来用，那么他们之间内部隔离又怎么做，这个问题就进一步更加复杂了。\n\n目前来讲没有特别好的方法，在一个分布式的环境下面去做很好的隔离，有两个方向可以考虑：\n\n第一种是最简单也是有效的方法，制定一些规则，把某些用户特别大的数据库表迁移到独享的服务器节点上面，这样就不会影响其他用户的服务，但是这里面就涉及到定制化的事情了，本身理念其实与云数据库并不相符。\n\n第二种就是依靠统计信息，做资源隔离和调度，但是这里面对技术的要求就比较高了。因为云数据库是分布式的，所以一般的统计都要横跨很多的机器，因为网络原因，不可能做到完全准确的统计，所有统计都是有延迟的。比如说对于某个用户，现在统计到的流量是 1 个 G，他可能突然就有一次峰值的网络访问，可能下一次统计消耗的流量是 5 个 G（这里面只是举例说明问题），如果你给他流量限制是 1 个 G，中间统计的间隔是多少比较合适，如果间隔比较小，那么这个对整个系统的压力就比较大，可能影响正常的用户 SQL 访问，另外本身这个流量限制的系统也是很复杂的系统。\n\n调度算法一直是整个分布式系统领域很困难的一个问题，如何做到隔离性和公平调度也是未来云数据库非常有挑战的一个事情。\n\n### 低成本\n低成本应该是云时代基础设施最明显的特点。首先，云数据库的高可用和容错能力，使得我们不再需要昂贵的硬件设备，只需要普通的 X86 服务器就可以提供服务。然后，受益于 Docker 的虚拟化技术，使得不同类型的应用容器可以跑在同一个物理机上，这样可以极大地提高资源的利用率。其次，多租户的支持，使得不同的用户可以共用一套底层的数据库存储系统，在数据库层面再一次提高了资源的利用效率。再次，云数据库的自动化运维工具，降低了整个核心数据库的运维成本。最后，云数据库资源是按需分配的，用户完全可以根据自身的业务特点，选购合适的服务资源。\n\n### 高吞吐\n\n云数据库虽然可以做到弹性扩容，但是本身是分布式存储的，虽然可以通过 Batch Write、Pipeline 和 Router Cache 等方式加快访问 SQL 请求的数据，但是相对传统单机的数据库来说，在数据访问链路上至少也要多走一次网络，所以大部分并发量不大的小数据量请求，都会比单机延迟要高一些。也就是说，当没有足够高的并发 SQL 访问的话，其实不能完全体现云数据库的性能优势，所以这也是我们在选用云数据库的时候需要认识到的问题，云数据库更多的是追求高吞吐，而不是低延迟。当并发大到一定规模，云数据库高吞吐特性就显现出来了，即使在很高的并发下，依然可以维持相当稳定的延迟，而不会像单机数据库那样，延迟线性增长。当然，延迟的问题，在合理的架构设计方案下，可以通过缓存的方式得到极大的缓解。\n\n### 数据安全\n云数据库的物理服务器分布在多个机房，这就为跨数据库中心的数据安全提供了最基础的硬件支持。谈到金融业务，大家耳熟能详的可能就是两地三中心，比如北京有两个机房，上海有一个。未来一切服务都跑在云上，金融类的业务当然也不例外。相比其他业务，金融类业务对数据安全要求就要高得多。当然，每个公司内部都有核心的业务，所以如果上云的话，也会有同样的强烈需要。这样，对云数据库来说，数据的一致性、分布式事务、跨数据中心的数据安全等更高端的需求有可能会日益强烈。常见的数据备份也有可能会被其他新的模式所取代或者弱化，比如基于 Paxos/Raft 的多副本方案，本身就保证了会有多份备份。\n\n### 自动负载平衡\n对于云数据库来说，负载平衡是一个很重要的问题，它直接决定了整个云数据库系统性能的好坏，如果一个数据库节点的数据访问过热的话，就需要考虑把数据迁移到其他的数据库节点来分担负载，不然就很容易出现性能瓶颈。整个负载平衡是一个动态的过程，调度算法需要保证资源配比的最大平衡，还有保证数据迁移的过程对系统整体的负载影响最小。这在未来也是云数据库需要解决的一个核心问题。\n\n## 小结\n从目前已有的 SQL 数据库实现方案来看，NewSQL 应该是最贴近于云数据库理念的实现。NewSQL 本身具有 SQL、ACID 和 Scale 的能力，天然就具备了云数据库的一些特点。但是，从 NewSQL 到云数据库，依然有很多需要挑战的难题，比如多租户、性能等。\n\n上面提到的一些云数据库的特点，也是 PingCAP 目前在着力实现的部分，TiDB 作为国内第一个 NewSQL 的开源项目，在与社区的共同努力下，我们在上月底刚刚发布了 Beta 版本，欢迎各位上 GitHub 了解我们。\n\n随着整个社区技术水平的发展和云时代新的业务需求的驱动，除了 PingCAP 的 TiDB，相信会有更多的团队在这方面进行探索， 期待早日看到云数据库成熟的那一天。\n\n## Q&A\n**问：由于客户数据环境复杂多样，在迁移到云端的时候怎么怎么做规划，以便后期统一运维管理？或者说，怎么把用户 SQL Server 或者 MongoDB 逐渐迁移到 TiDB 之类的分布式数据库？**\n**崔秋**：因为每个业务场景都不太相同，所以在选用云端服务的时候，首先要了解自身业务和云服务具体的优缺点。\n如果你的业务本身比较简单，比如你之前用的 MongoDB，现在很多云服务厂商都会提供云端的 MongoDB 服务。这个时候你就要根据业务特点来做判断，如果 MongoDB 本身容量不大，远期的业务数据不会增长过快的话，这个时候其实你可以直接使用 MongoDB 的服务的。但是如果你本身的数据量比较大，或者数据增长比较快的话，就可能要考虑数据的扩容问题，MongoDB 在这方面做的不是太好。\n你可以考虑 SQL 数据库的集群方案。比如 TiDB，它本身是支持弹性扩容，高并发高吞吐和跨数据库中心数据安全的，另外有一点明显的好处是 TiDB 兼容 MySQL 协议，所以如果你的应用程序是使用 MySQL，就基本上可以无缝地迁移到 TiDB，这方面是非常方便的。后续我们会提供常用的数据库迁移工具，帮用户把数据从 MongoDB/SQL Server 等平滑迁移到 TiDB 上面。\n还是那个原则，不要为了上云而上云，一定要了解清楚自己的业务特点，云数据库会帮助你提供很多特性，如果真的很适用你的业务的话，就可以考虑。\n\n**问：但从产品的角度来看，云厂商提供的 RDS 产品是 Copy 客户数据库的思路，或者说是为了支持不同的数据库而支持。请问这种局面以后会有什么改变吗？**\n**崔秋**：现在确实蛮多云数据库服务其实就是在传统的 RDS 上面包了一层自动化的监控，运维和部署工具，就卖给用户提供服务了，但是实际上本身解决的仅仅是自动化管控的问题，云服务提供的数据库特性还是单机的 RDS，或者 RDS Sharing 的特性。如果本身底层的数据库满足不了你的需求的话，云服务也是满足不了的。\n如果你需要不停服务的弹性扩容，单机的 RDS 服务肯定是搞不定的，RDS Sharing 也很难帮助你做到，这就对底层的数据库有了更高的要求，当然这方面是 TiDB 的强项了。\n现在很多云上的 RDS 产品还远远没有达到理想中的云数据库的要求，不过随着社区的发展和业务需求的推动，我个人觉得，这方面最近几年会有更多的变化。如果对于这方面感兴趣的话，可以关注下 TiDB。\n\n**问：从 Oracle 分流数据到 TiDB、Oracle 增量修改、Update 的记录，如何同步到 TiDB？有没有工具推荐，比如类似 Ogg？**\n**崔秋**：目前 TiDB 还没有相应的工具。如果真的需要在线从 Oracle 这边分流的话，可以考虑使用 Oracle 的触发器，将数据的变化记录下来，然后转化为 SQL，同步到 TiDB，当然这需要一定开发的工作量。","date":"2016-08-02","author":"崔秋","fillInMethod":"writeDirectly","customUrl":"cloud-native-db","file":null,"relatedBlogs":[]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}