沉浸式学习PostgreSQL|PolarDB 7: 移动社交、多媒体、内容分发、游戏业务场景, 跨地域多机房的智能加速

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: 在移动社交、多媒体、内容分发业务场景中, 如果用户要交互的内容都在中心网络(假设深圳), 现在用户流动非常频繁, 当用户从深圳出差到北京, 因为网络延迟急剧增加, 他的访问体验就会变得非常差.网络延迟对游戏业务的影响则更加严重.为了解决这个问题, 企业会将业务部署在全国各地, 不管用户在哪里出差, 他都可以就近访问最近的中心.由于标记用户的只有IP地址, 怎么根据用户的接入IP来判断他应该访问哪个中心呢? 通过这个实验, 大家可以了解到在数据库中如何存储IP地址范围和各中心IDC的映射关系, 以及如何根据用户的来源IP(接入IP)来判断他应该去哪个中心IDC访问.

作者

digoal

日期

2023-08-28

标签

PostgreSQL , PolarDB , 数据库 , 教学


背景

欢迎数据库应用开发者参与贡献场景, 在此issue回复即可, 共同建设《沉浸式数据库学习教学素材库》, 帮助开发者用好数据库, 提升开发者职业竞争力, 同时为企业降本提效.

  • 系列课程的核心目标是教大家怎么用好数据库, 而不是怎么运维管理数据库、怎么开发数据库内核. 所以面向的对象是数据库的用户、应用开发者、应用架构师、数据库厂商的产品经理、售前售后专家等角色.

本文的实验可以使用永久免费的阿里云云起实验室来完成.

如果你本地有docker环境也可以把镜像拉到本地来做实验:

x86_64机器使用以下docker image:

ARM机器使用以下docker image:

业务场景1 介绍: 移动社交、多媒体、内容分发、游戏业务场景, 跨地域多机房的智能加速

在移动社交、多媒体、内容分发业务场景中, 如果用户要交互的内容都在中心网络(假设深圳), 现在用户流动非常频繁, 当用户从深圳出差到北京, 因为网络延迟急剧增加, 他的访问体验就会变得非常差.

网络延迟对游戏业务的影响则更加严重.

为了解决这个问题, 企业会将业务部署在全国各地, 不管用户在哪里出差, 他都可以就近访问最近的中心.

由于标记用户的只有IP地址, 怎么根据用户的接入IP来判断他应该访问哪个中心呢? 通过这个实验, 大家可以了解到在数据库中如何存储IP地址范围和各中心IDC的映射关系, 以及如何根据用户的来源IP(接入IP)来判断他应该去哪个中心IDC访问.

实现和对照

1、设计一张IDC元数据表, 存储IDC的基本信息.

create table tbl_idc (  
  id int primary key,   -- 主键   
  info text    -- 随便输入一些信息, 这个字段和这个实验无关, 不影响这个实验的核心目标   
);     
-- 写入100个IDC数据  
insert into tbl_idc select generate_series(1,100), md5(random()::text);

2、下载(或购买)IP地址库.

参考这篇文章的方法, 得到一张IP地址库表. 《如何获得IP地址对应的地理信息库, 实现智能DNS解析? 就近路由提升全球化部署业务的访问性能》

su - postgres  
curl http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest -o src.html   
grep "^apnic|CN|ipv4" src.html > ./cn.csv    
./duckdb -c "copy (select column3, (32-log2(column4::int))::int from '/var/lib/postgresql/cn.csv') to '/var/lib/postgresql/ip2region.csv' with (delimiter '/')"
vi c.sh    
#!/bin/bash    
for line in $(cat /var/lib/postgresql/ip2region.csv)    
do    
  # echo $line    
  echo "${line},`curl -s http://whois.pconline.com.cn/ip.jsp?ip=${line}|iconv -f GBK -t UTF8|grep -v "^$"|awk '{print $1","$2}'`"    
done
. ./c.sh  >./c.csv

得到类似这样的信息:

