当前位置: 首页 > 科技观察

GoogleCloudSpanner实战心得

时间:2023-03-16 18:54:43 科技观察

CloudSpanner是GoogleMegastore系统的继任者,Spanner展现出了远超其前辈的能力。Spanner最早出现在谷歌内部数据中心,直到2017年才发布了beta版本并增加了SQL能力。现已上线谷歌云平台,在各行业拥有大量用户。CloudSpanner数据库是一个全球分布的关系型/事务型数据库,Google承诺CloudSpanner具有高吞吐量、低延迟和99.999%的高可用性。接触CloudSpanner第一次接触GoogleCloudSpanner是因为客户对新技术的追求和实验,我们把我们基本完成的API从原来的GoogleCloudSql迁移到了CloudSpanner数据库。客户在做这个决定时,考虑到公司的用户量正处于快速增长阶段,业务不断变化,需要改变表结构来适应业务的需要。所以我决定使用GoogleCloudSpanner来保证数据的ACID(原子性、一致性、隔离性和持久性),数据库仍然可以水平扩展和分布式。与主流云服务关系型数据库,如AWS的Aurora、GCP的CloudSQL、Azure的SQLDB相比,选择CloudSpanner不具备多节点扩展功能,只能在单节点垂直扩展。(增加RAM或CPU数量)。如果要实现水平扩展,可以使用NoSQL数据库,如HBase、MongoDB、DynamoDB或BigTable。但是这些数据库很难实现事务的特性,不能支持关系数据库所支持的功能,比如连接表。并且由于NoSQL查询语句与关系数据库语句有很大的不同,应用中的大量查询语句和表结构将需要重写。与这些数据库服务不同,CloudSpanner是一个独特的数据库。它将事务、SQL查询和关系结构与NoSQL数据库的可扩展性相结合。因此,CloudSpanner兼具SQL和NoSQL数据库结构的优点。CloudSpanner一开始是为存储NoSQL键值对而设计的,但随着它对关系模型需求的加入,CloudSpanner逐渐打破了NoSQL和SQL数据库之间的壁垒。特性作为一个分布式数据库,Spanner的每个实例都运行在不同数量的节点上,每个节点都由谷歌云平台服务自动管理。因此,CloudSpanner具有很高的可扩展性,可以根据请求负载和数据大小自动拆分(split),为系统提供更多的弹性空间。作为关系型数据库,CloudSpanner支持关系型数据库的所有功能,但CloudSpanner并不完全是关系型数据库,虽然Spanner的数据模型与其他关系型数据库基本相似,预定义的数据元组可以存储在关系(表)中并进行查询,但它缺乏约束。CloudSpanner有主键的概念,必须为每个表定义一个主键,并且主键必须是唯一的。但是,它没有外键的概念,而是交错的。在关系数据库中,我们期望强大的数据完整性来确保满足预定义的约束。CloudSpanner在这方面的能力有限。事务支持(ACID)CloudSpanner对事务提供最严格的并发控制,实现全局事务的外部强一致性。在外部一致性的保证下,即使CloudSpanner实例运行在多个数据中心,也可以在高性能和高可用的前提下顺序执行事务。借助TrueTime的特性,CloudSpanner可以实现外部一致性。TrueTime是谷歌为所有谷歌服务提供的高可用分布式时钟。该时钟为应用程序提供单调递增的时间戳。CloudSpanner使用TrueTime的这个特性来为事务分配时间戳。具体来说,每个事务都分配有一个时间戳,它为CloudSpanner提供事务发生的时间。其他功能CloudSpanner具有许多其他功能,包括单区域和多区域配置、多语言支持等。数据结构CloudSpanner的数据模型与传统的RDBMS基本相同。它们由行、列和值组成,并包含主键。CloudSpanner中的数据是强类型的。每个表需要定义一个schema,每一列的数据需要指定一个数据类型。其中,主键(PRIMARYKEY)定义在表模式之外。数据的分布是通过主键实现的。因此,在选择主键时,需要尽可能避免CloudSpanner服务的热点(Hotspots)。时间戳或自增序列号会导致热点。CloudSpanner建议使用随机(用户名等)信息或UUID作为主键。交错表(Interleavedtables)在CloudSpanner中,没有办法定义两个表之间的外键(FOREIGNKEY)关系。但是CloudSpanner引入了一个类似的概念——交错表。上面的模式表示为客户表创建帐户子表或“交错”表。注意事项:(1)customer_id是子表accounts的主键之一,也是父表customers的主键。accounts声明为customers子表时,必须添加主键,命名、类型、限制条件必须一致。(2)插入子表时,需要保证父表有对应的行(即以相同父表主键开头的行)。(3)删除父表行需要满足以下两点之一:子表中没有对应行。删除级联状态。(4)ONDELETECASCADE语句表示当父表中的一行被删除时,子表中对应的行也将被自动删除。如果没有这样的语句,或者语句是ONDELETENOACTION,则必须先删除子行,然后才能删除父行。(5)交错行先按父表行排序,再根据父表共享主键对子表重新排序。(6)分库时,只要父表行和子表行的大小在8GB以内,且子表行不存在热点,每个父表的数据存储区和子表关系保存在一起。交错表的主要目的是加快某些查询操作,尤其是涉及JOIN的查询操作。因为交错表直接改变了数据在云端的布局方式,保证了在执行JOIN操作时不会访问到集群的每个节点(Nodes)。二级索引:在CloudSpanner中,主键自动设置为表的索引。CloudSpanner还支持将其他非主键字段设置为二级索引。UNIQUEINDEX关键字表示索引将强制字段在插入时是唯一的。在极少数情况下,CloudSpanner可能会自动选择增加查询延迟的索引。在这种情况下,您可以使用FORCE_INDEX关键字为查询操作提供指定的索引。数据库碎片(拆分)在表之间。CloudSpanner最多支持七级父子关系,即七张逻辑上独立的表的行可以在物理上存储在一起。当相关表数据不断增长,达到单个CloudSpanner服务器的资源极限时,CloudSpanner作为分布式数据库,将数据划分为“拆分”块,每个块可以独立移动,分配到不同的物理多个服务器在不同的位置。拆分由一系列具有开始和结束键的连续行组成,称为“拆分边界”。CloudSpanner会根据大小和/或负载自动添加和删除分片边界,这样做会改变数据库中分片的数量。基于负载分片当数据库中某个表上的10行数据比表中所有其他行的读取频率更高时,CloudSpanner会为这10行中的每一行添加分片边界,以便每行由不同的服务器处理,以防止这10行数据的读写操作只消耗单台服务器的资源(避免热点)。表结构更新Cloudspanner支持对现有数据库模式进行以下更新操作:创建新表。新表中的列可以为NOTNULL。删除一个表,前提是该表中没有其他表交错且没有二级索引。向任意表添加一个非主键列,新的非主键列不能为NOTNULL。将NOTNULL添加到非主键列,不包括ARRAY列。从非主键列中删除NOTNULL。从任何表中删除非主键列,前提是该列未被二级索引使用。将STRING列更改为BYTES列,或将BYTES列更改为STRING列。增加或减少STRING或BYTES类型的长度限制,前提是它不是一个或多个子表继承的主键列。在值和主键列中启用或禁用提交时间戳。添加或删除任何二级索引。未来的趋势是基于CloudSpanner独特的结构,可以保证客户从小规模起步,不用担心未来数据量和业务量增加后需要迁移或重写数据库用户群和业务量的问题。CloudSpanner在保证关系型数据库管理系统特性的前提下,还提供了数据库的超强扩展性,可以在一定情况下更新已有表的结构。因此,无论应用程序的大小,CloudSpanner都会是一个不错的选择,它可以为应用程序提供包括事务支持、高可用性保证、只读副本和易于扩展的功能。在一文中介绍,CloudSpanner的总成本比本地数据库服务低78%,比其他云平台数据库服务低37%。这是因为CloudSpanner确保了数据库的高可用性,而不需要用户为额外的复制服务付费。并且由于CloudSpanner支持用户在不停机的情况下水平或垂直扩展数据库(CloudSpanner自动管理数据切片和数据复制)或更新表结构,例如添加索引。同时也说明CloudSpanner在经济性上也提供了比自己维护的数据库服务更低的成本。