事件缘起
有网友注意到了,近上线之由逐浪CMS官方团队维护的全新bootstrap v4.0中文镜像与使用手册(网址http://code.z01.com/v4 )的搜索非常快,而且调用的是一个外部搜索文件(search.js),支持全文检索,这是一种什么样的技术?
事实上,这就是当前流行NoSQL技术的应用一则。
(上图:在逐浪CMS中部署NoSQL服务指引)
技术背景
人们一直觉得NoSQL其实很容易理解的,我本身也已经对NoSQL有了非常深入的研究,但是在近准备YunTable的Chart的时候,发现NoSQL不仅非常博大精深,而且我个人对NoSQL的理解也只是皮毛而已,但我还算是一个“知耻而后勇”的人,所以经过一段时间的学习之后,从本系列第六篇开始,就将和大家聊聊NoSQL,而本篇将主要给大家做一下NoSQL数据库的综述。
首先将和大家聊聊为什么NoSQL会在关系型数据库已经非常普及的情况下异军突起?
诞生的原因
随着互联网的不断发展,各种类型的应用层出不穷,所以导致在这个云计算的时代,对技术提出了更多的需求,主要体现在下面这四个方面:
1. 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度;
2. 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量;
3. 大规模集群的管理:系统管理员希望分布式应用能更简单的部署和管理;
庞大运营成本的考量:IT经理们希望在硬件成本、软件成本和人力成本能够有大幅度地降低;
目前世界上主流的存储系统大部分还是采用了关系型数据库,其主要有一下优点:
1.事务处理—保持数据的一致性;
2.由于以标准化为前提,数据更新的开销很小(相同的字段基本上只有一处);
3.可以进行Join等复杂查询。
虽然关系型数据库已经在业界的数据存储方面占据不可动摇的地位,但是由于其天生的几个限制,使其很难满足上面这几个需求:
1. 扩展困难:由于存在类似Join这样多表查询机制,使得数据库在扩展方面很艰难;
2. 读写慢:这种情况主要发生在数据量达到一定规模时由于关系型数据库的系统逻辑非常复杂,使得其非常容易发生死锁等的并发问题,所以导致其读写速度下滑非常严重;
3. 成本高:企业级数据库的License价格很惊人,并且随着系统的规模,而不断上升;
4. 有限的支撑容量:现有关系型解决方案还无法支撑Google这样海量的数据存储;
业界为了解决上面提到的几个需求,推出了多款新类型的数据库,并且由于它们在设计上和传统的NoSQL数据库相比有很大的不同,所以被统称为“NoSQL”系列数据库。总的来说,在设计上,它们非常关注对数据高并发地读写和对海量数据的存储等,与关系型数据库相比,它们在架构和数据模型方量面做了“减法”,而在扩展和并发等方面做了“加法”。现在主流的NoSQL数据库有BigTable、HBase、Cassandra、SimpleDB、CouchDB、MongoDB和Redis等。接下来,将关注NoSQL数据库到底存在哪些优缺点。
优缺点
在优势方面,主要体现在下面这三点:
1. 简单的扩展:典型例子是Cassandra,由于其架构是类似于经典的P2P,所以能通过轻松地添加新的节点来扩展这个集群;
2. 快速的读写:主要例子有Redis,由于其逻辑简单,而且纯内存操作,使得其性能非常出色,单节点每秒可以处理超过10万次读写操作;
3. 低廉的成本:这是大多数分布式数据库共有的特点,因为主要都是开源软件,没有昂贵的License成本;
4.
但瑕不掩瑜,NoSQL数据库还存在着很多的不足,常见主要有下面这几个:
1. 不提供对SQL的支持:如果不支持SQL这样的工业标准,将会对用户产生一定的学习和应用迁移成本;
2. 支持的特性不够丰富:现有产品所提供的功能都比较有限,大多数NoSQL数据库都不支持事务,也不像MS SQL Server和Oracle那样能提供各种附加功能,比如BI和报表等;
3. 现有产品的不够成熟:大多数产品都还处于初创期,和关系型数据库几十年的完善不可同日而语;
上面NoSQL产品的优缺点都是些比较共通的,在实际情况下,每个产品都会根据自己所遵从的数据模型和CAP理念而有所不同,接下来,将给大家介绍NoSQL两个重要的概念:数据模型和CAP理念,并在本文后,对主流的NoSQL数据库进行分类。
Naresh Kumar是位软件工程师与热情的博主,对于编程与新事物拥有极大的兴趣,非常乐于与其他开发者和程序员分享技术上的研究成果。近日,Naresh撰文比较了NoSQL与RDBMS,并详细介绍了他们各自的特点与适用的场景。
NoSQL并不是关系型数据库管理系统,本文将会介绍NoSQL数据库与关系型数据库之间的差别,同时还会讨论在何种场景下应该使用NoSQL,何种场景下不应该使用。由于NoSQL还是个相对较新的技术,因此它还面临着很多挑战。
时至今日,互联网上有数以亿计的用户。大数据与云计算已经成为很多主要的互联网应用都在使用或是准备使用的技术,这是因为互联网用户每天都在不断增长,数据也变得越来越复杂,而且有很多非结构化的数据存在,这是很难通过传统的关系型数据库管理系统来处理的。NoSQL技术则能比较好地解决这个问题,它主要用于非结构化的大数据与云计算上。从这个角度来看,NoSQL是一种全新的数据库思维方式。
技术选型
那么如何部署NoSQL技术模型呢?
一般说来有两种方法,一是自主部署NoSQL数据库(环境)软件,一是采用第三方云计算公司提供的NoSQL服务。
后者无疑是方便的部署方式。
由Algolia提供的搜索服务,即是其中的杰的代表(官网:http://www.algolia.com/)
关于Algolia的基本认识:
法国一家初创公司(现在已经是业界搜索技术的主流供应商了),类似于存储云服务,计算云服务,提供的是搜索云服务,用户建立应用,接着通过sdk推送数据,然后通过sdk就可以搜索了。
目前QPS(query per second)保持在1万以上,近一年内融资将近2亿元。
基础架构采用物理隔离,单应用单cluster,多个小应用可能共享一个cluster。
不会存储应用的原始数据。应用数据进入后,直接建立索引。
同一应用数据全球多地部署,其中只有一个master,其他都是slave,master负责建立索引,然后通过文件形式同步到其他机房。
同一cluster内部多个副本,采用multi-write方式,保证终一致性。
应用数据都是通过sdk推送进来后,直接通过实时系统建立了索引,然后就可以立即查询了。所以,时效性非常高。
实施过程
在网站开发中,很重要的一个功能那就是搜索了。对于一个访问量很大的网站来说,对于所有的搜索请求直接读取数据库来完成将会造成非常大的负荷。两种办法可以有效地解决以上问题,种就是缓存,memcached
,redis
等都很有名气,在这里就不予赘述了。
那么第二种就是使用云搜索。什么是云搜索?类似于CDN
,我们把数据库内可以用于被搜索的信息推送至云端,然后用户在我们的网站进行搜索时,实际上搜索请求并没有发送给我们的服务器,而是被传递到云服务器进行搜索,并返回相应的结果。这样的解决方案可以大大降低网站的延迟,并提高应用的性能。现在比较有名的Algolia
就提供了云搜索的服务。
具体办法是我们将数据库的信息以JSON
的格式上传到Algolia
服务器,然后通过相应的API进行搜索。搜索既可以是实时的(采用Javascript
调用Algolia API
),也可以是后端的(使用PHP
调用Algolia API
)。
图片中可以看到,我使用了javascript
实现了前端实时搜索,这样不仅高效,而且对用户友好。Algolia
的免费许可允许上传10,000
条JSON
数据,每月允许100,000
次操作(包括上传和搜索),还是相当不错的。今天我们将要使用Javascript来实现Algolia
的实时搜索功能,框架我选用的是新的jQuery
。好了,那我们这就开始。首先前往Algolia
官网:http://www.algolia.com注册好之后,我们就可以登录dashboard
控制和管理我们的数据了。
注意,我们在上图中左边第三个钥匙按钮中,可以找到我们需要的API Keys
:
我们需要的是Application ID
,Search-Only API Key
和Admin API Key
。注意:Admin API KEY
一定不要放在js
里,因为这个key
是用来上传,删除和操作我们的云端数据的,所以一定要保管好。
有了key之后,当然就要着手开始上传我们的数据了。一个很简单的方法就是先把我们数据库数据导出成JSON
文件后,使用algolia API
的上传功能,直接上传至服务器。不过如果数据进行了更新,并不能实时反应在搜索中。我将会在另一篇文章中介绍如何使用Laravel Scout
来进行数据的实时上传与更新。
首先我们需要把数据库的数据push
到云端服务器。假设我们的数据库里有一个叫contacts
的table
,包含了客户联系人的数据,我们已经将这个table
导出成JSON
形式的文件:contacts.json
。有了这个JSON
文件后,我们就可以着手开始push
数据到云端了。现在我们新建一个js
文件,并填入以下代码:
var index = client.initIndex('contacts');var contactsJSON = require('./contacts.json');index.addObjects(contactsJSON, function(err, content) { if (err) { console.error(err); }});12345678
可以看到,以上的代码中,我们要建立一个叫contacts
的索引,这个索引名称将在以后的搜索中使用到,每次搜索contacts table
中的数据时,我们都需要先call
一次client.initIndex('contacts')
。
剩余的代码就是将我们的JSON
文件上传到algolia
服务器。
好了,数据库的数据我们已经上传到服务器端了,现在我们就可以开始搜索了!首先我们需要引入algolia
的js
库:
<script src="https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script>1
接着我们新建一个叫instant-search
的js
文件,然后添加以下代码:
var client = algoliasearch("Application ID", 'Search-Only API Key'); var contact_index = client.initIndex('contacts'); var search_input_string = 'some-contacts-to-search'; contact_index.search(search_input_string, function (err, contacts) { for (var i = 0; i < contacts.hits.length; i++) { // Code to deal with each contact } });12345678910
我们可以看到,首先我们需要我们的Application ID
及Search-Only API Key
来初始化,接着我们使用contacts
这个索引来搜索。search_input_string
在这里为了方便说明我用的是固定的字符串,而实际上我们应该动态获取搜索框中的字符串来进行实时搜索。contact_index.search
这个函数会将搜索到的结果放在contacts.hits
中,所以我们可以使用一个loop来处理每一个返回的结果,比如把每一个结果添加上相应的<a></a>
并加入到搜索结果的list
中。
后总结
我在CodePen
上做好了一个instant-search
的template
:
https://codepen.io/lgyaxx/project/full/XmYyBX/
方便大家观看效果。另外我把代码上传到github
了,包括了instant-search
的逻辑。大致的概念就是每当搜索框有新的input
,那么记录下这个input
,等待一定的时间(例如1s或者2s),再次获取input
,看跟之前的搜索串是否有不同,如果有不同,那么就搜索新的字符串,如果没有不同,那么就搜索旧的字符串。这样的延时机制可以有效地避免用户在搜索字符串还没打完的时候就进行多次搜索了。
当然,我使用了jQuery
框架并且结合了Bootstrap 4
,大家可以自己发挥来实现所需的UI。还有需要注意的是,Algolia
免费版需要把logo
放在搜索结果旁边,这是官方要求,切记。
综合本案中,我们是采用:
<link href="../assets/css/docsearch.min.css" rel="stylesheet">
以及
<script src="../assets/js/docsearch.min.js"></script>
两段代码结合,已经内置好了样式,非常好用。