43.226.64.0/22,辽宁省大连市,电信  
43.226.68.0/22,辽宁省大连市,电信  
43.226.72.0/22,辽宁省大连市,电信  
43.226.76.0/22,辽宁省大连市,电信  
43.226.80.0/22,辽宁省大连市,电信  
43.226.84.0/22,辽宁省大连市,电信  
43.226.88.0/22,辽宁省大连市,电信  
43.226.92.0/22,辽宁省大连市,电信  
43.226.96.0/22,江苏省常州市,电信  
43.226.100.0/22,江苏省常州市,电信  
43.226.104.0/22,江苏省常州市,电信  
43.226.108.0/22,江苏省常州市,电信

导入postgresql|polardb

psql   
create table tbl_iprange (  
  id serial primary key,  -- 主键   
  ipr inet,  -- ip地址段   
  loc text,  -- 物理地址   
  provider text  -- 运营商   
);   
copy tbl_iprange(ipr,loc,provider) from '/var/lib/postgresql/c.csv';

3、根据IP地址库的地理位置信息, 整理维护一份属于自己的IP地址范围对应IDC的表.

create table tbl_idc_iprange (  -- IP地址范围对应IDC的表  
  id int primary key,  -- 主键   
  ipr inet,  -- ip地址段   
  loc text,  -- 物理地址   
  provider text,  -- 运营商   
  idcid int references tbl_idc(id)  -- idc id, 随便输入, 不影响测试   
);   
insert into tbl_idc_iprange select *, ceil(random()*100) from tbl_iprange;

4、根据用户的来源IP(移动端接入地址通常是基站IP)

本实验会使用三种方法来实现.

传统方法 设计和实验

传统数据库没有IP类型, 也没有iprange类型, 所以需要将IP地址段拆成2个int8字段来存储IP地址段的开始和结束地址.

create table tbl_idc_iprange_int8 (  
  id int primary key,  -- 主键   
  ipstart int8,  -- ip地址段开始地址  
  ipend int8,  -- ip地址段结束地址  
  loc text,  -- 物理地址   
  provider text,  -- 运营商   
  idcid int references tbl_idc(id)  -- idc id, 随便输入, 不影响测试   
);

创建一个函数, 将inet类型转换为int8类型

create or replace function ip2int8 (inet) returns int8 as $$  
select ('b'||  
  split_part($1::text,'.',1)::int::bit(8)::text||  
  split_part($1::text,'.',2)::int::bit(8)::text||  
  split_part($1::text,'.',3)::int::bit(8)::text||  
  (split_part(split_part($1::text,'.',4),'/',1))::int::bit(8)::text)::bit(32)::int8;  
$$ language sql strict;

将ip开始和结束值转换为int8 , 写入测试表.

insert into tbl_idc_iprange_int8   
select id,  
ip2int8(network(ipr)),  
ip2int8(broadcast(ipr)),  
loc,  
provider,  
idcid  
from tbl_idc_iprange;

创建索引

create index on tbl_idc_iprange_int8 (ipstart, ipend);

根据用户的来源IP(移动端接入地址通常是基站IP). 假设来源来源ip是202.101.172.35 : 3395660835

select * from tbl_idc_iprange_int8 where ipstart < 3395660835 and ipend > 3395660835;   
  id  |  ipstart   |   ipend    | loc | provider | idcid   
------+------------+------------+-----+----------+-------  
 6924 | 3395649536 | 3395665919 |     |          |     4  
(1 row)  
postgres=# explain analyze select * from tbl_idc_iprange_int8 where ipstart < 3395660835 and ipend > 3395660835;  
                                                                          QUERY PLAN                                                                             
---------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Index Scan using tbl_idc_iprange_int8_ipstart_ipend_idx on tbl_idc_iprange_int8  (cost=0.28..85.71 rows=1 width=88) (actual time=0.385..0.388 rows=1 loops=1)  
   Index Cond: ((ipstart < '3395660835'::bigint) AND (ipend > '3395660835'::bigint))  
 Planning Time: 0.322 ms  
 Execution Time: 0.426 ms  
(4 rows)

编写压测脚本进行压力测试

vi t1.sql    
select * from tbl_idc_iprange_int8 where ipstart < 3395660835 and ipend > 3395660835;   
pgbench -M prepared -n -r -f ./t1.sql -P 1 -c 10 -j 10 -T 120

压测结果

