开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术:NoSQL 4】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/76/detail/15775
NoSQL 4
内容介绍:
一、mangoDB 的一个例子
二、mango DB具体实现
三、非切分客户端与切分客户机
四、When to Shard
五、Chunk
六、切分机制
七、mango DB小结
八、Sanguo App例子
上一节在关于数据库上,由于每一种手机的参数不一样,所以必须要把列转换成行来存储,才能让不同的手机带不同的参数,但这样一来,数据库必须要拆成表,要拆成两张表,所以在后面做任何一种操作,按参数去找到手机,先要在参数里面找,找到符合要求的ID或者是ID的集合,再到mobiles表里再去找,实际上要做一个join操作,就显得很慢。
一、mangoDB 的一个例子
在mangoDB的世界里有一个mobiles Collection。
1.存iphone
往里面存iphone的时候,name是iphone,品牌是Apple,参数是一个数组,数组里面放的是一堆的document。document有参数的名字和它的值,这是待机时间和屏幕,另外有一个红色专门标出来叫做quality的一个属性是增加的,比如3S级别,整个在mobiles的collection上建个索引,按照参数的name去做索引,在参数name都相同的情况下,按照值做索引都是升序,这是iphone的手机的插入。
2. 存三星手机S10
再插入一个三星手机S10 ,前两个是一样的,也是name和brand,参数里面也是一样,参数里前两个也都一样,但第三个属性就不是前面的quality,它强调价格很吸引人。
3.两个手机不同点
同样在mobiles里面的两个Document里面含的内容是不一样的,首先来看,只有一个collection,bells存储在Mexico里面两张表的信息,表是把name和brand拿出来,把Parameters存成了行,又是一张表,现在在一个collection里面就可以存储。
其次两个collection有差异,在parameters里面的包含的内容,一个参数叫做price,另一个叫做quality,也就是说,没有要求在mobiles里面的两个document上所有的内容结构要是一样,这就是所谓的Schema- free的意思,不要求数据一定要遵循标准的格式,上图中红颜色画出来就属于格式不一样的地方。
4.mangoDB与MYSQL相比
mangoDB第一个特点就是Schema- free,可以存不一样的东西。第二个特点就是由于关系型数据库表的约束,必须是两张表,现在只有一个collection,它和关系型数据库有两个表相比,很显然不存在关联操作的动作,所以查找就会比较容易实现,数据会较快。
5.查找操作的例子
要查在mobiles里面的参数。满足底下这两个条件的参数,两个条件是待机时间要大于100,屏幕是oled,搜出来的是苹果手机,如果执行下面搜索,待机时间要大于100,并且价格吸引人,这时候所搜到的就是三星手机。
6.具体的操作程序
具体的操作程序就是把上面命令复制下来,到控制台里面去搜就可以。这是iphone的那个手机搜出来的结果。
如果执行下面操作的话,就只能搜出来三星的手机,这是三星的S10,
7.搜索简单
它的强大之处是在于两个搜索查找的内容是不一样的,一个是price,一个是screen,而且在整个collection里面。一个document有price,另一个没有,一个有quality另一个没有,所以一个在查price,另一个在查screen。三星和苹果的手机都有前两个属性,第一个查找没什么特别,但是第二个查找就比较特殊,price是只有三星有苹果是没有,但是照样可以查,不会报错,这就是它强大的地方。
(1)、可以查大家共有的东西,也可以去查可能某一些document有,另外一些document的没有的东西。
(2)、现在搜索不存在所谓的像数据库关系和数据库里面类似jion的操作。所以速度就会比较快。
(3)另外一点更重要的是,没有要求所有的数据是一样的结构,所以可以把不一样结构的数据存到一起,变成一个collection,比如课程,把所有的课程存到数据库model DB里,在存成一个collection的时候,有的课程是录播的有video,有课件,还有一些其他的文本资料,但有的是课程是直播的,没有Video事后才能补上去,在这种情况下,尽管大家结构不一样,也可以把这些课程存到一个collection。
比如直播没有video,但它可能有上课聊天的聊天记录,录播的课是没有聊天记录,但是它有video,就会有一些差异,也可以全部都存到一个collection,
在my SQL的关系性数据库里是做不到的,必须要把它拆成至少两张表,然后把其中一张表变成是列转行的存储,再存储它们不同的东西。
二、mango DB具体实现
1. 切分
NoSQL 时候讲很重要的一点是因为需要分布式的存储,所以才用到了NoSQL ,关系型数据库在分布存储时候非常效率比较低,因为不能把有关联关系的几张表正好分到不同的机器上,存储的时候保证所有的数据,不需要做连接,所以在做分布存储的时候比较弱,所以出现了NoSQL 。
(1)、mango DB里面的collection没有collection和collection之间关联,Collection就是一个线性的表,只不过里面的所有的刀片,可以有不一样的结构,总的来说,它的存储格式是线性,随便切一刀就能够把数据切成两部分,存在两台机器上。它做分布存储的制叫Shard,或者用Sharding来表示,碎片的意思。
(2)、把数据切成碎片去存储,就允许在多台机器上存储,而且机器可以不断的增加,去应对不断提升的系统的压力和数据的尺寸,
(3)、人为的可以做Sharding,但后续工作难以维护。
(4)、mango DB数据库自动做Sharding,当数据存到服务器上存的太多之后,自动一切为二,存到两台机器上,如果新加入一台机器,能不能把这数据再迁移过来,变成在三台机上平均存储。
2.mango DB自动切片
如果数据是切开存储的,因为所有的NoSQL数据库都来自于big table,跟big table道理一样,要有一个地方去存储到底,什么样的Shard的上面存储数据信息,所谓的需要一个路由,请求来之后,都是在访问路由,路由在查找相应的配置,然后知道要访问数据在哪个Shard的server上。
Shard server 是在存储被切成了小块之后的数据,是一个物理上的概念。两台服务器叫两个Shard server,可以存collection上面的切成小块后的东西,比如说collection a被切成了collection a1 collectiona2和 collectiona3三块,这三块就在两台机器上存储,这三块就叫chunks。
Shard server的作用就是维护,在存储大的collection切成chunks之后的小的chunks,所以需要一个配置,配置里面就记录a被切成了三个chunk,其中一和二存储在S1服务器上,第三块存储在服务器S2上,以此类推。
其实所有的collection都需要这样一个描述,描述文件是所有应用在访问的一个入口点,只有访问到,才能知道要访问的collection数据在哪里。
三、非切分客户端与切分客户机
需要一个路由,在访问的时候,如果后台就一台机器就Client,像刚才演示的直接访问就可以。如果后台有多个节点构成了一个集群,在它的前面一定需要一个mangos 的服务器,就是mango Shard服务器与client交互,mangos 会根据要查找的数据查配置文件,知道到哪个机器后台shut down去访问数据这样一个过程。
四、When to Shard
1. 什么时候去Shard?
磁盘空间如果用完,就会去做Shard的动作,为什么mango DB会自动切开数据以后,把一部分数据放到另外一台机器上,就是硬盘空间快满了,就要去做这样的事情,所以Shard server是自动来做这个事。
2. server是怎么做的?
collection每一个数据里面都有一个key。然后用Key的范围来划分数据。在person这个collection里面,插入的一Shard是曹操,二是刘备,三是孙权,可能会插入更多的人,假设插入1000个人,于是表里面可能会有从一直到一千,在进行划分的时候,把一到100划分成一个块就是chunk,101到200换成一个chunk,201到300换一个chunk,以此类推,一直到最后901到1000,就变成了十个chunk,十个chunk分布到mango DB的Shard server上,比如有三台机器,就会去记录chunk1在在哪,chunk2在哪等等。所以,配置文件就会去记录一个collection分成了多少个chunk,它们的key的范围是什么样的,然后每一个chunk都在哪个Shard server上存储,只要记住配置信息就可以。
当要去找一个ID为201的人的时候,在这个配置文件里,首先根据key的range,就知道这个人在哪个chunk里。再去查这个chunk在哪个Shard sever上存储。在这个Shard sever上就可以把数据取出来了。
五、Chunk
1.切分原理
Chunk里包含里所定范围里所有的documents,如果加入一个新的服务器会把mango DB,collection里,还没有被切开过,只是一个Chunk,它就会切成两个Chunk去存储,如果已经切开成两个Chunk,那会做成甚至更Chunk去平衡这些Chunk。
2.如果切成了十个Chunk
有两台服务器存储,写简单一点,12345在一块,六七八九十在另一块,当加入一台新服务器之后,下次监测到新服务器之后,发现前两台机器数据过多要迁移一些过来,比如把四、五和十迁到第三个服务器,就会看到这样一个结构,是3、4、3的一个结构,差异就比较小,这添加一台服务器之后,它要做的事情。
六、切分机制
整个意思可以引用一个图来看,key从负无穷大到正无穷大都有可能,把数据切成了5块,然后这些块就会存储到不同的Shard serve上。
1.自动平衡机制
mango DB里会有自动平衡机制。平衡服务器上Chunk的数量的差异是小于等于2,一旦发现超过的,比如Chunk2如果拿掉,就会发现Shard2里是两个,Shard1有五个就违反了约定,mango DB就会自动做一个平衡。在Shard1随机选中一个迁到Shard2,保证所有的Shard server上面存储的数据量差不多,这是mango DB背后的存储机制。
2. 限制前提
mango DB听起来不错,可以保证所有的服务器上面存储的数据量大体相当。但有一个前提条件,所有的数据被访问的概率差不多。
(1)、控制数据量一样。比如Shard放的是新闻,Shard1虽然放的很多,但它放的是上个月的新闻。Shard2上面虽然放的很少,但放的是今天的新闻,很显然,Shard2放的数据量很少访问压力也会变得很大,因为大家看今天的新闻肯定比较多,不太会去看上个月的新闻。所以如果硬靠存储量平衡的话,Shard2已经很忙,Shard1还要把数据迁到Shard2,前提是所有的数据被访问的概率是均等,这种情况下,打开mango DB的自动平衡,这种机制是比较好,否则的话,应该把这个机制关掉。
(2)、控制访问量相等。靠人为的写代码去控制它,让所有的机器上面不是数据量差不多,而是访问的压力差不多。比如Shard2机器上是今天的新闻,就不应该这么存。今天新闻如果有三块,应该是三台机上各有一块,如果要这样做,就不是自动平衡机就能解决了,需要写代码去维护,有很多研究,包括实验室有一些研究正在解决这个问题,如果感兴趣可以去看一看。
七、mango DB小结
后面讲的不太理解的话,至少有一点应该知道,数据是可以做分布存储,靠Sharding的分布存储,在多台机器上去存储,它是在应对mySQL关系性数据库不容易做分布存储问题,总结一下mango DB是什么?
1、第一个,开始讲的问题,就是没法分布存储,数据库做不到这一点,或者做到之后性能很差,所以出现了no SQL数据库。在no SQL虽然自称是not only SQL,但实际上确实可以认为它就是no SQL,它没有relationship,没有表和表之间的关联。
2、第二个是既然表都没有关联,而且是no SQL没有结构化。所以schema- free ,因为结构化要把表拆开,然后去做表和表之间的关联操作,就像刚才举的手机的例子,之所以schema- free,是因为在大数据的场景之下,数据源很多,很难去要求所有的数据具有相同的结构,关系型数据库不能胜任的问题。
3、现在讲的no SQL, mango db严格意义上讲就是一个key value的数据库当中的一种,value依据它的类型,还有人说key object value。mango db绝不是唯一的一种。
加入这个内容,一方面数据库主要是以关于数据库为主,要知道还存在其他数据库,大三,还会再去讨论,图数据库,讨论日志数据库,讨论其他的东西,要明白数据库未必只有关系数据库一种。
另外一个问题,要学会在两个数据库之间存放数据之后,怎么同时去读写它们,怎么把它们向上层去屏蔽掉它的差异。
八、Sanguo App例子
给一个例子,怎么去把person的数据存储在两种不同的数据库里。把人的数据怎么存在关系型数据库和非关系型数据库里,然后一起去进行访问。
1.用户访问
假设在描述三国的人物,三国人物它有姓名,年龄等等这些数据,这是结构化的,每个人都有,把它存在MYSQL里面,在上面可以按ID来查找,它还有一个icon,这个数据就在mango DB,通过这个例子可以看到,没有去让用户感受到这件事情,用户就在上框里输入他想找的人。一点OK,这些数据都返回了。
2.代码是怎么写的
在关系数据库里,利用之前映射的时候数据库里面就会有人的信息,有ID、 age、 first name、 last name,另外一个是在test,mango DB里面有一个personicon的collection。它里面就会有ID和一个叫做icon base64的一个建支队,它的名字值就是把图像放到BASE64的开源的网站上,转出来的字符串放进去。
下图是用刚才的客户端去看到的里边的内容,就用它把字符串写进去,
3.person icon.java
(1)、先看person icon定义,还是用到的spring的东西,在里面看到的是它是个document,它映射的那个collection叫做person icon,就是在刚才的数据库里看到的person icon,collection里是写的三个人字符串,就是图像返过来字符串。
(2)、注意方面
在这里面,有ID,要用ID来标示一下。另外还有iconBase64和数据库里的名字一样,所以不用做其他的特殊的处理,然后要注意的是要靠spring的template或者是Porsche把东西从数据库里读出来放进去,所以必须要写set get的方法,Set让spring把东西设计,Get是将来要获取里面的东西,把它展现出来。
这是person icon的用处。
(3)、 person的前一半就是person的ID 、age、 person last name,在my SQL里面,整个前面内容和之前的一模一样,那就说它是个实体,它映射的表,是spring jpa,要去防止循环依赖的问题,要加这样东西。前一半儿没有做任何改动,唯一的就是在底下做了一个事情,其他地方都没动,就是复用之前的代码,就是前面映射,属性,去关联参加的event,email,全都没动在复用之前的类,只在里面加了底下这段代码。
(4)、这段新加的什么意思?最重要的是transient,里面有个叫icon的一个属性,它是person icon类型的,然后对它有GET3,真正的idolation就transient一个,在讲hypocrite或者是spring gpa的时候,提到的它其实不是hibernate或者spring的icnotation是Java gpa标准的规范的icnotation。icnotation的意思是在说一个瞬时的数据,
(5)、瞬时的数据是什么?就是告诉gpa的工具,做or映射的工具。这个字段别管,在ORM眼里就是原来的transient,transient就是字面意思就知道它是在说顺时的,Or工具把做的操作反应到数据库里,数据库在硬盘上,硬盘是掉了电之后数据仍然在的,所以它是一种持久化的数据。,持久化的数据当然不是瞬时,瞬时的是指一掉电就没了,它只存在内存里,顺势的就告诉or有些工具说我就在内存里放一下,就别管,不要去持久化。其实写它的目的不是数据在内存里,其实也在硬盘上,在mango DB里,只是想让or工具不要管。让别的东西管,就是要用mango DB的reposit来管理。
4.Personrepository.java
(1)、会写两个reposit。第一个是在复制之前的代码仍然没有动,它是个gpa的repository,它会管理除person icon之外的所有东西。第二个是mango repostry,它专门管理person icon。
这两个东西都会是spring去生成他们俩的实现类,并没有没有自己去做,因为两个接口里面已经定义了一些标准的方法,可以拿来直接用了,所以没有再定义其他额外的东西,然后他可以帮我们生成相应的类,
(2)、关键就在于Dao,要定义一个find one这样一个方法,因为在刚才的例子里面,做了一个让用户输入ID的一个输入框,点击OK就拿到了,按照ID来拿数据来定一个find one,给一个ID,然后应该是dao。Do you implementation。
(3)、Dao是怎么实现的?里面有一个person repository,还有个person icon repository,注意他俩都Autowired让spring拿去到工程编译出来在哪里,找实现它俩接口的东西,spring拿到这两个接口自动生成实现了它俩的类就。于是就给注入进来。注入进来之后find one要先用关系型数据库,person repository调用它的get one方法,get one方法是reports里面预先定义好的,传ID,用ID来查找数据,它读完之后自然就会组装一个person数据出来。这时候person里面它就有了first name、 last name、 email这样的一些东西,但是没有icon,icon是空的,在底下又通过repository里面一个find by ID方法,然后把同样的ID给了它,就会返回东西,然后,report返回的东西是Optional<personicon>icon的类型。
(4)、只要在icon对象里面,去get一下就能拿到它里面包的person icon,先判断一下到底里面有没有,如果有就get一下出来,通过person对象的set icon方法,就把icon设进去,现在person里面就有了icon,如果没找到,就说明这个人没有图像存在mangoDB。就给这个人的icon设个空,然后在控制台上输出一个“这是空的”,
不管怎么操作,最后person里面所有的东西都有,就把它返回,这就是dao的实现。
(5)、前面service代码有没有在动,而且和之前的代码是一模一样的,定一个接口传一个东西进来,然后通过dao的find one方法去找到想要查的东西,分层的好处就在这里,在dao层把底下数据来源的这件事情全部都封装在find one方法里,然后暴露出来find one,在他之上的层就看不到这个差异,所以到底数据在哪里,这些事情都不是要去关心的,只关心调用dau的find one方法,就能返回来一个对象。至于person到底数据在哪全部被dao混装,上层不用管。
所以一再强调接口事件分离,接口事件分离,然后左分层,就这个道理。
(6)、跟dao类似,很显然controller也不用管,不用改,它持有一个service,从路径里面的参数传进来一个ID,然后调service的findPersonByld ID就拿到它,这是一个rest controller,所以它返回的时候,返回值是一个person类型。会把person自动转成一个Json返回去,这就是看到的后台代码。
5.回顾后台代码
其实就是在person类里面加了一点东西,然后专门定义了一个针对这个东西的person icon。在dao这一层,拿出去的时候,一部分是通过report拿的,另外一部分是mango DB,通过底下report拿的,再往上所有代码都没有动,跟原来是一样。
6.前台
现在来看一下前台,前台为了方便起见,没有用框架去写,没有复杂的框架,直接下了一个j query,之前给你们讲阿贾克斯的时候提到过这块,然后里头发了个请求出去,就是有一个页面上有一个button,
这个BUTTON一点击它就执行底下参数,发了个get的阿贾克斯请求出去。是get person,然后在取who里面的值,拼到get person上。WHO就是上图底下划线的。输入框输入什么,就在这里拼。
这样一个路径拼出去之后,就和find person/id匹配起来被它处理,然后执行完回调这个函数在data里面,而data,这边用的是rest controller,所以它返回来都已经转成Json,于是在data里面取first name加空格,再加last name去替换掉name标签里的内容。所以name标签一开始空的,同样的age和icon也是这样放的,那么age就在data里面。
7.取到icon
关键是看icon。icon是怎么拿到的?在下图可以看到image对象,
Image对象是有source属性,Source属性之前写的都是它等于一个相对路径,但是它另外一种写法就是source等于BASE64值,
(1)、BASE64值在哪里?Jason发回来的时候要取person icon属性person icon里面本身又包含了ID和icon base。就在取person icon的person base 64值,也就是Jason回来的时候就有first name比如说cao,有last name:cao,AGE:60,然后是Person icon里面有个数组:它的ID:1,ICON base 64,就是那一串字符串,
所以就通过这种方式把那串字符串拿出来,base 64如果直接附给一个image类型的source属性,它就会把它显示出来。所以base 64那么大概的意思就是说,其实看到的所有的东西,它在数据存储的时候,都是以0101这样的位来存储,能把一张图片拿过来,把它当成0101被解析成字符,或者说把它解析成字符串儿去处理。
所以想法就是把一张图片变成字符串儿,遵循一定格式的字符串去处理,到时来会传递。传到前端之后,你如果告诉这个emage的source字符串,再把传过来的字符串,比如说AB2037这样的字符串,再按照图片的格式给解析出来去呈现,就做这样一个事情,整个工程的代码就是这个样子。
8.前台简化
只想把例子写的简单一点,在后台仍然是按照分层的架构去做的,而且controller service都没有动,在repos tree里面加了一个,然后其他的都没动,然后entity里面加了一个,然后改了一个,改的只是在里面添加新,没有改原来的代码,然后关键的时间就在Dao里面改动的比较大,它是在访问底下的两个reposche得到的结果,而对上层就屏蔽掉了它的差异。
9.例子结果
如果跑一下这一个例子,其实之前也给大家看过。例子在poster里面,是不能给它的代码实现的,因为它是个接口,要想让它定义新的方法,写个get person,要在上面用query去描述一下,然后spring拿到后再生成接口的实现内容会把逻辑实现,就是把它实现给添加到get questions的方法体,然后跑一下试试看,当然跑话就是后台mango DB和MYSQL都要运行起来,要去找一号,就是曹操54岁,这张图片比较大,那可以看到这是一个结果,
二号人物,就是刘备,然后三号人物孙权就是这样一个例子,
这个例子本身是数据源确实是来自于两个地方,但是从代码可以看到,通过分层的架构,通过处理,其实有很多东西是没有动的。
10.就这个例子在回答几个问题,
(1)、第一个就是反复强调的为什么要做分层架构。
(2)、第二就是为什么在request的基础上,还要一个dao层,如果没有这一层该怎么做,想怎么做?而且做完之后要对其他代码的影响就几乎没有,怎么能做得到?这个例子是一个能说明这些问题,其实现在没有什么必须要用mango DB的需求,
(3)、讲mango DB的意义在讲明白数据源可能会来自不同的地方,而且no SQL和SQL的差异是什么,真正在大作业里想用的时候怎么用?一种可以像这样给举个例子,把图片存到mango DB里。但其实这不是最佳的一个方案,最佳的方案是什么?
(4)、举个例子,不代表必须要实现。假设书有很多人看之后发表一些书评,然后书评,就有点像微博,它还可以有跟帖、跟帖甚至还有跟帖,这样一个结构要想存到关系型数据库里怎么存?
显然它不太适合,如果非要存进去,它要做连接操作,自连接,自己跟自己连接,才知道谁是谁的根条,才能把整个这书评给它展示出来。但是如果把整个书评给它存入到mango DB里,事情就会不一样,就会变得很简单。
这是一种可能的场景,然后没有约束一定要怎么做,但是应该去体现两种数据库的访问,简单点就像把图片存进去,这是有关mango db。
刚才例子里面没有mango conflict,例子比较简单,它所以里面它不需要写那个东西,如果碰到复杂的其他的就是有很多项配置,可以写到一个类。