阿里妹导读:Lindorm,就是云操做系统飞天中面向大数据存储处理的重要组成部分。Lindorm是基于HBase研发的、面向大数据领域的分布式NoSQL数据库,集大规模、高吞吐、快速灵活、实时混合能力于一身,面向海量数据场景提供世界领先的高性能、可跨域、多一致、多模型的混合存储处理能力。目前,Lindorm已经全面服务于阿里经济体中的大数据结构化、半结构化存储场景。
注:Lindorm是阿里内部HBase分支的别称,在阿里云上对外售卖的版本叫作HBase加强版,以后文中出现的HBase加强版和Lindorm都指同一个产品。html
2019年以来,Lindorm已经服务了包括淘宝、天猫、蚂蚁、菜鸟、妈妈、优酷、高德、大文娱等数十个BU,在今年的双十一中,Lindorm峰值请求达到了7.5亿次每秒,天吞吐22.9万亿次,平均响应时间低于3ms,总体存储的数据量达到了数百PB。这些数字的背后,凝聚了HBase&Lindorm团队多年以来的汗水和心血。Lindorm脱胎于HBase,是团队多年以来承载数百PB数据,亿级请求量,上千个业务后,在面对规模成本压力,以及HBase自身缺陷下,全面重构和引擎升级的全新产品。相比HBase,Lindorm不管是性能,功能仍是可用性上,都有了巨大飞跃。本文将从功能、可用性、性能成本、服务生态等维度介绍Lindorm的核心能力与业务表现,最后分享部分咱们正在进行中的一些项目。java
Lindorm比HBase在RPC、内存管理,缓存、日志写入等方面作了深度的优化,引入了众多新技术,大幅提高了读写性能,在相同硬件的状况下,吞吐可达到HBase的5倍以上,毛刺更是能够达到HBase的1/10。这些性能数据,并非在实验室条件下产生的,而是在不改动任何参数的前提下,使用开源测试工具YCSB跑出来的成绩。咱们把测试的工具和场景都公布在阿里云的帮助文件中,任何人均可以依照指南本身跑出同样的结果。算法
取得这么优异的性能的背后,是Lindorm中积攒多年的“黑科技”,下面,咱们简单介绍下Lindorm内核中使用到的部分“黑科技”。数据库
Lindorm 的文件LDFile(相似HBase中的HFile)是只读 B+ 树结构,其中文件索引是相当重要的数据结构。在 block cache 中有高优先级,须要尽可能常驻内存。若是能下降文件索引所占空间大小,咱们能够节省 block cache 中索引所须要的宝贵内存空间。或者在索引空间不变的状况下,增长索引密度,下降 data block 的大小,从而提升性能。而HBase中的索引block中存的是全量的Rowkey,而在一个已经排序好的文件中,不少Rowkey都是有共同前缀的。跨域
数据结构中的Trie (前缀树) 结构可以让共同前缀只存一份,避免重复存储带来的浪费。可是传统前缀树结构中,从一个节点到下一个节点的指针占用空间太多,总体而言得不偿失。这一状况有望用 Succinct Prefix Tree 来解决。SIGMOD2018年的最佳论文 Surf 中提出了一种用 Succinct Prefix Tree 来取代 bloom filter,并同时提供 range filtering 的功能。咱们从这篇文章获得启发,用 Succinct Trie 来作 file block index。数组
咱们在线上的多个业务中使用了Trie index实现的索引结构。结果发现,各个场景中,Trie index能够大大缩小索引的体积,最多能够压缩12倍的索引空间!节省的这些宝贵空间让内存Cache中可以存放更多的索引和数据文件,大大提升了请求的性能。缓存
ZGC(Powerd by Dragonwell JDK)是下一代Pauseless GC算法的表明之一,其核心思想是Mutator利用内存读屏障(Read Barrier)识别指针变化,使得大部分的标记(Mark)与合并(Relocate)工做能够放在并发阶段执行。 这样一项实验性技术,在Lindorm团队与AJDK团队的紧密合做下,进行了大量的改进与改造工做。使得ZGC在Lindorm这个场景上实现了生产级可用,主要工做包括:安全
注:图中的单位应该为us,平均GC在5ms性能优化
上图是HBase中的RegionServer从网络上读取RPC请求并分发到各个Handler上执行的流程。HBase中的RPC Reader从Socket上读取RPC请求放入BlockingQueue,Handler订阅这个Queue并执行请求。而这个BlockingQueue,HBase使用的是Java原生的JDK自带的LinkedBlockingQueue。服务器
LinkedBlockingQueue利用Lock与Condition保证线程安全与线程之间的同步,虽然经典易懂,但当吞吐增大时,这个queue会形成严重的性能瓶颈。所以在Lindorm中全新设计了LindormBlockingQueue,将元素维护在Slot数组中。维护head与tail指针,经过CAS操做对进队列进行读写操做,消除了临界区。并使用Cache Line Padding与脏读缓存加速,同时可定制多种等待策略(Spin/Yield/Block),避免队列为空或为满时,频繁进入Park状态。LindormBlockingQueue的性能很是突出,相比于原先的LinkedBlockingQueue性能提高4倍以上。
LDLog是Lindorm中用于系统failover时进行数据恢复时的日志,以保障数据的原子性和可靠性。在每次数据写入时,都必须先写入LDLog。LDLog写入成功以后,才能够进行后续的写入memstore等操做。所以Lindorm中的Handler都必须等待WAL写入完成后再被唤醒以进行下一步操做,在高压条件下,无用唤醒会形成大量的CPU Context Switch形成性能降低。针对这个问题,Lindorm研发了基于版本的高并发多路线程同步机制(VersionBasedSynchronizer)来大幅优化上下文切换。
VersionBasedSynchronizer的主要思路是让Handler的等待条件被Notifier感知,减小Notifier的唤醒压力。通过模块测试VersionBasedSynchronizer的效率是JDK自带的ObjectMonitor和J.U.C(java util concurrent包)的两倍以上。
HBase内核在关键路径上有大量的锁,在高并发场景下,这些锁都会形成线程争抢和性能降低。Lindorm内核对关键链路上的锁都作了无锁化处理,如MVCC,WAL模块中的锁。另外,HBase在运行过程当中会产生的各类指标,如qps,rt,cache命中率等等。而在记录这些Metrics的“不起眼”操做中,也会有大量的锁。面对这样的问题,Lindorm借鉴了tcmalloc的思想,开发了LindormThreadCacheCounter,来解决Metrics的性能问题。
在高并发应用中,一个RPC请求的实现每每包含多个子模块,涉及到若干次IO。这些子模块的相互协做,系统的ContextSwitch至关频繁。ContextSwitch的优化是高并发系统绕不开的话题,各位高手都各显神通,业界有很是多的思想与实践。其中coroutine(协程)和SEDA(分阶段事件驱动)方案是咱们着重考察的方案。基于工程代价,可维护性,代码可读性三个角度考虑,Lindorm选择了协程的方式进行异步化优化。咱们利用了阿里JVM团队提供的Dragonwell JDK内置的Wisp2.0功能实现了HBase Handler的协程化,Wisp2.0开箱即用,有效地减小了系统的资源消耗,优化效果比较客观。
从性能角度考虑,HBase一般须要将Meta信息装载进block cache。若是将block大小较小,Meta信息较多,会出现Meta没法彻底装入Cache的状况, 性能降低。若是block大小较大,通过Encoding的block的顺序查询的性能会成为随机读的性能瓶颈。针对这一状况,Lindorm全新开发了Indexable Delta Encoding,在block内部也能够经过索引进行快速查询,seek性能有了较大提升。Indexable Delta Encoding原理如图所示:
经过Indexable Delta Encoding, HFile的随机seek性能相对于使用以前翻了一倍,以64K block为例,随机seek性能基本与不作encoding相近(其余encoding算法会有必定性能损失)。在全cache命中的随机Get场景下,相对于Diff encoding RT降低50%
相比社区版HBase,Lindorm还有多达几十项的性能优化和重构,引入了众多新技术,因为篇幅有限,这里只能列举一部分,其余的核心技术,好比:
原生的HBase只支持KV结构的查询,虽然简单,可是在面对各项业务的复杂需求时,显的有点力不从心。所以,在Lindorm中,咱们针对不一样业务的特色,研发了多种查询模型,经过更靠近场景的API和索引设计,下降开发门槛。
WideColumn是一种与HBase彻底一致的访问模型和数据结构,从而使得Lindrom能100%兼容HBase的API。用户能够经过Lindorm提供的高性能原生客户端中的WideColumn API访问Lindorm,也能够经过alihbase-connector这个插件,使用HBase客户端及API(无需任何代码改造)直接访问Lindorm。同时,Lindorm使用了轻客户端的设计,将大量数据路由、批量分发、超时、重试等逻辑下沉到服务端,并在网络传输层作了大量的优化,使得应用端的CPU消耗能够大大节省。像下表中,相比于HBase,使用Lindorm后的应用侧CPU使用效率提高60%,网络带宽效率提高25%。
注:表中的客户端CPU表明HBase/Lindorm客户端消耗的CPU资源,越小越好。
在HBase原生API上,咱们还独家支持了高性能二级索引,用户可使用HBase原生API写入数据过程当中,索引数据透明地写入索引表。在查询过程当中,把可能全表扫的Scan + Filter大查询,变成能够先去查询索引表,大大提升了查询性能。关于高性能原生二级索引,你们能够参考:
https://help.aliyun.com/docum...
HBase中只支持Rowkey这一种索引方式,对于多字段查询时,一般效率低下。为此,用户须要维护多个表来知足不一样场景的查询需求,这在必定程度上既增长了应用的开发复杂性,也不能很完美地保证数据一致性和写入效率。而且HBase中只提供了KV API,只能作Put、Get、Scan等简单API操做,也没有数据类型,全部的数据都必须用户本身转换和储存。对于习惯了SQL语言的开发者来讲,入门的门槛很是高,并且容易出错。
为了解决这一痛点,下降用户使用门槛,提升开发效率,在Lindorm中咱们增长了TableService模型,其提供丰富的数据类型、结构化查询表达API,并原生支持SQL访问和全局二级索引,解决了众多的技术挑战,大幅下降普通用户的开发门槛。经过SQL和SQL like的API,用户能够方便地像使用关系数据库那样使用Lindorm。下面是一个Lindorm SQL的简单示例。
-- 主表和索引DDL create table shop_item_relation ( shop_id varchar, item_id varchar, status varchar constraint primary key(shop_id, item_id)) ; create index idx1 on shop_item_relation (item_id) include (ALL); -- 对第二列主键建索引,冗余全部列 create index idx2 on shop_item_relation (shop_id, status) include (ALL); -- 多列索引,冗余全部列 -- 写入数据,会同步更新2个索引 upsert into shop_item_relation values('shop1', 'item1', 'active'); upsert into shop_item_relation values('shop1', 'item2', 'invalid'); -- 根据WHERE子句自动选择合适的索引执行查询 select * from shop_item_relation where item_id = 'item2'; -- 命中idx1 select * from shop_item_relation where shop_id = 'shop1' and status = 'invalid'; -- 命中idx2
相比于关系数据库的SQL,Lindorm不具有多行事务和复杂分析(如Join、Groupby)的能力,这也是二者之间的定位差别。相比于HBase上Phoenix组件提供的二级索引,Lindorm的二级索引在功能、性能、稳定性上远远超过Phoenix,下图是一个简单的性能对比。
注:该模型已经在阿里云HBase加强版上内测,感兴趣的用户能够联系云HBase答疑钉钉号或者在阿里云上发起工单咨询。
现代互联网架构中,消息队列承担了很是重要的职责,能够极大的提高核心系统的性能和稳定性。其典型的应用场景有包括系统解耦,削峰限流,日志采集,最终一致保证,分发推送等等。常见的消息队列包括RabbitMq,Kafka以及RocketMq等等。这些数据库尽管从架构和使用方式和性能上略有不一样,但其基本使用场景都相对接近。然而,传统的消息队列并不是完美,其在消息推送,feed流等场景存在如下问题:
针对上述需求,Lindorm推出了队列模型FeedStreamService,可以解决海量用户下的消息同步,设备通知,自增ID分配等问题。
FeedStream模型在今年手机淘宝消息系统中扮演了重要角色,解决了手机淘宝消息推送保序,幂等等难题。在今年双十一中,手淘的盖楼和回血大红包推送都有Lindorm的身影。手淘消息的推送中,峰值超过了100w/s,作到了分钟级推送全网用户。
注:该模型已经在阿里云HBase加强版上内测,感兴趣的用户能够联系云HBase答疑钉钉号或者在阿里云上发起工单咨询。
虽然Lindorm中的TableService模型提供了数据类型和二级索引。可是,在面对各类复杂条件查询和全文索引的需求下,仍是显得力不从心,而Solr和ES是优秀的全文搜索引擎。使用Lindorm+Solr/ES,能够最大限度发挥Lindorm和Solr/ES各自的优势,从而使得咱们能够构建复杂的大数据存储和检索服务。Lindorm内置了外部索引同步组件,可以自动地将写入Lindorm的数据同步到外部索引组件如Solr或者ES中。这种模型很是适合须要保存大量数据,而查询条件的字段数据仅占原数据的一小部分,而且须要各类条件组合查询的业务,例如:
全文索引模型已经在阿里云上线,支持Solr/ES外部索引。目前,索引的查询用户还须要直接查询Solr/ES再来反查Lindorm,后续咱们会用TableService的语法把查询外部索引的过程包装起来,用户全程只须要和Lindorm交互,便可得到全文索引的能力。
除了上述这些模型,咱们还会根据业务的需求和痛点,开发更多简单易用的模型,方便用户使用,下降使用门槛。像时序模型,图模型等,都已经在路上,敬请期待。
从一个婴儿成长为青年,阿里HBase摔过不少次,甚至头破血流,咱们在客户的信任之下幸运的成长。在9年的阿里应用过程当中,咱们积累了大量的高可用技术,而这些技术,都应用到了HBase加强版中。
HBase是参照Gooogle著名论文BigTable的开源实现,其中最核心特色是数据持久化存储于底层的分布式文件系统HDFS,经过HDFS对数据的多副本维护来保障整个系统的高可靠性,而HBase自身不须要去关心数据的多副本及其一致性,这有助于总体工程的简化,但也引入了"服务单点"的缺陷,即对于肯定的数据的读写服务只有发生固定的某个节点服务器,这意味着当一个节点宕机后,数据须要经过重放Log恢复内存状态,而且从新派发给新的节点加载后,才能恢复服务。
当集群规模较大时,HBase单点故障后恢复时间可能会达到10-20分钟,大规模集群宕机的恢复时间可能须要好几个小时!而在Lindorm内核中,咱们对MTTR(平均故障恢复时间)作了一系列的优化,包括故障恢复时先上线region、并行replay、减小小文件产生等众多技术。将故障恢复速度提高10倍以上!基本上接近了HBase设计的理论值。
在原来的HBase架构中,每一个region只能在一个RegionServer中上线,若是这个region server宕机,region须要经历Re-assgin,WAL按region切分,WAL数据回放等步骤后,才能恢复读写。这个恢复时间可能须要数分钟,对于某些高要求的业务来讲,这是一个没法解决的痛点。另外,虽然HBase中有主备同步,但故障下只能集群粒度的手动切换,而且主和备的数据只能作到最终一致性,而有一些业务只能接受强一致,HBase在这点上可望不可即。
Lindorm内部实现了一种基于Shared Log的一致性协议,经过分区多副本机制达到故障下的服务自动快速恢复的能力,完美适配了存储分离的架构, 利用同一套体系便可支持强一致语义,又能够选择在牺牲一致性的前提换取更佳的性能和可用性,实现多活,高可用等多种能力。
在这套架构下,Lindorm拥有了如下几个一致性级别,用户能够根据本身的业务自由选择一致性级别:
注:该功能暂时未在阿里云HBase加强版上对外开放
虽说目前HBase能够组成主备,可是目前市面上没有一个高效地客户端切换访问方案。HBase的客户端只能访问固定地址的HBase集群。若是主集群发生故障,用户须要中止HBase客户端,修改HBase的配置后重启,才能链接备集群访问。或者用户在业务侧必须设计一套复杂地访问逻辑来实现主备集群的访问。阿里HBase改造了HBase客户端,流量的切换发生在客户端内部,经过高可用的通道将切换命令发送给客户端,客户端会关闭旧的连接,打开与备集群的连接,而后重试请求。
若是须要使用此项功能,请参考高可用帮助文档:https://help.aliyun.com/docum...
Lindorm从立项之初就考虑到上云,各类设计也能尽可能复用云上基础设施,为云的环境专门优化。好比在云上,咱们除了支持云盘以外,咱们还支持将数据存储在OSS这种低成本的对象存储中减小成本。咱们还针对ECS部署作了很多优化,适配小内存规格机型,增强部署弹性,一切为了云原生,为了节省客户成本。
目前Lindorm在云上的版本HBase加强版均采用ECS+云盘部署(部分大客户可能采用本地盘),ECS+云盘部署的形态给Lindorm带来了极致的弹性。
最开始的时候,HBase在集团的部署均采用物理机的形式。每一个业务上线前,都必须先规划好机器数量和磁盘大小。在物理机部署下,每每会遇到几个难以解决的问题:
ECS提供了一个近似无限的资源池。当面对业务的紧急扩容时,咱们只需在资源池中申请新的ECS拉起后,便可加入集群,时间在分钟级别以内,无惧业务流量高峰。配合云盘这样的存储计算分离架构。咱们能够灵活地为各类业务分配不一样的磁盘空间。当空间不够时,能够直接在线扩缩容磁盘。同时,运维不再用考虑硬件故障,当ECS有故障时,ECS能够在另一台宿主机上拉起,而云盘彻底对上层屏蔽了坏盘的处理。极致的弹性一样带来了成本的优化。咱们不须要为业务预留太多的资源,同时当业务的大促结束后,可以快速地缩容下降成本。
在海量大数据场景下,一张表中的部分业务数据随着时间的推移仅做为归档数据或者访问频率很低,同时这部分历史数据体量很是大,好比订单数据或者监控数据,下降这部分数据的存储成本将会极大的节省企业的成本。如何以极简的运维配置成本就能为企业极大下降存储成本,Lindorm冷热分离功能应运而生。Lindorm为冷数据提供新的存储介质,新的存储介质存储成本仅为高效云盘的1/3。
Lindorm在同一张表里实现了数据的冷热分离,系统会自动根据用户设置的冷热分界线自动将表中的冷数据归档到冷存储中。在用户的访问方式上和普通表几乎没有任何差别,在查询的过程当中,用户只需配置查询Hint或者TimeRange,系统根据条件自动地判断查询应该落在热数据区仍是冷数据区。对用户而言始终是一张表,对用户几乎作到彻底的透明。详细介绍请参考:https://yq.aliyun.com/article...
早在两年前,咱们就把集团内的存储压缩算法替换成了ZSTD,相比原来的SNAPPY算法,得到了额外25%的压缩收益。今年咱们对此进一步优化,开发实现了新的ZSTD-v2算法,其对于小块数据的压缩,提出了使用预先采样数据进行训练字典,而后用字典进行加速的方法。咱们利用了这一新的功能,在Lindorm构建LDFile的时候,先对数据进行采样训练,构建字典,而后在进行压缩。在不一样业务的数据测试中,咱们最高得到了超过原生ZSTD算法100%的压缩比,这意味着咱们能够为客户再节省50%的存储费用。
阿里云HBase Serverless 版是基于Lindorm内核,使用Serverless架构构建的一套新型的HBase 服务。阿里云HBase Serverless版真正把HBase变成了一个服务,用户无需提早规划资源,选择CPU,内存资源数量,购买集群。在应对业务高峰,业务空间增加时,也无需进行扩容等复杂运维操做,在业务低谷时,也无需浪费闲置资源。
在使用过程当中,用户能够彻底根据当前业务量,按需购买请求量和空间资源便可。使用阿里云HBase Serverless版本,用户就好像在使用一个无限资源的HBase集群,随时知足业务流量忽然的变化,而同时只须要支付本身真正使用的那一部分资源的钱。
关于HBase Serverless的介绍和使用,能够参考:https://developer.aliyun.com/...
Lindorm引擎内置了完整的用户名密码体系,提供多种级别的权限控制,并对每一次请求鉴权,防止未受权的数据访问,确保用户数据的访问安全。同时,针对企业级大客户的诉求,Lindorm内置了Group,Quota限制等多租户隔离功能,保证企业中各个业务在使用同一个HBase集群时不会被相互影响,安全高效地共享同一个大数据平台。
Lindorm内核提供一套简单易用的用户认证和ACL体系。用户的认证只须要在配置中简单的填写用户名密码便可。用户的密码在服务器端非明文存储,而且在认证过程当中不会明文传输密码,即便验证过程的密文被拦截,用以认证的通讯内容不可重复使用,没法被伪造。
Lindorm中有三个权限层级。Global,Namespace和Table。这三者是相互覆盖的关系。好比给user1赋予了Global的读写权限,则他就拥有了全部namespace下全部Table的读写权限。若是给user2赋予了Namespace1的读写权限,那么他会自动拥有Namespace1中全部表的读写权限。
当多个用户或者业务在使用同一个HBase集群时,每每会存在资源争抢的问题。一些重要的在线业务的读写,可能会被离线业务批量读写所影响。而Group功能,则是HBase加强版(Lindorm)提供的用来解决多租户隔离问题的功能。 经过把RegionServer划分到不一样的Group分组,每一个分组上host不一样的表,从而达到资源隔离的目的。
例如,在上图中,咱们建立了一个Group1,把RegionServer1和RegionServer2划分到Group1中,建立了一个Group2,把RegionServer3和RegionServer4划分到Group2。同时,咱们把Table1和Table2也移动到Group1分组。这样的话,Table1和Table2的全部region,都只会分配到Group1中的RegionServer1和RegionServer2这两台机器上。
一样,属于Group2的Table3和Table4的Region在分配和balance过程当中,也只会落在RegionServer3和RegionServer4上。所以,用户在请求这些表时,发往Table一、Table2的请求,只会由RegionServer1和RegionServer2服务,而发往Table3和Table4的请求,只会由RegionServer3和RegionServer4服务,从而达到资源隔离的目的。
Lindorm内核中内置了一套完整的Quota体系,来对各个用户的资源使用作限制。对于每个请求,Lindorm内核都有精确的计算所消耗的CU(Capacity Unit),CU会以实际消耗的资源来计算。好比用户一个Scan请求,因为filter的存在,虽然返回的数据不多,但可能已经在RegionServer已经消耗大量的CPU和IO资源来过滤数据,这些真实资源的消耗,都会计算在CU里。在把Lindorm当作一个大数据平台使用时,企业管理员能够先给不一样业务分配不一样的用户,而后经过Quota系统限制某个用户每秒的读CU不能超过多少,或者总的CU不能超过多少,从而限制用户占用过多的资源,影响其余用户。同时,Quota限流也支持Namesapce级别和表级别限制。
全新一代NoSQL数据库Lindorm是阿里巴巴HBase&Lindorm团队9年以来技术积累的结晶,Lindorm在面向海量数据场景提供世界领先的高性能、可跨域、多一致、多模型的混合存储处理能力。对焦于同时解决大数据(无限扩展、高吞吐)、在线服务(低延时、高可用)、多功能查询的诉求,为用户提供无缝扩展、高吞吐、持续可用、毫秒级稳定响应、强弱一致可调、低存储成本、丰富索引的数据实时混合存取能力。Lindorm已经成为了阿里巴巴大数据体系中的核心产品之一,成功支持了集团各个BU上千个业务,也屡次在天猫双十一“技术大团建”中经受住了考验。阿里CTO行癫说过,阿里的技术都应该经过阿里云输出,去普惠各行各业数百万客户。所以Lindorm从今年开始,已经在阿里云上以“HBase加强版”的形式,以及在专有云中对外输出**(点击了解详情
))**让云上的客户可以享受到阿里巴巴的技术红利,助力业务腾飞!
参考资料:
HBase加强版/Lindorm性能测试相关文档
https://help.aliyun.com/docum...
如何下降90%Java垃圾回收时间?以阿里HBase的GC优化实践为例
https://yq.aliyun.com/article...
大数据时代的结构化存储—HBase在阿里的应用实践
https://yq.aliyun.com/article...
看我72变,阿里HBase数据压缩编码探索
https://yq.aliyun.com/article...
阿里HBase高可用8年“抗战”回忆录
https://developer.aliyun.com/...
高性能原生二级索引
https://help.aliyun.com/docum...
阿里云HBase推出普惠性高可用服务,独家支持用户的自建、混合云环境集群
https://developer.aliyun.com/...
HBase毛刺消除利器-双集群并发访问(Dual Service)
https://developer.aliyun.com/...
面向海量数据的极致成本优化-云HBase的一体化冷热分离
https://developer.aliyun.com/...
1元包月,阿里云HBase Serverless开启大数据学习与测试的新时代
https://developer.aliyun.com/...
双12来袭!500元淘宝红包、iPhone11等你拿https://www.aliyun.com/1212/2019/home?utm_content=g_1000092611
本文做者:正研
本文来自云栖社区合做伙伴“ 阿里技术”,如需转载请联系原做者。