社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  DATABASE

万字长文剖析AliSQL X-Cluster|基于X-Paxos的高性能强一致MySQL数据库

阿里技术 • 7 年前 • 1034 次点击  

阿里妹导读

MySQL数据库从诞生以来就以其简单、易用、开源为其主打特点,成为不少开发者首选的数据库系统。阿里在2008年开始提出"去IOE"的口号,其中,使用大量的MySQL,配合业务的改造替代原有的商业版Oracle系统。自此集团迈入了MySQL数据库的时代。根据阿里交易型应用的特点,以及双十一这样业界罕有的需求推动下,我们在官方的MySQL基础上增加了非常多实用的功能、性能补丁,打造了AliSQL这个业界响当当的MySQL分支品牌。

时间很快走到2014年,随着业务高速的增长,同城主备AliSQL部署的方式已经无法满足阿里对可扩展的部署、国际化、以及容灾方面的需求。“异地多活”成为了公司应用的新标准。“异地多活”也给底层的数据库提出了新的容灾要求。传统的Master-Slave架构下,主备如果不使用强同步模式就会存在数据丢失的可能,然而强同步下一旦有节点异常则整体不可服务。而且这套架构下需要HA工具来进行选主的仲裁和控制。

过去阿里巴巴的DBA们开发了高效可靠的HA以及一整套工具和流程来做主备切换后数据和日志的校验和订正。然而我们相信技术的发展能带来更大的运维便利性以及更好的用户体验。以Google Spanner以及Amazon Aruora 为代表的NewSQL系统为数据库的数据一致性给出了与以往不同的思路:基于一致性协议搭建分布式的多副本数据库。

本文字数近万字,建议对数据库感兴趣的童鞋收藏细看。

AliSQLX-Cluster 介绍

AliSQL X-Cluster(本文中简称X-Cluster)是阿里巴巴数据库团队推出的兼容MySQL 5.7,提供数据强一致功能,支持全球部署的分布式数据库集群产品。


说到AliSQL X-Cluster就不能不提其分布式核心,一致性协议。


X-Paxos是阿里巴巴自主研发的一致性协议库,目标是填补市面上高性能、易接入的一致性协议库的空白。而市面上已开源的一致性协议实现,包括etcd以及其他厂商等都存在或性能不够,或功能上无法满足复杂的现实应用场景需求的问题。


有了X-Paxos,可基于它打造一套强一致的分布式系统,X-Cluster是第一个接入X-Paxos生态的重要产品,利用了X-Paxos实现了自动选主,日志同步,集群内数据强一致,在线集群配置变更等功能。同时X-Cluster基于MySQL生态,兼容最新版本的MySQL 5.7,集成了AliSQL过去的各种功能增强。 MySQL的用户可以零成本迁移到X-Cluster上。


整体架构

先来看一下X-Cluster的基本架构:



上图展示的是一个部署三个实例的Cluster集群。X-Cluster是一个单点写入,多点可读的集群系统。在同一时刻,整个集群中至多会有一个Leader节点来承担数据写入的任务。相比多点写入,单点写入不需要处理数据集冲突的问题,可以达到更好的性能与吞吐率。

X-Cluster 的每个实例都是一个单进程的系统,X-Paxos被深度整合到了数据库内核之中,替换了原有的复制模块。集群节点之间的增量数据同步完全是通过X-Paxos来自驱动,如何复制,从哪个点回放不再需要运维人员或者外部工具来介入。 X-Cluster为了追求最高的性能,利用MySQLBinlog进行深度改造和定制来作为X-PaxosConsensus日志,实现了一系列的X-Paxos日志接口,赋予X-Paxos直接操纵MySQL日志的能力。

为了保证集群数据的一致性以及全球部署的能力,在事务提交、日志复制回放以及恢复上X-Cluster都进行了重新设计。

事务提交、复制流程

X-Cluster的复制流程是基于X-Paxos驱动Consensus日志进行复制。   

Leader节点在事务prepare阶段会将事务产生的日志收集起来,传递给X-Paxos协议层后进入等待。X-Paxos协议层会将Consensus日志高效地转发给集群内其他节点。当日志在超过集群半数实例上落盘后 X-Paxos会通知事务可以进入提交步骤。否则如果期间发生Leader变更,期间prepare的事务会根据Paxos日志的状态进行相应的回滚操作。相比原生 MySQL,日志传输采用了多线程、异步化、BatchingPipelining等优化手段,特别是在长传链路的场景中,效率提升明显。

