整合NoSQL---MongoDB及Session共享
本篇继续学习如何整合非关系型数据库(NoSQL),主要是MongoDB的整合,顺便学习如何进行Session的共享。
MongoDB简介
MongoDB是一种面向文档的数据库管理系统,它是一个介于关系型数据库和非关系型数据库之间的产品,MongoDB功能丰富,它支持一种类似JSON的BSON数据格式,既可以存储简单的数据格式,也可以存储复杂的数据类型。MongoDB最大的特点是它支持的查询语言非常强大,且支持对数据建立索引。总的来说,MongoDB是一款应用相当广泛的NoSQL数据库。
MongoDB安装
目前MongoDB最新版为4.4.1,但是为避免一些问题,此处依然使用4.0.0版本,安装环境选择CentOS7,安装的步骤如下:
第一步,下载MongoDB。进入到home目录下执行如下命令下载MongoDB:
1 | wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.0.tgz |
下载完成后,将下载的MongoDB解压,并将解压后的文件夹重命名为mongodb,可执行如下命令:
1 | tar -zxvf mongodb-linux-x86_64-4.0.0.tgz |
第二步,配置MongoDB。进入到第一步中的mongodb目录下,创建两个文件夹db和logs,分别用来保存数据和日志,使用的命令如下:
1 | cd monngodb |
接着进入到bin目录(mongodb目录自带的目录)下,新建一个新的MongoDB配置文件mongo.conf
,里面的代码为:
1 | dbpath=/home/mongodb/db |
简单解释一下上述的配置信息:dbpath表示数据存储目录;logpath表示日志文件位置;port表示启动端口;fork=true
表示以守护程序的方式启动MongoDB,也就是运行MongoDB在后台运行。
第三步,MongoDB的启动和关闭。配置完成后,还是在bin目录下,运行如下命令来启动MongoDB
:
1 | ./mongod -f mongo.conf --bind_ip_all |
上述命令中的-f
表示指定配置文件的位置,--bind_ip_all
则表示允许所有的远程地址连接该MongoDB实例。MongoDB启动成功后,在bin目录下再执行mongo命令,即可进入到MongoDB的控制台,然后输入db.version()
,如果能看到MongoDB的版本号,则表示MongoDB就已经安装成功:
默认情况下,启动后连接的是MongoDB中的test库,而关闭MongoDB的命令需要在admin库中执行,因此关闭MongoDB首先需要切换到admin库,然后执行db.shutdownServer();
命令,完整的操作步骤为:
1 | use admin; |
服务关闭后,执行exit退出MongoDB控制台,此时如果再执行./mongo
命令就会执行失败,如下图所示:
第四步,MongoDB安全管理。默认情况下,启动的MongoDB是没有登录密码的,这在生产环境中是非常不安全的,但是不同于MySQL、Oracle等关系型数据库,MongoDB中每一个库都有独立的密码,在哪一个库中创建用户就需要在哪一个库中验证密码。要配置密码,首先需要创建一个用户,如在admin库中创建一个用户,代码如下(需要进入到MongoDB控制台下)
1 | use admin; |
新创建的用户名为envy,密码为123,roles表示该用户具有的角色,这里的配置表示该用户对test库具有读和写两项权限:
用户创建成功后,关闭当前实例,然后重新启动,启动命令如下:
1 | ./mongod -f mongo.conf --auth --bind_ip_all |
启动成功后,再次进入控制台,然后切换到admin库中验证登录(默认连接上的库是test库),验证成功后就可以对test库执行读写操作了,代码如下:
1 | ./mongo |
如果db.auth("envy","123");
命令执行结果为1,则表示认证成功,可以对test库执行读写操作了:
MongoDB整合SpringBoot
借助于SpringData MongoDB
,SpringBoot 为MongoDB也提供了开箱即用的自动化配置方案,具体的配置步骤如下:
第一步,创建SpringBoot Web项目并添加依赖。使用spring Initializr
构建工具构建一个SpringBoot的Web应用,名称为mongodbspringboot
,然后在pom.xml文件中添加如下依赖:
1 | <dependency> |
第二步,配置MongoDB。在application.properties
文件中配置MongoDB的连接信息,代码如下:
1 | # 验证信息登录库 |
第三步,创建实体类。新建pojo包,并在其中新建Book类,里面的代码为:
1 | public class Book { |
第四步,创建BookDao。新建一个dao包,并在其中新建一个BookDao接口,需要继承MongoRepository
接口。其实BookDao的定义类似于Spring Data JPA中的Repository的定义,BookDao接口文件里中的代码为:
1 | public interface BookDao extends MongoRepository<Book,Integer> { |
MongoRepository
接口中已经预定义了针对实体类的查询、添加、删除等操作,因此可以仿照Spring Data JPA的例子和方法命令规则来定义查询方法。
第五步,创建BookController。新建一个controller包,并在其中新建一个BookController类,处于简单考虑这里就不创建Service层,相应的代码为:
1 | @RestController |
第六步,测试。运行项目,在浏览器地址栏中输入http://localhost:8080/test
,可以看到控制台打印日志信息:
1 | [Book{id=2, name='彷徨', author='鲁迅'}] |
此时可以登录到MongoDB服务器,认证身份后,在test库中即可查询到刚刚插入的数据,如下图所示:
第七步,使用MongoTemplate。在dao 接口文件中除了继承MongoRepository
接口外,Spring Data MongoDB
还提供了MongoTemplate
用来更加方便地操作MongoDB。在SpringBoot中,若添加了MongoDB相关的依赖,而开发者并没有提供MongoTemplate
时,此时SpringBoot默认会有一个MongoTemplate
注解到Spring容器中,相关配置源码可以在MongoDataAutoConfiguration
类中。因此用户可以直接使用MongoTemplate
,只需要在controller中直接注入MongoTemplate
就可以使用了。可以将第五步的BookController
文件修改为如下:
1 | @RestController |
运行项目,在浏览器地址栏中输入http://localhost:8080/test
,可以看到控制台打印日志信息:
1 | [Book{id=1, name='西游记', author='吴承恩'}, Book{id=2, name='彷徨', author='鲁迅'}, Book{id=3, name='三国演义', author='罗贯中'}, Book{id=4, name='且介亭文集', author='鲁迅'}] |
当然也可以去MongoDB服务器上查看数据是否已经保存成功:
那么这样关于SpringBoot整合MongoDB的内容就学习完了。
Session共享
正常情况下,HTTPSession是通过Servlet容器创建并进行管理的,创建成功之后都是保存在内存中。如果开发者需要对项目进行横向扩展搭建集群,那么可以利用一些硬件或者软件工具来作负载均衡,此时来自同一用户的HTTP请求就有可能被分发到不同的实例上去,如何保证各个实例之间Session的同步就成为一个必须解决的问题。SpringBoot提供了自动化的Session共享配置,它结合Redis可以非常方便地解决这个问题。使用Redis解决Session共享问题的原理非常简单,就是把原本存储在不同服务器上的Session拿出来放在一个独立的服务器上,如下图所示:
当一个请求到达Nginx服务器后,首先进行请求分发,假设请求被图中的real server1处理了,real server1在处理请求时,无论是存储Session还是读取Session,都去操作Session服务器而不是操作自身内存中的Session,其他real server在处理请求时也是如此,这样就可以实现Session共享了。
Session共享配置
SpringBoot中的Session共享配置非常容易,按照下面的步骤进行即可:
第一步,新建项目并添加Redis和Session依赖。使用spring Initializr
构建工具构建一个SpringBoot的Web应用,名称为sessionspringboot
,然后在pom.xml文件中添加如下依赖:
1 | <dependency> |
除了Redis依赖外,这里还需要提供spring-session-data-redis
依赖,SpringSession可以做到透明化地替换掉应用的Session容器。
第二步,配置数据库连接信息。项目创建成功后,在application.properties
配置文章中进行Redis的基本连接信息配置,相应的代码为:
1 | spring.redis.database=0 |
第三步,创建controller并进行测试。新建controller包,并在其中新建HelloController
类,里面的代码为:
1 | @RestController |
这里提供了两个方法,一个save接口用来向Session中存储数据,还有一个get接口用于从Session中获取数据,这里注入了项目启动的端口号server.port
,主要是为了区分到底是哪个服务器提供的服务。另外,虽然还是HttpSession,但实际上HttpSession容器已经被透明替换,真正的Session此时储存在Redis服务器上。
项目创建完成以后,将项目打包成jar包上传到CentOS上,然后依次执行如下两条命令来启动项目:
1 | nohup java -jar sessionspringboot-0.0.1-SNAPSHOT.jar --server.port=8080 & |
nohup表示不挂断程序运行,即当终端窗口关闭后,程序依然在后台运行,最后的&表示让程序在后台运行。--server.port
表示设置启动端口,一个为8080,一个为8081。启动成功后,接下来就可以配置负载均衡器了。
Nginx负载均衡
本例子使用Nginx做负载均衡,因此首先需要在CentOS上安装Nginx,安装过程如下:
第一步,下载源码并解压。使用如下命令下砸nginx源码并解压:
1 | wget https://nginx.org/download/nginx-1.14.2.tar.gz |
然后进入解压目录中执行编译安装,使用的命令如下:
1 | cd nginx-1.14.2 |
安装成功后,找到Nginx的安装目录,执行sbin目录下的nginx文件启动nginx,使用的命令如下:
1 | /usr/local/nginx/sbin/nginx |
Nginx启动成功后,默认端口是80,可以在物理机直接进行访问(服务器需要在安全组中开放80端口访问权限):
接下来进入到Nginx安装目录使用vi /usr/local/nginx/conf/nginx.conf
命令来修改其配置文件nginx.conf
,需要编辑以下内容:
1 | ...... |
注意这里仅仅只列出了修改的配置,在修改的配置中首先配置上游服务器,即两个real server,两个real server的权重都是1,意味2这请求将平均分配到两个real server上,然后在server中配置拦截规则,将拦截到的请求转发到定义好的real server上。
配置完成后,启动Nginx,重启命令如下:
1 | /usr/local/nginx/sbin/nginx -s reload |
请求转发
当real server和Nginx都启动后,调用/save
接口来储存数据,打开postman测试工具,以post方式提交并输入以下信息http://47.100.175.12:80/save?name=余思
,可以发现后台输出8080。此处调用的端口是80,也就是调用的是Nginx服务器,请求会被Nginx转发到real server上进行处理,返回值为8080,说明真正处理请求的real server是8080那台服务器。
接下来调用get接口获取数据,打开postman测试工具,以get方式提交并输入以下信息http://47.100.175.12:80/get
,可以发现后台输出8081:余思
。调用的端口依然是80,也就是调用的是Nginx服务器,但是返回值是8081,说明是8081那台real server提供的服务,如果这里不是8081,再访问一次即可。
经过如上步骤就完成了利用Redis实现Session共享的功能,基本上不需要额外的配置,开箱即用。
整合NoSQL数据库小结
在第九篇中介绍了SpringBoot如何整合Redis,而在第十篇中介绍了如何整合MongoDB,以及结合Redis实现了Session共享。对应NoSQL数据库,此处仅仅介绍了较为常见的两种:Redis和MongoDB。MongoDB在一些场景中甚至可以完全替代关系型数据库,而Redis更多的使用场景则是作为缓存服务器,这一点在后续将会学习到,开发者可以根据自己实际情况选择合适的NoSQL。