关于NoSQL

关于NoSQL云计算背后的秘密 NoSQL 诞生的原因和优缺点我本来一直觉得 NoSQL 其实很容易理解的 我本身也已经对 NoSQL 有了非常深入的研究 但是在最近准备 YunTable 的 Chart 的时候 发现 NoSQL 不仅非常博大精深 而且我个人对 NoSQL 的理解也只是皮毛而已 但我还算是一个 知耻而后勇 的人 所以经过一段时间的学习之后 从本系列第六篇开始 就将和大家聊聊 NoSQL 而本篇将主要给大家做一下 NoSQL

云计算背后的秘密:NoSQL诞生的原因和优缺点

诞生的原因

  1. 庞大运营成本的考量:IT经理们希望在硬件成本、软件成本和人力成本能够有大幅度地降低;

目前世界上主流的存储系统大部分还是采用了关系型数据库,其主要有一下优点:

1.事务处理—保持数据的一致性;

2.由于以标准化为前提,数据更新的开销很小(相同的字段基本上只有一处);

3.可以进行Join等复杂查询。

优缺点

Naresh Kumar是位软件工程师与热情的博主,对于编程与新事物拥有极大的兴趣,非常乐于与其他开发者和程序员分享技术上的研究成果。近日,Naresh撰文比较了NoSQL与RDBMS,并详细介绍了他们各自的特点与适用的场景。

NoSQL并不是关系型数据库管理系统,本文将会介绍NoSQL数据库与关系型数据库之间的差别,同时还会讨论在何种场景下应该使用NoSQL,何种场景下不应该使用。由于NoSQL还是个相对较新的技术,因此它还面临着很多挑战。

时至今日,互联网上有数以亿计的用户。大数据与云计算已经成为很多主要的互联网应用都在使用或是准备使用的技术,这是因为互联网用户每天都在不断增长,数据也变得越来越复杂,而且有很多非结构化的数据存在,这是很难通过传统的关系型数据库管理系统来处理的。NoSQL技术则能比较好地解决这个问题,它主要用于非结构化的大数据与云计算上。从这个角度来看,NoSQL是一种全新的数据库思维方式。

为何要使用NoSQL数据库?

1.NoSQL具有灵活的数据模型,可以处理非结构化/半结构化的大数据

现在,我们可以通过Facebook、D&B等第三方轻松获得与访问数据,如个人用户信息、地理位置数据、社交图谱、用户产生的内容、机器日志数据以及传感器生成的数据等。对这些数据的使用正在快速改变着通信、购物、广告、娱乐以及关系管理的特质。没有使用这些数据的应用很快就会被用户所遗忘。开发者希望使用非常灵活的数据库,能够轻松容纳新的数据类型,并且不会被第三方数据提供商内容结构的变化所累。很多新数据都是非结构化或是半结构化的,因此开发者还需要能够高效存储这种数据的数据库。但遗憾的是,关系型数据库所使用的定义严格、基于模式的方式是无法快速容纳新的数据类型的,对于非结构化或是半结构化的数据更是无能为力。NoSQL提供的数据模型则能很好地满足这种需求。很多应用都会从这种非结构化数据模型中获益,比如说CRM、ERP、BPM等等,他们可以通过这种灵活性存储数据而无需修改表或是创建更多的列。这些数据库也非常适合于创建原型或是快速应用,因为这种灵活性使得新特性的开发变得非常容易。

2.NoSQL很容易实现可伸缩性(向上扩展与水平扩展)

如果有很多用户在频繁且并发地使用你的应用,那么你就需要考虑可伸缩的数据库技术而非传统的RDBMS了。对于关系型技术来说,很多应用开发者会发现动态的可伸缩性是难以实现的,这时就应该考虑切换到NoSQL数据库上。对于云应用来说,关系型数据库一开始是普遍的选择。然而,在使用过程中却遇到了越来越多的问题,原因就在于他们是中心化的,向上扩展而非水平扩展的。这使得他们不适合于那些需要简单且动态可伸缩性的应用。NoSQL数据库从一开始就是分布式、水平扩展的,因此非常适合于互联网应用分布式的特性。