Follower节点也使用X-Paxos进行日志的管理操作,为提升接收效率,收到Leader传递过来的日志以后将日志内容AppendConsensus Log末尾,Leader会异步的将达成多数派的日志的消息发送给FollowerFollower的协调者线程会负责读取达成多数派的日志并加以解析,并传递给各个回放工作线程进行并发的数据更新。 Follower的并发回放可以有多种方式,包括按照Leader上的Group Commit维度或者是按照表级别的维度,未来会引入最新的writeset方式来精确控制最大并发。

Failover

X-Cluster 只要半数以上的节点存活就能保证集群正常对外服务。因此当少数的follower节点故障时并不影响集群的服务能力。当Leader节点故障时会自动触发集群的重新选主流程。选主流程由X-Paxos驱动,在Paxos协议的基础上,结合优先级推选出新的Leader节点。

对于X-Cluster而言,failover_time = election_time+ apply_timeelection_time代表协议选主的时间,一般在 10s左右, apply_time是数据应用日志的时间,取决于回放的速度,优秀的并行回放算法能把应用日志的时间控制在10s之内。

相对来说之下Leader节点故障是一个相对复杂的场景,故障包括了实例崩溃、服务器宕机、网络隔离等等。


如上图所示,一个三节点的X-Cluster集群,左边的Case是原Leader A节点宕机,因此B节点和C节点会在较长的时间内收不到Leader的心跳,因此在一个选举超时周期后,B节点开始尝试推选自己为Leader,并且C节点同意,那么B成为新的主节点,恢复服务能力。

右边的Case 是原Leader A节点发生网络分区,此时在选举超时后,BC两个节点的行为和之间的Case类似。 A节点由于无法将心跳和日志发送给BC两个节点在超时后会降级,然后不断尝试选自己为主,但是因为没有其他节点的同意,达不成多数派,一直都不会成功。当网络分区恢复后,A收到 B节点的心跳,触发Leader stickness机制,A自动加回集群。

AliSQLX-Cluster的优化特性

X-Cluster拥有一系列的新功能和特性,以满足不同类型的应用对于功能和性能上的需求。

跨地域部署

X-Cluster的一个显著功能就是能够支持跨地域部署,在跨域的情况下也能保证集群数据强一致,拥有城市级容灾的能力。即使某个城市的机房全部宕机,只要保证集群多数派节点存活,所有的数据都不会丢失。依赖X-Paxos以及数据库内核中异步化工作线程的改造,在数十毫秒的网络RTTRound Trip Time)下,X-Cluster依然有非常高的吞吐性能。拥有了跨地域部署的能力,X-Cluster的部署方式是非常灵活的。业务可以根据实际的业务情况以及不同的容灾级别需求,选择同机房容灾,机房容灾,城市容灾部署,并且可以在不同的容灾级别之间灵活切换。

集群的动态配置和选举

X-Cluster支持在线集群配置变更。包括:

  • 增加节点下线节点

  • 修改节点类型为一致性节点或者是只读节点

  • 修改节点优先级

  • 修改集群的Leader

  • 修改只读节点复制源

所有的上述修改配置的过程在线进行,不会阻塞业务的正常运行,集群配置的变化也会严格按照Paxos 协议进行,记录日志并且对应的推动状态机变更,并且有完善的恢复机制。保证最终集群内配置达成一致,不会因为集群配置变更过程中的异常导致脑裂或者其他配置出现终态不一致的问题。

X-Cluster集群的节点从功能上看有两个类型,包括参与选主与多数派协议的一致性协议节点还有只读节点。一致性协议节点是X-Cluster的基础。目前一个X-Cluster集群支持至少1个一致性节点,至多99个一致性节点。只读节点可以无限扩展。用户可以从一开始的单节点集群开始,后续不断根据需求扩展不同类型的节点。

优先级

应用往往对于容灾后新主节点是有要求的,在原先的主节点意外宕机后,新主如若落在了一个低规格的节点,那么对于应用来说是很难接受的服务降级。 X-Cluster 支持同一个集群中的节点拥有不同的优先级,用户可以根据实际的部署需要,在配置集群时为每个实例节点设置优先级。

