17PostgreSQL shared nothing分布式用法讲解|学习笔记(一 )

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
网络型负载均衡 NLB,每月750个小时 15LCU
简介: 快速学习17PostgreSQL shared nothing分布式用法讲解

开发者学堂课程【PostgreSQL快速入门17PostgreSQL shared nothing分布式用法讲解】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/16/detail/76


17PostgreSQL shared nothing分布式用法讲解


内容介绍:

一、数据库的异地分区

二、PL/Proxy 应用场景举例

三、PL/Proxy 的使用背景

四、PL/Proxy 的原理

五、PL/Proxy 的安装使用

六、PL/Proxy 的使用

七、小测试

八、PL/Proxy 使用注意事项


上节课学习了 PostgreSQL 的本地分区,本节课学习 PostgreSQL 的异地分区,并以 PL/Proxy 为例学习shared nothing 数据分区的部署,了解其应用场景设计,学习其原理、安装方式,并以实例的方式学习如何配置代理库、编写代理函数以及实体函数。


一、数据库的异地分区

异地分区与分布式数据库在概念上十分相近,是 shared nothing 的数据分区,即在一个节点中存储的数据只是整个数据的一部分,所有的节点存储的数据之和才是一份完整的数据。异地分区的方法很多,如通过中间件来实现,像PL/Proxy、PgBouncer、Pgpool 等支持 shared nothing 数据分区的。

本节课以 PL/Proxy 为例来学习数据库的异地分区,PL/Proxy 是一个比较小的软件,其代理节点本身支持无缝扩展,节点也是支持无缝扩展的插件。


二、PL/Proxy 应用场景举例

1、Shared nothing(run on any|nr|hash)+Replication (语句级复制,run on all)+Load Balance(run on ANY|NR\HASH)

(1)Shared nothing 数据分区

若要使用PL/Proxy的方式来实现 Shared nothing 数据分区,则要依靠 PL/Proxy 中的语法:run on any|nr|hash,其中“nr”是一个数字,若分区数为4,则nr为0、1、2、3,“run on 0”即指定在0号节点运行,“run on 3”即指定在3号节点运行;“hash”是指一个哈希函数,其只要返回一个int类型,如 int2、int4或 int8,若返回一个哈希数字,通过数字再与节点数做比特微运算,若有四个节点,则比特微运算的结果也是0-3之间的数字,运营在指定的节点;run on any 是指在所有的数据节点里随机执行。

(2)replication 模式

若处于 replication 模式,依靠 replication(语句级复制,run on all)。对于一个数据存储量较小的表,要使得所有的节点都有一份相同的拷贝,可以使用 run on all,即在所有的节点都执行,比如可以使 insert 语句或 select 语句在所有的节点都执行。比如,数据已经完成分布,要查询所有的数据,则可以使用 select 语句+run on all,同样对于分节点(在某一个/某几个/任一节点)也适用。

(3)Load Balance

Load Balance 与 Shared nothing 用法相同,依靠 run on ANY|NR|HASH。

如果是某一份数据,如某一个表尤其是数据量较小的表,在所有的节点都相同,则可以使用 run on ANY|NR|HASH 随机或指定选择在节点执行来实现 Load Balance。

以下为其架构示意图:

image.png

应用程序连接代理节点,代理节点实际上是数据库代理函数,只是该函数是使用 PL/Proxy 语言编写的,代理节点下方才是真正的数据节点,其中包含实际函数。图上显示分了四个数据节点p0、p1、p2、p3。联系上方应用场景对应的语法,在代理节点中用 PL/Proxy 语言编写了一个函数,函数中包括 run on any,则在调用函数时,就会随机的在四个节点里面选一个节点执行该函数。真正的数据节点中编写的才是实际函数,而实际的函数 plpgsql 可以 plpython或其他语言编写,而代理函数必须使用 plproxy 语言编写,是专门的 plproxy 插件,它支持一种语法。

plproxy 本身可以无限扩展,可以完全独立,比如使用了两个 plproxy,当其中一个 plproxy 不运行时,可以用程序将它连到另外的 plproxy。只要 plproxy 之间他的代理函数定义相同即可,因为代理节点(代理函数)中不存储实际的数据,只存储代理函数。而 plproxy 不承担运算,因此不容易成为瓶颈,当然也不是绝对的,如部分运算需要下面真正的数据汇聚上来之后再来做一些聚合,这种情况下,plproxy 也会承担一定的运算量,如要 count 所有的数据,则需要所有节点的数据 count 之后,再将所有 count 的结果相加。当然即使 plproxy 要承担一定的运算量,这种运算量也很小。