在三层互联网架构的Web/应用层上,多年来向上扩展已经成为默认的扩展方式了。随着应用使用人数的激增,我们需要添加更多的服务器,性能则是通过负载均衡来实现的,这时的代价与用户数量成线性比例关系。在NoSQL数据库之前,数据库层的默认扩展方式就是向上扩展。为了支持更多的并发用户以及存储更多的数据,你需要越来越好的服务器,更好的CPU、更多的内存、更大的磁盘来维护所有表。然而,好的服务器意味着更加复杂、私有、并且也更加昂贵。这与Web/应用层所使用的便宜的硬件形成了鲜明的对比。

3.动态模式

关系型数据库需要在添加数据前先定义好模式。比如说,你需要存储客户的电话号码、姓名、地址、城市与州等信息,SQL数据库需要提前知晓你要存的是什么。这对于敏捷开发模式来说是场灾难,因为每次完成新特性时,数据库的模式通常都需要改变。因此,如果在开发过程中想将客户喜欢的条目加到数据库中,那就得向表中添加这一列才行,然后要做的就是将整个数据库迁移到新的模式上。

4.自动分片

由于是结构化的,关系型数据库通常会垂直扩展,单台服务器要持有整个数据库来确保可靠性与数据的持续可用性。这样做的代价就是非常昂贵、扩展受到限制,并且数据库基础设施会成为失败点。这个问题的解决方案就是水平扩展,添加服务器而不是为单台服务器增加更多的能力。NoSQL数据库通常都支持自动分片,这意味着他们本质上就会自动在多台服务器上分发数据,应用甚至都不知道这些事情。数据与查询负载会自动在多台服务器上做到平衡,当某台服务器当机时,它能快速且透明地被替换掉。

5.复制

大多数NoSQL数据库也支持自动复制,这意味着你可以获得高可用性与灾备恢复功能。从开发者的角度来看,存储环境本质上是虚拟化的。

NoSQL数据库面临的挑战

1.成熟度

RDBMS系统由来已久。NoSQL拥护者们会说RDBMS的高龄是其衰退的标志,不过对于大多数CIO来说,RDBMS的成熟让人放心。对于大多数情况来说,RDBMS系统是稳定且功能丰富的。相比较而言,大多数NoSQL数据库则还有很多特性有待实现。

2.支持

企业需要的是安心,如果关键系统出现了故障,他们可以获得即时的支持。所有RDBMS厂商都在不遗余力地提供良好的企业支持。与之相反,大多数NoSQL系统都是开源项目,虽然每种数据库都有那么几家公司提供支持,不过这些公司大多都是小的初创公司,没有全球支持资源,也没有Oracle、微软或是IBM那种令人放心的公信力。

3.分析与商业智能

NoSQL数据库在Web 2.0应用时代开始出现。因此,大多数特性都是面向这些应用的需要的。然而,应用中的数据对于业务来说是有价值的,这种价值远远超出了Web应用那种CRUD。企业数据库中的业务信息可以帮助改进效率并提升竞争力,商业智能对于大中型企业来说是个非常关键的IT问题。

4.管理

NoSQL的设计目标是提供零管理的解决方案,不过当今的现实却离这个目标还相去甚远。现在的NoSQL需要很多技巧才能用好,并且需要不少人力、物力来维护。

5.专业

全球有很多开发者,每个业务部门都会有熟悉RDBMS概念与编程的人。相反,几乎每个NoSQL开发者都处于学习模式。这种状况会随着时间的流逝而发生改观。但现在,找到一个有经验的RDBMS程序员或是管理员要比NoSQL专家容易多了。

结论

NoSQL数据库正在成为数据库领域的重要力量。如果使用恰当,那么它会带来很多好处。然而,企业应该非常小心并注意到这些数据库的限制与问题。

NoSQL这两年越来越热,尤其是大型互联网公司非常热衷这门技术。根据笔者的经验,并不是任何场景,NoSQL都要优于关系型数据库。下面我们来具体聊聊,什么时候使用NoSQL比较给力:

1) 数据库表schema经常变化
比如在线商城,维护产品的属性经常要增加字段,这就意味着ORMapping层的代码和配置要改,如果该表的数据量过百万,新增字段会带来额外开销(重建索引等)。NoSQL应用在这种场景,可以极大提升DB的可伸缩性,开发人员可以将更多的精力放在业务层。

2)数据库表字段是复杂数据类型