优先级功能主要包括以下两方面:

  • 权重化选主

  • 策略化多数派

权重化选主代表选主的顺序权重。只要在选举的时候没有网络隔离,选举Leader的顺序会按照集群存活节点的权重顺序进行。权重越高的节点,就有更大的优先级被选为Leader。我们实现了两段式的选举时间,第一阶段是集群内统一的租约时间,而二阶段是根据权重来决定,权重越大的节点时间越短,也就是会越早发起自选举。除此之外,还有一重权重检测机制来保证权重优先级,节点上任时会广播检测一遍所有能够联通的集群内节点,如果发现权重更高的节点会主动发起一次Leader TransferLeader角色过继过去。

权重化选主在跨地域部署的场景下尤其重要。跨地域的部署业务和数据库之间的访问延时会非常敏感,如果Leader节点随机的切换到了另一个地域的机房可能会导致应用大规模的访问异地实例,大幅增加客户端的响应时间。权重化选主可以完美解决此问题。按照应用的部署需求进行动态设置,非常灵活。

策略化多数派是指在事务提交日志同步过程中,哪些节点必须要日志复制完成。复制优先级分为两档,强复制和弱复制。标准的Paxos只要超过半数的节点同步日志即可推进状态机,但是由于每个连接会自动分配路由的问题,可能在跨Region的访问中RTT时间会有误差。

那么为了缩短网络/节点故障后按照选主优先级重新选主并继续服务的时间间隔,我们可以配置在规定日志复制到多数节点的基础上必须还要复制到了所有强复制的节点才可以推进状态机并返回客户端事务提交成功的响应。这是一个类Max protection模式的设计,如果检测到强一致节点宕机,可选择适当的降级。

低成本副本管理

X-Cluster中,副本按照是否有数据状态机分为普通型(Normal),日志型(Log)两类。普通型拥有全部的功能;日志型只拥有日志不包含数据。如果日志型节点还是一个参与Paxos投票的一致性节点,那么它只有投票权,没有被选举权。

之所以要创建不同的类型的副本,还是出于应用需求以及成本控制的考虑。相比传统的两节点主备复制,X-Cluster的常规同城部署方式是三节点。 

日志型副本是作为降低部署成本的一种选择。日志型副本只存储日志,不需要存储数据,也不需要回放日志更新数据。因此无论是存储还是CPU的开销,日志型副本相比普通副本都有很大的优势。在实际应用规划中,非常适合来当作容灾型的节点部署。

只读节点管理


如上图所示,X-Cluster集群中的只读节点可以从任何一个一致性节点复制日志,这不仅是考虑到如果所有节点的日志都从Leader节点复制会对Leader节点造成过大的网络和IO瓶颈,而且由于跨区域部署下不同地域的数据状态机可能会有延时,设置了读写分离的用户在特定的场景下需要有特定的只读状态延时的要求。但是这时的问题就是如果某个一致性节点发生了宕机,那么和它建立复制关系的只读节点应该如何进行灾备联动?

作为一个自运维的数据库服务,X-Cluster自然要解决好这个问题。X-Cluster定义了Learner Source Group。每个Group是一个只读节点的容灾单元。当Group内某个一致性节点发生意外状况(宕机或者网络隔离)集群会根据Group的配置,将挂载在故障节点下的只读节点配置到Group 中另外一个正常工作的节点下进行数据同步。

高性能日志



MySQL系统在开启主备复制的情况下除了会记录Binlog之外,在备库上还会记录一份RelayLog。即从库通过指定对应主库的Binlog位置去同步一份二进制日志写入RelayLog,供复制线程读取和回放。在X-Cluster中,只使用一份日志进行节点间的同步,利用X-Paxos的插件式日志模块的特性,每个节点有一份Consensus日志。

这样既方便了对Consensus日志的管理,也降低了日志存储以及读写的开销。 Consensus Log拥有AppendGetTruncate以及Purge等基本接口,它的控制权完整地交给了X-Paxos,由X-Paxos进行控制。除此之外,X-ClusterConsensus Log设计了日志索引和日志缓存、预读机制,极大的提升了日志模块的性能保证一致性协议运作的高效性。