数据层支持2n 个节点,同时也支持无限扩展,如要将4个节点扩展,就只能扩成8个、16个节点等,即该扩展的数值一定是2n。因为若为 run on hash,返回的hash数值要与的节点数作比特微运算,这就限定了扩展节点的数值是种是2n 个。该算法在代码中是确定的,当然也可以修改,如要支持5个节点,而像这种支持的节点数不是2n 的情况,同样可以,只是 run on hash 算法会更复杂,效率更低,而支持节点数为2n 个的情况比特微运算的效率很高,因此,建议使用支持2n个节点的应用场景。

2、Replication(流复制)+Load Balance(读写分离,读 run on  any|nr|hash,写 run on 0)

该应用场景同样支持2n 个节点,但其所有的节点的数据是一致的。以下为其架构示意图(展示支持4个节点):

image.png

若使用 Replication(流复制),则p0是主节点,s1、s2、s3是该主节点的复制节点。

复制节点可以做读写分离,“读”可请求,可以使用 run on  any 或 run on nr 或 run on hash 指定在某个节点执行。对于“写”,可以使用 run on 0写入节点,该节点即 run on nr 中的0号节点,也就是 p0节点。写的数据要写到p0节点,读的数据可以随机指定。这样即可使用 PL/Proxy 实现读写分离的场景。


三、PL/Proxy 的使用背景

1、PL/Proxy 的解决方案是水平扩展,对硬件的要求不高,由于是水平扩展,因此对于单个节点的硬件投入较低,还可以计算其投入产出比。如将4个节点扩展成8个节点,性能可以翻倍,同理,8个节点扩展为16个节点,性能也翻倍。

2、PL/Proxy 可以通过调用 PostgreSQL 函数来支持事务。在 PostgreSQL 中,函数操作具有原子性,因此需要用到事务的操作可以封装到 PostgreSQL 函数当中。PL/Proxy 其实上是通过函数来实现交互的,如使用 plproxy 编写了代理函数,代理函数可以指定运行的节点,而“运行”的过程还是在指定的节点中调用函数。在默认情况下,函数名会与同一 scheme下面同样的函数名称相同。

如有一函数为 function a,那么在调用该函数时,指定 run on 0,实际上会在调用p0节点数据库中 function a(PostgreSQL 语言编写)的同时,将函数的结果返回代理函数,再返回给 app。

总之,所有节点的函数操作都是原子性的,要么将整个函数都提交,要么全部回滚,因此其可以很好地支持节点上面事务操作。

PL/Proxy 路由选择非常灵活,非常容易做到读写的负载均衡。

PL/Proxy 与 PostgreSQL 都是免费的,PL/Proxy 的许可也是弹性的,可以复制使用,可以开源也可以闭源。

PL/Proxy 的耦合度不高。因为P L/Proxy 本身没有处理逻辑,它真正的处理逻辑都写在数据节点里的实际函数中,如果不使用代理节点了,就可以将它破坏直接通过直联数据库调用函数,与使用代理的效果相同。

调用函数的好处:

安全性提高,因为应用连接代理数据库,而非直连数据库,并且 PL/Proxy 语言只有超级用户可以编写,即超级用户写好函数之后,可以将函数的调动权限赋给普通用户,而应用程序通过普通用户再调用函数。

也就是其只有调用函数的权限,而没有编写函数的权限,可以隐藏掉一些实际操作的,如可以隐藏直连数据库的操作,这些具体操作数据库的程序无法获取,即使遭受恶意攻击,攻击者也只能获取已经存在的函数,而无法自行创立函数直连数据库进行操作。

业务逻辑代码放在数据库端,当数据经过处理之后可以直接发布至用户,减少交互,使处理效率更高。但前提是在数据库的处理能力足够的情况下,当数据库的处理能力不足的情况下,可以把数据提取出来在app端进行逻辑处理。


四、PL/Proxy 的原理

PL/Proxy 的原理分三个层次:PL/Proxy 节点(s)、连接池(s)与数据节点(s)。其中连接池(s)可以隐藏。

1、PL/Proxy 节点(s)

实际上就是的 PL/Proxy 层。

负责接收应用程序发取请求,即调用plproxy编写的函数;(2)负责解析提交给数据节点的 SQL。

如使用 PL/Proxy 函数,函数书写方式为:CREATE FUNCTION get_date(IN first_name text, IN last_name text, OUT bdate date, OUT balance numeric(20,10)),其中IN first_name text、 IN last_name text是传入参数, OUT bdate date、OUT balance numeric(20,10)是输出参数。