transaction type: ./t1.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 10  
number of threads: 10  
duration: 120 s  
number of transactions actually processed: 7666686  
latency average = 0.156 ms  
latency stddev = 0.084 ms  
initial connection time = 19.873 ms  
tps = 63899.196660 (without initial connection time)  
statement latencies in milliseconds:  
         0.156  select * from tbl_idc_iprange_int8 where ipstart < 3395660835 and ipend > 3395660835;  
TPS: 63899.196660

PolarDB|PG新方法1 设计和实验

PolarDB和PG都支持inet类型, 可以直接使用IP地址进行范围判断.

create table tbl_idc_iprange (  
  id int primary key,  -- 主键   
  ipr inet,  -- ip地址段   
  loc text,  -- 物理地址   
  provider text,  -- 运营商   
  idcid int references tbl_idc(id)  -- idc id, 随便输入, 不影响测试   
);   
-- 创建inet的spgist索引.  
create index on tbl_idc_iprange using spgist (ipr);

根据用户的来源IP(移动端接入地址通常是基站IP). 假设来源来源ip是202.101.172.35 : 3395660835

select * from public.tbl_idc_iprange where ipr >>= '202.101.172.35';  
  id  |       ipr        | loc | provider | idcid   
------+------------------+-----+----------+-------  
 6924 | 202.101.128.0/18 |     |          |     4  
(1 row)  
postgres=# explain analyze select * from public.tbl_idc_iprange where ipr >>= '202.101.172.35';  
                                                                QUERY PLAN                                                                  
------------------------------------------------------------------------------------------------------------------------------------------  
 Index Scan using tbl_idc_iprange_ipr_idx on tbl_idc_iprange  (cost=0.15..2.37 rows=1 width=79) (actual time=0.070..0.072 rows=1 loops=1)  
   Index Cond: (ipr >>= '202.101.172.35'::inet)  
 Planning Time: 0.371 ms  
 Execution Time: 0.117 ms  
(4 rows)

编写压测脚本进行压力测试

vi t2.sql  
select * from public.tbl_idc_iprange where ipr >>= '202.101.172.35';  
pgbench -M prepared -n -r -f ./t2.sql -P 1 -c 10 -j 10 -T 120

压测结果

transaction type: ./t2.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 10  
number of threads: 10  
duration: 120 s  
number of transactions actually processed: 32939025  
latency average = 0.036 ms  
latency stddev = 0.025 ms  
initial connection time = 21.646 ms  
tps = 274540.956059 (without initial connection time)  
statement latencies in milliseconds:  
         0.036  select * from public.tbl_idc_iprange where ipr >>= '202.101.172.35';  
TPS: 274540.956059

PolarDB|PG新方法2 设计和实验

很显然使用了spgist后性能得到了飙升. 如果用户最初设计的表结构并未使用inet类型, 那么可以使用表达式索引来支持该能力.

使用传统方法的表结构, 将字段转换为int8range类型, 然后使用范围类型索引加速范围检索.

create index on tbl_idc_iprange_int8 using gist (int8range(ipstart,ipend));
select * from tbl_idc_iprange_int8 where int8range(ipstart,ipend) @> 3395660835;  
  id  |  ipstart   |   ipend    | loc | provider | idcid   
------+------------+------------+-----+----------+-------  
 6924 | 3395649536 | 3395665919 |     |          |     4  
(1 row)  
postgres=# explain analyze select * from tbl_idc_iprange_int8 where int8range(ipstart,ipend) @> 3395660835;  
                                                                 QUERY PLAN                                                                   
--------------------------------------------------------------------------------------------------------------------------------------------  
 Bitmap Heap Scan on tbl_idc_iprange_int8  (cost=1.58..36.16 rows=43 width=88) (actual time=0.155..0.158 rows=1 loops=1)  
   Recheck Cond: (int8range(ipstart, ipend) @> '3395660835'::bigint)  
   Heap Blocks: exact=1  
   ->  Bitmap Index Scan on tbl_idc_iprange_int8_int8range_idx  (cost=0.00..1.57 rows=43 width=0) (actual time=0.144..0.145 rows=1 loops=1)  
         Index Cond: (int8range(ipstart, ipend) @> '3395660835'::bigint)  
 Planning Time: 0.629 ms  
 Execution Time: 0.269 ms  