异步化事务提交

传统的MySQL都是 One Thread per Connection的工作模式,在引入线程池后是以一个线程池孵化一定数量的工作线程,每个线程负责处理一次query的解析、优化、修改数据、提交、回网络包等等。集群需要跨地域部署下,一次事务的提交由于需要在集群之间同步事务日志,受限于网络的RTT的限制,会达到数十毫秒的级别,那么对于一个普通的写事务来说,大量的时间会耗费在同步节点日志等待事务提交的过程。

在大压力下,很快数据库内部的工作线程会耗尽,吞吐达到瓶颈。如果一味的放大数据库内部的工作线程数目,那么线程上下文的代价会大幅增加。如果将整个事务的提交异步化,将工作线程从等待X-Paxos日志同步中解放出来,去处理新的连接请求,在大负载下可以拥有更高的处理能力。

异步化改造的说明示意如下图所示:



X-Cluster的异步化提交核心思想是将每个事务的请求分成两个阶段,提交之前一个阶段,提交和回包一个阶段。两个阶段都可以由不同的工作线程来完成。为了完成异步化的改造,X-Cluster增加了等待同步队列和等待提交队列,用于存储处于不同阶段的事务。前者队列中的事务是等待Paxos多数派日志同步的事务,后者是等待提交的事务。当用户发起Commit/Rollback/XA_Prepare时,处理用户连接的线程池Worker产生事务日志并将事务上下文存储到等待同步的队列中。等待同步队列的消费由少量数目的worker线程来完成,其余工作线程可以直接参与其他任务的处理。事务等待多数派完成后会被推入等待提交队列。这个队列里的事务都是可以被立即提交的。所有的worker线程发现该队列里有事务,就可以顺道取出来执行提交操作。

这样一来,系统中只有少数的线程在等待日志同步操作,其余的线程可以充分利用CPU处理客户端的请求。 X-Cluster以这样的思路为指导原则,结合MySQLGroup Commit逻辑,将原有需要等待的操作全部异步化,让Worker线程可以去执行新的请求响应。在测试中,异步化改造在同城部署的场景中相比同步提交有10%的吞吐率提升,跨区域的部署后有几倍的吞吐提升。

热点更新

热点更新原本就是数据库的一个难题,受制于行锁竞争,性能吞吐一直很难提升上去。X-Cluster面对跨域场景下的长传网络更加是雪上加霜,提交的时间变长,事务占据行锁的时间也显著增加。

为了解决此问题,X-Cluster在单机版AliSQL的热点功能之上优化了复制,使得在保证数据强一致的情况下,热点更新性能提升200倍。



如上图所示,X-Cluster针对热点行更新的基本思路是合并多个事务对同一行的更新。为了让批量的更新事务能够同时进行提交,X-Cluster增加了一种新的行锁类型——热点行锁。热点行锁下,热点更新的事务之间是相容的。 X-Cluster为了保证数据的一致性,对同一批的热点更新事务日志打上特殊标志, X-Paxos会根据这些标志将这一整批事务的日志组成一个单独的网络包进行集群间的数据同步,保证这些事务是原子的提交/回滚。除此之外为了提升日志回放的效率,X-Cluster将每个批次事务中对于热点行的更新日志也做了合并。

一体化的客户端和服务端


X-Cluster有完整的Client-Server生态。所以整个系统不需要外部组件的介入,能够自封闭的成为一个生态闭环。作为客户端的X-Driver能够订阅Server端发生的一切改变,从而进行自动寻主,实例列表动态维护等功能。客户端的元数据就保存在X-Cluster服务内部。相比外置的元数据中心,这套自封闭体系能够以最快的时间获取到准确的集群变化。降低集群变更对用户的感知程度。

优化的备份以及数据订阅体系



基于强大的X-Paxos体系,日志备份以及数据订阅系统都能够以日志订阅者的方式接入进来。由于有了X-Paxos的全局唯一位点支持,这些订阅系统的failover不再会有难以找到准确位点的困扰。而且由于X-Paxos是流式的推送日志消息,因此数据的实时性也能大幅改进。

AliSQLX-Cluster 实战部署方案