PL/Proxy 调用函数时,会将其解析成:SELECT bdate::date, balance:: numeric(20,10) FROM public.get_date(S1::text, S2::text),即将其转成其中的“OUT”,以上函数中输出值为 date 类型,若该函数写在 public 下面,那么就会在数据节点调用函数,S1与S2指的是两个传入的变量;最终显示 Explicite 的类型转换,指定输出顺序。

即在应用程序调用 PL/Proxy 函数时,PL/Proxy 代理节点会将其解析,在实际的数据节点运行,比如要在 p0节点运行,就将解析结果语句交给 p0节点,p0节点处理数据之后,再返回给 PL/Proxy,进而返回给应用程序。

如果是 run all,则是一个异步的过程,直接把 sql 语句传给所有的数据,而不是在一个节点返回数据之后,再传给另一节点,这是一个并行的过程。当接收到数据节点返回的数据后就直接输出给用户,这也是一种异步的输出。

(3)PL/Proxy 支持旁路模式(CONNECT 模式)或选择数据节点(CLUSTER 模式)。使用旁路模式后,后期不直接交给数据节点函数,而是在 PL/Proxy 函数中写入 SELECT 语句,该 SELECT 语句是真正传递给数据节点的是 SELECT 语句,而不是传入函数的方式,这就是旁路模式。而非航路模式是指在数据节点也必须要有对应的实际操作的函数。

(4)CLUSTER 模式分为两种,一种是它的集群是存储在 SQL/MED 配置的集群信息里,选择数据节点是通过Libpq asyne API 异步 API 发送解析的 SQL 给节点。由于其调用的是异步接口,因此执行run all 是 SQL 语句的发送是多个并行的,待数据节点返回结果后,再发送至应用程序;另一种其配置不在 SQL/MED 中,而是由,而由 PL/Proxy 自行存储配置信息,有其专门的配置表,其中有专门的配置缓存的函数。除了配置信息的不同,其余与第一种模式相同

2、连接池(s)

简单来说,PL/Proxy 层和数据库之间是长连接,两者之间可以加连接池,也可以不加连接池。

在正常情况下,如果应用程序与数据库节点之间是短连接,如应用程序连到 PL/Proxy 调用函数获取函数结果之后就断开了连接,如果下次数据获取再重新连接,反复连接--断开,就会导致 PL/Proxy 与数据库节点之间有断开连接-重新连接的过程。如果应用程序与数据库节点之间是长链接,用户连在连接池上,PL/Proxy 与数据库的连接就不会断开,即只要会话存在,应用程序与数据库连接就不会断掉。且连接时间可以配置,如可以配置最长生存时间是1800秒,那么只要会话存在,这1800秒之内连接都不会断掉,后面如果要进行查询就不需要再重新建立连接。

但是对于短连接,只要断开,PL/Proxy 跟数据库之间的节点也断开。因此如果应用程序与数据库节点之间是短连接,则建议在应用程序和 PL/Proxy 之间加连接池,而不是加在 PL/Proxy层和数据库之间,因为 PL/Proxy 层和数据库之间本身本身就是一种长连接,没必要另加。

PL/Proxy2.x 之后的代理和连接池模块都拆掉了,因此,PL/Proxy 不依赖连接池或连接池的类型。

3、数据节点(s)

数据节点存放实际的数据与实际的函数,实际函数可以使用 plpgsql 语言编写,也可以用其他语言编写,如plpython、pljava 等。数据节点负责接收来自于 plproxy 发起的 SQL 请求,并把执行结果的返回给 plproxy。

各种函数的用法:

plproxy 函数的用法

①旁路模式,即不使用代理函数,直接在代理函数中编写 SQL 语句,并将其直接传递给数据节点,而不经过代理函数翻译。

②集群模式,即使用代理函数,应用程序的传递参数给代理函数,将代理函数解析成 SELECT 的 SQL 语句,再传给数据节点执行。具体的使用方法会在后面的案例中进行实际操作。

plproxy 函数的的语法

目前仅支持以下几种语法:

①CONNECT  

CONNECT 'libpq connstr'; | connect_func(...) | argname

不使用种集群配置,直接使用connect连接数据节点,其后使用'libpq connstr'字符串或 connect_func(...)连接函数或argname,如配置 host=...,port=...,use=..., password=...,即指定连接的位置。

CLUSTER, [RUN ON ALL|ANY|int 2,4,8|NR]

CLUSTER 'cluster name'; | cluster_func(...)