对于复杂数据类型,比如SQL Sever提供了可扩展性的支持,像xml类型的字段。很多用过的同学应该知道,该字段不管是查询还是更改,效率非常一般。主要原因是是DB层对xml字段很难建高效索引,应用层又要做从字符流到dom的解析转换。NoSQL以json方式存储,提供了原生态的支持,在效率方便远远高于传统关系型数据库。

3)高并发数据库请求

此类应用常见于web2.0的网站,很多应用对于数据一致性要求很低,而关系型数据库的事务以及大表join反而成了”性能杀手”。在高并发情况下,sql与no-sql的性能对比由于环境和角度不同一直是存在争议的,并不是说在任何场景,no-sql总是会比sql快。有篇article和大家分享下,http://artur.ejsmont.org/blog/content/insert-performance-comparison-of-nosql-vs-sql-servers

4)海量数据的分布式存储

海量数据的存储如果选用大型商用数据,如Oracle,那么整个解决方案的成本是非常高的,要花很多钱在软硬件上。NoSQL分布式存储,可以部署在廉价的硬件上,是一个性价比非常高的解决方案。Mongo的auto-sharding已经运用到了生产环境。http://www.mongodb.org/display/DOCS/Sharding

并不是说NoSQL可以解决一切问题,像ERP系统、BI系统,在大部分情况还是推荐使用传统关系型数据库。主要的原因是此类系统的业务模型复杂,使用NoSQL将导致系统的维护成本增加。

为什么要使用NoSQL

NoSQL概念
随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一词最早于1998年被用于一个轻量级的关系数据库的名字。)

NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用。比如cdb、qdbm、bdb数据库。

传统关系数据库的瓶颈
传统的关系数据库具有不错的性能,高稳定型,久经历史考验,而且使用简单,功能强大,同时也积累了大量的成功案例。在互联网领域,MySQL成为了绝对靠前的王者,毫不夸张的说,MySQL为互联网的发展做出了卓越的贡献。

在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站不多。

到了最近10年,网站开始快速发展。火爆的论坛、博客、sns、微博逐渐引领web领域的潮流。在初期,论坛的流量其实也不大,如果你接触网络比较早,你可能还记得那个时候还有文本型存储的论坛程序,可以想象一般的论坛的流量有多大。

Memcached+MySQL
后来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技术产品。

Memcached作为一个独立的分布式的缓存服务器,为多个web服务器提供了一个共享的高性能缓存服务,在Memcached服务器上,又发展了根据hash算法来进行多台Memcached缓存服务的扩展,然后又出现了一致性hash来解决增加或减少缓存服务器导致重新hash带来的大量缓存失效的弊端。当时,如果你去面试,你说你有Memcached经验,肯定会加分的。

Mysql主从读写分离
由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。

分表分库
随着web2.0的继续高速发展,在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但是由于在互联网几乎没有成功案例,性能也不能满足互联网的要求,只是在高可靠性上提供了非常大的保证。

MySQL的扩展性瓶颈
在互联网,大部分的MySQL都应该是IO密集型的,事实上,如果你的MySQL是个CPU密集型的话,那么很可能你的MySQL设计得有性能问题,需要优化了。大数据量高并发环境下的MySQL应用开发越来越复杂,也越来越具有技术挑战性。分表分库的规则把握都是需要经验的。虽然有像淘宝这样技术实力强大的公司开发了透明的中间件层来屏蔽开发者的复杂性,但是避免不了整个架构的复杂性。分库分表的子库到一定阶段又面临扩展问题。还有就是需求的变更,可能又需要一种新的分库方式。

MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。

关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

NOSQL的优势

易扩展
NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。

大数据量,高性能
NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。而NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。

灵活的数据模型
NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的web2.0时代尤其明显。

高可用
NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。

总结
NoSQL数据库的出现,弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本。
MySQL和NoSQL都有各自的特点和使用的应用场景,两者的紧密结合将会给web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,NoSQL关注在存储上。

关系数据库还是NoSQL数据库

上一篇简单的说明了为什么要使用NoSQL。接下来我们看下如何把NoSQL引入到我们的项目中,我们到底要不要把NoSQL引入到项目中。