(7 rows)  
postgres=# set enable_bitmapscan =off;  
SET  
postgres=# explain analyze select * from tbl_idc_iprange_int8 where int8range(ipstart,ipend) @> 3395660835;  
                                                                         QUERY PLAN                                                                           
------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Index Scan using tbl_idc_iprange_int8_int8range_idx on tbl_idc_iprange_int8  (cost=0.15..38.30 rows=43 width=88) (actual time=0.127..0.129 rows=1 loops=1)  
   Index Cond: (int8range(ipstart, ipend) @> '3395660835'::bigint)  
 Planning Time: 0.212 ms  
 Execution Time: 0.174 ms  
(4 rows)

编写压测脚本进行压力测试

vi t3.sql  
select * from tbl_idc_iprange_int8 where int8range(ipstart,ipend) @> 3395660835;  
pgbench -M prepared -n -r -f ./t3.sql -P 1 -c 10 -j 10 -T 120

压测结果

transaction type: ./t3.sql  
scaling factor: 1  
query mode: prepared  
number of clients: 10  
number of threads: 10  
duration: 120 s  
number of transactions actually processed: 27106165  
latency average = 0.044 ms  
latency stddev = 0.032 ms  
initial connection time = 20.660 ms  
tps = 225923.247074 (without initial connection time)  
statement latencies in milliseconds:  
         0.044  select * from tbl_idc_iprange_int8 where int8range(ipstart,ipend) @> 3395660835;  
TPS: 225923.247074

对照

测试模型 性能指标(TPS)
传统方法int8类型 between and 63899.196660
PG|PolarDB inet类型 >>= 274540.956059
PG|PolarDB int8range 类型表达式索引 @> 225923.247074

传统方法没有IP类型也没有range类型, 使用传统的2字段范围检索, 性能较差.

知识点

inet类型: https://www.postgresql.org/docs/16/datatype-net-types.html

  • 得到ip地址段的开始IP network(inet) AS start_address
  • 得到ip地址段的结束IP broadcast(inet) AS end_address
  • 得到ip地址段的IP split_part(inet::text, '/', 1)
  • 将ip地址转换为int8 ip2int8(inet)

IP地址段匹配: https://www.postgresql.org/docs/16/functions-net.html

int8range类型: https://www.postgresql.org/docs/16/rangetypes.html

表达式索引: https://www.postgresql.org/docs/16/indexes-expressional.html

范围查找: https://www.postgresql.org/docs/16/functions-range.html

gist索引:

spgist索引:

思考

还有什么业务需要通过本实例提供的方法解决网络延迟的问题.

如果是星链网络, 有没有来源IP, 是不是涉及到3维实时计算离哪个基站最近?

参考

《如何获得IP地址对应的地理信息库, 实现智能DNS解析? 就近路由提升全球化部署业务的访问性能》

《PolarDB for PostgreSQL 采用iprange和SPGiST index 实现超光速 - 全球化业务根据来源IP智能DNS路由就近分配本地机房访问, 提升用户体验》

《聊聊between and的坑 和 神奇的解法 - range + gist - 智能DNS解析》

《PostgreSQL 黑科技 range 类型及 gist index 20x+ speedup than Mysql index combine query》

《PostgreSQL 黑科技 range 类型及 gist index 助力物联网(IoT)》