X-Cluster最为经典的两个部署方案是同城3副本,两份数据一份日志。以及跨地域5 副本,四份数据一份日志。分别用于满足机房级容灾和城市级容灾需求。这里的副本概念指的都是一致性节点的部署,只读节点部署不影响容灾能力。这两类经典的部署方案都是考虑了可用性以及成本之间的权衡,以较小的代价换来目标的容灾能力。

X-Cluster的同城部署三副本能够方便的实现零数据丢失的实例容灾以及机房级容灾。相比主备方式,额外增加了一个日志节点,换取强一致以及可用性。  



三地五实例(四数据、五日志)能够保证城市级容灾,如图所示,任何一个城市的节点全部宕机都不会影响到集群可用性,5个节点中至少还有3个节点是能够正常运行的。在日常运行中,5节点在每次事务提交的时候必定需要将日志同步到3个节点,因此必然会出现一次跨域的网络同步,这也就是长传链路网络场景,X-Cluster对于慢网络的优化正是应对类似这样的需求。

AliSQLX-Cluster 性能表现

我们使用了三节点部署的方式,分别在同域三机房、跨域三机房的网络环境下进行了测试。测试工具使用标准的Sysbench insert/oltp Insert测试下,并且每个事务中只包含一条插入语句,属于密集的小事务场景,而相反的OLTP是读写大事务。针对热点环境,测试的场景是改造update_non_index ,使更新同一行数据。只读场景不在本次测试的范畴内,原因是只读不涉及到节点的日志、数据同步,因此可以认为只读测试对于X-Cluster这样的分布式系统是没有意义的。所有的测试,数据量为10张表,每张表20万条记录。

作为对比,我们使用了最新的开源单机版MySQL 5.7.19 以及该版本下的Group ReplicationGroup Replication在测试中关闭限流。

测试机均是 64core  256G内存 PCIE SSD

测试同域下的集群,Insert我们使用300并发线程、 OLTP使用400并发线程,热点更新使用300并发线程。




在同一个域下,X-Cluster的吞吐和响应时间表现都是非常出色的,甚至略好于单机版本的MySQL 5.7.19。相比Group Replication,在本次测试的压力下,Insert case X-Cluster有超过一倍的吞吐以及55%左右的响应时间,OLTP case X-Cluster 有超过5%的吞吐以及接近70%的响应时间表现。

测试跨域下的集群需要大量的连接来保证吞吐,因此Insert使用2000并发线程,OLTP使用700并发线程,热点更新使用2500并发线程。



当集群部署在不同域时,X-ClusterGroup Replication相比同域的部署下吞吐都有下降,响应时间收到物理网络延迟的影响也有显著提高,然而在Insert case下,X-Cluster仍然可以领先Group Replication 5倍,响应时间只有GR的四分之一。OLTP case下,X-Cluster 的吞吐领先Group Replication接近4倍,响应时间只有三分之一。



热点更新是X-Cluster的一大亮点功能,根据测试结果,无论是同域还是跨域部署, X-Cluster的吞吐和响应时间表现都要远远超过单机MySQLGroupReplication

AliSQLX-Cluster正确性保障

分布式系统的测试是非常复杂的,因为没有人能够通过穷举来罗列所有可能出现的情况。简单的接口测试和性能回归也只能覆盖一小部分场景,无法来衡量一个分布式系统版本的质量。只有日复一日的测试以及线上系统的正常运行能够真正地说明分布式系统的鲁棒性。

X-Cluster最大的挑战就是保证其基于分布式一致性协议实现的正确性。经过实践证明,灰盒测试时最有效的手段。X-Cluster集成了 X-PaxosX-Paxos项目本身有一系列的测试框架用于发现和回归。除此之外X-Cluster基于tcsystemtap等工具构建了多种多样模拟网络异常、实例宕机、I/O异常的环境。在这套环境下网络分区、丢包、各种IO异常,各种实例宕机可以随机组合。同时使用benchmark工具对每个节点施加大压力的读写,定期的去校验集群中不同节点的数据以及日志的一致性。一致性相关所有的操作都会记录在X-Cluster专门的日志中,方便追溯集群节点间的交互行为。数据和日志的最终一致性校验交由外部系统来完成。