在过去,我们只需要学习和使用一种数据库技术,就能做几乎所有的数据库应用开发。因为成熟稳定的关系数据库产品并不是很多,而供你选择的免费版本就更加少了,所以互联网领域基本上都选择了免费的MySQL数据库。在高速发展的WEB2.0时代,我们发现关系数据库在性能、扩展性、数据的快速备份和恢复、满足需求的易用性上并不总是能很好的满足我们的需要,我们越来越趋向于根据业务场景选择合适的数据库,以及进行多种数据库的融合运用。几年前的一篇文章《One Size Fits All – An Idea Whose Time Has Come and Gone》就已经阐述了这个观点。

当我们在讨论是否要使用NoSQL的时候,你还需要理解NoSQL也是分很多种类的,在NoSQL百花齐放的今天,NoSQL的正确选择比选择关系数据库还具有挑战性。虽然NoSQL的使用很简单,但是选择却是个麻烦事,这也正是很多人在观望的一个原因。

NoSQL的分类

以上NoSQL数据库类型的划分并不是绝对,只是从存储模型上来进行的大体划分。它们之间没有绝对的分界,也有交差的情况,比如Tokyo Cabinet / Tyrant的Table类型存储,就可以理解为是文档型存储,Berkeley DB XML数据库是基于Berkeley DB之上开发的。

NoSQL还是关系数据库
虽然09年出现了比较激进的文章《关系数据库已死》,但是我们心里都清楚,关系数据库其实还活得好好的,你还不能不用关系数据库。但是也说明了一个事实,关系数据库在处理WEB2.0数据的时候,的确已经出现了瓶颈。

那么我们到底是用NoSQL还是关系数据库呢?我想我们没有必要来进行一个绝对的回答。我们需要根据我们的应用场景来决定我们到底用什么。

如果关系数据库在你的应用场景中,完全能够很好的工作,而你又是非常善于使用和维护关系数据库的,那么我觉得你完全没有必要迁移到NoSQL上面,除非你是个喜欢折腾的人。如果你是在金融,电信等以数据为王的关键领域,目前使用的是Oracle数据库来提供高可靠性的,除非遇到特别大的瓶颈,不然也别贸然尝试NoSQL。

然而,在WEB2.0的网站中,关系数据库大部分都出现了瓶颈。在磁盘IO、数据库可扩展上都花费了开发人员相当多的精力来优化,比如做分表分库(database sharding)、主从复制、异构复制等等,然而,这些工作需要的技术能力越来越高,也越来越具有挑战性。如果你正在经历这些场合,那么我觉得你应该尝试一下NoSQL了。

选择合适的NoSQL
如此多类型的NoSQL,而每种类型的NoSQL又有很多,到底选择什么类型的NoSQL来作为我们的存储呢?这并不是一个很好回答的问题,影响我们选择的因素有很多,而选择也可能有多种,随着业务场景,需求的变更可能选择又会变化。我们常常需要根据如下情况考虑:

1.数据结构特点。包括结构化、半结构化、字段是否可能变更、是否有大文本字段、数据字段是否可能变化。

2.写入特点。包括insert比例、update比例、是否经常更新数据的某一个小字段、原子更新需求。

3.查询特点。包括查询的条件、查询热点的范围。比如用户信息的查询,可能就是随机的,而新闻的查询就是按照时间,越新的越频繁。

NoSQL和关系数据库结合
其实NoSQL数据库仅仅是关系数据库在某些方面(性能,扩展)的一个弥补,单从功能上讲,NoSQL的几乎所有的功能,在关系数据库上都能够满足,所以选择NoSQL的原因并不在功能上。

所以,我们一般会把NoSQL和关系数据库进行结合使用,各取所长,需要使用关系特性的时候我们使用关系数据库,需要使用NoSQL特性的时候我们使用NoSQL数据库,各得其所。

举个简单的例子吧,比如用户评论的存储,评论大概有主键id、评论的对象aid、评论内容content、用户uid等字段。我们能确定的是评论内容content肯定不会在数据库中用where content=’’查询,评论内容也是一个大文本字段。那么我们可以把 主键id、评论对象aid、用户id存储在数据库,评论内容存储在NoSQL,这样数据库就节省了存储content占用的磁盘空间,从而节省大量IO,对content也更容易做Cache。

NoSQL作为缓存服务器
MySQL+Memcached的架构中,我们处处都要精心设计我们的缓存,包括过期时间的设计、缓存的实时性设计、缓存内存大小评估、缓存命中率等等。