目录
相关文章
|
8月前
|
Cloud Native 关系型数据库 分布式数据库
让PolarDB更了解您--PolarDB云原生数据库核心功能体验馆
让PolarDB更了解您——PolarDB云原生数据库核心功能体验馆,由阿里云数据库产品事业部负责人宋震分享。内容涵盖PolarDB技术布局、开源进展及体验馆三大部分。技术布局包括云计算加速数据库演进、数据处理需求带来的变革、软硬协同优化等;开源部分介绍了兼容MySQL和PostgreSQL的两款产品;体验馆则通过实际操作让用户直观感受Serverless、无感切换、SQL2Map等功能。
293 7
|
4月前
|
存储 Cloud Native 关系型数据库
PolarDB开源:云原生数据库的架构革命
本文围绕开源核心价值、社区运营实践和技术演进路线展开。首先解读存算分离架构的三大突破,包括基于RDMA的分布式存储、计算节点扩展及存储池扩容机制,并强调与MySQL的高兼容性。其次分享阿里巴巴开源治理模式,涵盖技术决策、版本发布和贡献者成长体系,同时展示企业应用案例。最后展望技术路线图,如3.0版本的多写多读架构、智能调优引擎等特性,以及开发者生态建设举措,推荐使用PolarDB-Operator实现高效部署。
264 3
|
4月前
|
Cloud Native 关系型数据库 分布式数据库
PolarDB开源:云原生数据库的新篇章
阿里云自研的云原生数据库PolarDB于2023年5月正式开源,采用“存储计算分离”架构,具备高性能、高可用及全面兼容性。其开源版本提供企业级数据库解决方案,支持MySQL、PostgreSQL和Oracle语法,适用于高并发OLTP、核心业务系统等场景。PolarDB通过开放治理与开发者工具构建完整生态,并展望更丰富的插件功能与AI集成,为中国云原生数据库技术发展贡献重要力量。
450 17
|
8月前
|
NoSQL 关系型数据库 MySQL
阿里云PolarDB游戏场景最佳实践
阿里云PolarDB游戏场景最佳实践涵盖了数据库体系演进、行业优化、Redis解决方案、性能优化、备份还原及全球部署等内容。PolarDB通过共享存储、物理复制等技术提升读扩展和大容量支持,针对游戏行业的高IO需求进行优化,提供秒级备份与快速恢复能力。同时,PolarDB for Redis实现了一写多读架构,支持百TB级别的高性能存储,具备成本优势。该方案已在米哈游等大型游戏中广泛应用,确保了高并发下的稳定性和数据一致性,满足游戏行业的特殊需求。
327 36
|
8月前
|
运维 关系型数据库 分布式数据库
阿里云PolarDB:引领云原生数据库创新发展
阿里云PolarDB引领云原生数据库创新,2024云栖大会将分享其最新发展及在游戏行业的应用。PolarDB凭借弹性、高可用性、多写技术等优势,支持全球80多个站点,服务1万多家企业。特别是针对游戏行业,PolarDB助力Funplus等公司实现高效运维、成本优化和业务扩展。通过云原生能力,PolarDB推动游戏业务的全球化部署与快速响应,提升用户体验并保障数据安全。未来,PolarDB将继续探索AI、多云管理等前沿技术,为用户提供更智能的数据基础设施。
330 2
|
5月前
|
关系型数据库 分布式数据库 数据库
一库多能:阿里云PolarDB三大引擎、四种输出形态,覆盖企业数据库全场景
PolarDB是阿里云自研的新一代云原生数据库,提供极致弹性、高性能和海量存储。它包含三个版本:PolarDB-M(兼容MySQL)、PolarDB-PG(兼容PostgreSQL及Oracle语法)和PolarDB-X(分布式数据库)。支持公有云、专有云、DBStack及轻量版等多种形态,满足不同场景需求。2021年,PolarDB-PG与PolarDB-X开源,内核与商业版一致,推动国产数据库生态发展,同时兼容主流国产操作系统与芯片,获得权威安全认证。
|
2月前
|
存储 关系型数据库 分布式数据库
喜报|阿里云PolarDB数据库(分布式版)荣获国内首台(套)产品奖项
阿里云PolarDB数据库管理软件(分布式版)荣获「2024年度国内首版次软件」称号,并跻身《2024年度浙江省首台(套)推广应用典型案例》。
|
3月前
|
关系型数据库 分布式数据库 数据库
再获殊荣,阿里云PolarDB数据库蝉联SIGMOD最佳论文奖
内存池化技术新突破,阿里云PolarDB蝉联SIGMOD最佳论文奖
|
4月前
|
Cloud Native 关系型数据库 分布式数据库
阿里云PolarDB与沃趣科技携手打造一体化数据库解决方案,助推国产数据库生态发展
阿里云瑶池数据库与沃趣科技将继续深化合作,共同推动国产数据库技术的持续创新与广泛应用,为行业生态的繁荣注入更强劲的技术动力。
阿里云PolarDB与沃趣科技携手打造一体化数据库解决方案,助推国产数据库生态发展

热门文章

最新文章

相关产品

  • 云原生数据库 PolarDB
  • 推荐镜像

    更多