阿里内部有专门的分片校验系统可以做X-Cluster不同节点的全量数据校验。 Consensus日志解析工具可以快速解析日志内容进行比对。这套测试环境帮助我们发现了非常多的系统BUG。包括实例恢复的BUG,网络异常导致的BUG等等。我们认为一个稳定的版本的标准是一定需要通过这个场景长时间的测试并各种表现符合预期。

除了数据和日志的最终一致性,对于数据的线性一致,事务隔离性,我们引入了Jepsen工具。Jepsen帮助了大量分布式系统发现了分布式协议和实现的正确性问题。我们为X-Cluster专门构造了一系列的测试用例来尽可能覆盖各种异常场景,来发现系统在隔离性和一致性上的问题。

AliSQLX-Cluster与同类的对比

AliSQL X-Cluster不是第一个基于MySQL的强一致集群方案,然而是最适合阿里这样体量的公司的数据库解决方案。对比下面这些同类产品:

Galera

GalaraMariaDB支持的MySQL集群版本,支持强同步,支持多点写入,支持自动的集群配置以及节点Failover,支持行级别的并行复制,支持原生的MySQL客户端。在这套架构下,Slave不会有延时,任意节点读到的都是一致数据,不会有事务数据丢失,读写可扩展。

Galera的集群通信是用了一种基于单令牌环的Totem组播协议。为了能支持多点写入,主机在收到写请求后,会原子广播到组内所有的机器,由它们各自的事务管理层来决定是提交或者回滚。组播由于是P2P的通信,随着节点数增加,延时会放大,响应时间会变慢,并且只适用于低延时的局域网。除此之外组播还有一个问题,如果组内的某台机器宕机,组播会超时,在踢掉fail的机器重新确定组内成员关系之前,整个集群不可服务。

Galera 采用了专门的文件gcache进行增量状态复制,gcache不做任何他用,因此gcache本身需要 额外的计算和存储代价进行维护

GroupReplication

Group ReplicationMySQL 官方出品的集群方案。Group Replication多少是借鉴了Galera的思想,同样支持多主多点写入。Group Replication实现了一个X-COM的通信层,其新版本中已经使用了Paxos算法。目前一个GR集群中最多可以有9 个节点,响应延时相对稳定,在节点同步日志层面, GR使用Binlog,相比Galera更加的通用。

Group Replication的协议层复制是XCOM,且在复制中强依赖GTID。在测试中的性能表现,特别是跨域部署下还达不到需求,目前的版本中也仍然有大量的BUG在修复,完全可用于生产环境还有待后续版本的稳定性和性能提升。

总结

X-Cluster是针对数据质量要求较高的用户推出的全新的数据库解决方案。X-Cluster不仅能够享受到开源社区带来的红利,其中涉及一致性的关键的技术也能够做到完全的自主、可控,能够针对业务的需求进行灵活的变更。未来 X-Cluster会在此基础上做更多的优化,例如支持多分片的Paxos,多节点提供强一致读等功能。随着X-PaxosAliSQL的不断进化,X-Cluster也给大家会带来更多的惊喜。

参考文献


【1】Group Replication is GA with MySQL 5.7.17 – comparison with Galerahttp://lefred.be/content/group-replication-vs-galera/

【2】MySQL HighAvailability Blog http://mysqlhighavailability.com/tag/mysql-group-replication/

【3】Introduction to Galera https://www.slideshare.net/henrikingo/introduction-to-galera

【4】 GALERA CLUSTER DOCUMENTATION

 http://galeracluster.com/documentation-webpages/





如果你对人工智能感兴趣,渴望用算法改变世界;

如果你希望进入阿里,与业界技术大牛并肩作战;

如果你处于职业生涯的十字路口,希望听听前辈的成长经历;

......


今天(8月9日)晚上,参与阿里技术直播,与巅峰相遇,一起对话阿里AI大牛!

识别上图二维码,或是点击文末“阅读原文”即可免费报名参与!




你可能还喜欢

点击下方图片即可阅读



五分钟读懂SIGIR 2017前沿技术研究成果



首次披露!拍立淘技术框架及核心算法,日均UV超千万




关注「阿里技术」 

把握前沿技术脉搏

转载 l 合作 l 投稿

lunalin.lpp@alibaba-inc.com


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/apujo3mbAy
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/2990
 
1034 次点击