NoSQL数据库一般都具有非常高的性能,在大多数场景下面,你不必再考虑在代码层为NoSQL构建一层Memcached缓存。NoSQL数据本身在Cache上已经做了相当多的优化工作。

Memcached这类内存缓存服务器缓存的数据大小受限于内存大小,如果用NoSQL来代替Memcached来缓存数据库的话,就可以不再受限于内存大小。虽然可能有少量的磁盘IO读写,可能比Memcached慢一点,但是完全可以用来缓存数据库的查询操作。

规避风险
由于NoSQL是一个比较新的东西,特别是我们选择的NoSQL数据库还不是非常成熟的产品,所以我们可能会遇到未知的风险。为了得到NoSQL的好处,又要考虑规避风险,鱼与熊掌如何兼得?

现在业内很多公司的做法就是数据的备份。在往NoSQL里面存储数据的时候还会往MySQL里面存储一份。NoSQL数据库本身也需要进行备份(冷备和热备)。或者可以考虑使用两种NoSQL数据库,出现问题后可以进行切换(避免出现digg使用Cassandra的悲剧)。

总结
本文只是简单的从MySQL和NoSQL的角度分析如何选择,以及进行融合使用。其实在选择NoSQL的时候,你可能还会碰到关于CAP原则,最终一致性,BASE思想的考虑。因为使用MySQL架构的时候,你也会碰到上面的问题,所以这里没有阐述。


(function () {

(‘pre.prettyprint code’).each(function () { var lines =

(this).text().split(\n).length;var
numbering = $(‘

  • ‘).addClass(‘pre-numbering’).hide(); (this).addClass(hasnumbering).parent().append( numbering); for (i = 1; i
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/228517.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午6:50
下一篇 2026年3月16日 下午6:50


相关推荐

  • pytest指定用例_python测试用例

    pytest指定用例_python测试用例前言测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果.有些同学在写用例的时候,用例写了先后顺序,有先后顺序后,后面还会有新的问题(如:上个用例返回

    2022年7月31日
    16
  • 如何开发股票软件情报分析功能101[通俗易懂]

    如何开发股票软件情报分析功能101[通俗易懂]各种情报铺天盖地,真真假假,虚虚实实,很多是庄家的托放出来的假情报。数据的解读也是一样,各种数据铺天盖地。但是东方大国股市的反应是真的,本周下跌趋势是真的。各种数据和情报分析就是很重要的功能,对于股票软件开发而言。哪些是假情报,哪些是真实的数据,就需要认真分析,不能一股脑传递给散户。突围!国内外局势正发生巨大转向!https://mu.mbd.ba…

    2022年6月21日
    31
  • Redis客户端中文乱码[通俗易懂]

    Redis客户端中文乱码[通俗易懂]Redis客户端中文乱码$redis-cliredis127.0.0.1:6379>set’name”中文’OKredis127.0.0.1:6379>get’name’"\xd6\xd0\xce\xc4"redis127.0.0.1:6379>客户端查看乱码,这个情况我们只要将修改客户端命令行就可以。redis-cli –raw$r…

    2022年5月7日
    233
  • Mac 系统中使用maven 配置环境变量

    Mac 系统中使用maven 配置环境变量Mac系统中配置maven使用Mac系统配置maven环境变量,针对单独用户配置。在~/.bash_profile中配置PATH路径。一、下载maven的zip压缩包下载路径二、配置单独用户的.bash_profile文件1.vim~/.bash_profile2.输入exportMAVEN_HOME=/Users/zhang/Documents/a…

    2022年7月24日
    21
  • MySQL的吞吐量

    MySQL的吞吐量MySQL 的 QPS 吞吐量或者说 TPS 与很多因素有关 例如 CPU 内存以及硬盘等 高性能 MySQL 第三版 1 5 小节对各个版本的 MySQL 进行了测试 其结果如下 测试机器测试机器 CiscoUCSC250 内存 384GB 存储引擎是 InnoDB 测试的数据集 2 5GBMySQL 的 bufferpool 设置为 4GB 从上面的数据看 最大 QPS 不到 8000 对于插

    2026年3月18日
    2
  • hbase 单机安装部署

    hbase 单机安装部署hbase 单机安装部署

    2022年4月23日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号