集群模式,指定 cluster 的名字或 cluster 函数(不使用 SQL/MED 存储)。指定完成后,选择 RUN ON,RUN ON NR指运行节点,RUN ON HASH函数返回int类型即可,RUN ON ALL 是在所有节点运行,RUN ON ANY 是在任意节点运行。若该集群种有4个连接,则 RUN ON ALL 会在4个连接里都发起 SQL 请求。

③SELECT(CONNECT+SELECT 旁路模式)

不使用 RUN ON 选择运行的节点,而是直接连接然后进行 SELECT④SPLIT

指当传入的参数是数组时,可以按元素分组拆分,减少 plproxy 和程序端的交互,比如传入的参数是数组[1,2,3,4,5,6],即其对应的是 useID,只要查询数组对应的 useID 传给函数,函数就会进行拆分,即将这6个元素封装成一个数组传给代理函数,代理函数使用 SPLIT 语法将元素分组拆分,分六次传给数据节点,而无需将每个元素对应的useID 参数传到数据节点,每传入一个参数调用一次,即整个过程只需要 plproxy 和程序交互一次。

⑤TARGET

当代理函数和节点函数不同名或 schema 不同时,可以使用 target 来指定。如代理函数是放在 schema A下,但实际的数据数据的函数却存储在 schema B下,在调用函数时,如果不使用 target 语法,则默认调用数据节点 schema A下的函数,直接报错,而使用 target 就可以解决该问题,target 是 a.function_name,在调用时就可指定调用该target 下的 function_name,而非默认的。

⑥run on

tag_run_on_partitions(ProxyFunction *func, FunctionCallInfo fcinfo, int tag, DarunArray **array_parans, int array_row)

(

ProxyCluster  *cluster = func->cur_cluster;

int  i;

switch (func->run_type)

(

case R_HASH:

tag_hash_partitions(func, fcinfo, tag, array_parans, array_row);

break;

//使用HASH函数得到数字,即运行的节点

case R_ALL:

for (i = 0; i< cluster->part_count; i++)

cluster->part_nap[i]->run_tag =tag;

break;

//其实是for循环,即所有的节点都要运行

case R_EXACT:

i =func->exact_nr;

//指定运行的节点 nr

if (i < 0 ::i >= cluster->part_count)

plproxy_error(func, “part nunber out of range");

cluster->part_map[i]->run_tag=tag;

break;

//此处存在判断语句,当i<0或i ≥集群的节点数时,则系统报错

如果有4个数据节点,输入小于0以及大于或等于4的值,都会

报错,即只有输入0、1、2、3才不会报错。

case R_ANY:

i = randon() & cluster->part_mask;

cluster->part nap[i]->run_tag=tag;

break;

//随机指定运行的节点

default:

plproxy_error(func, "uninitialized run_type");

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
关系型数据库 开发工具 C语言
PostgreSQL libpq开发入门
简单入门C语言开发基于PostgreSQL libpq应用
|
SQL 存储 缓存
PG内核解读-第2节PostgreSQL体系结构
本文整理自阿里云数据库开源社区Maintainer于巍(花名漠雪),在PostgreSQL数据库内核解读系列的分享。本篇内容主要分为三个部分: 1. PostgreSQL系统表 2. PostgreSQL初始化、启动、查询流程 3. PostgreSQL辅助进程
PG内核解读-第2节PostgreSQL体系结构
|
6月前
|
监控 关系型数据库 数据库
PostgreSQL和greenplum的copy命令如何使用?
【6月更文挑战第5天】PostgreSQL和greenplum的copy命令如何使用?
177 2
|
关系型数据库 PostgreSQL
PostgreSQL pg_orphaned扩展
由于种种原因,PostgreSQL可能会产生一些孤儿文件,这些文件会占用磁盘空间,手工查找费时费力还容易出错,pg_orphaned扩展很好的解决了这个问题。
|
关系型数据库 PostgreSQL
PostgreSQL VFD机制
PostgreSQL VFD机制
121 0
PostgreSQL VFD机制
|
7月前
|
SQL 监控 关系型数据库
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
191 0
|
存储 关系型数据库 PostgreSQL
Postgresql内核源码分析-heapam分析
Postgresql内核源码分析-heapam分析
193 1
|
存储 算法
图解PostgreSQL-buffer管理(二)
图解PostgreSQL-buffer管理(二)
145 0
|
存储
图解PostgreSQL-buffer管理(三)
图解PostgreSQL-buffer管理(三)
89 0
|
关系型数据库 PostgreSQL
PostgreSQL pg_resetwal处理机制
PostgreSQL pg_resetwal处理机制
183 0