21.1 nosql介绍
- 非关系型数据库就是NoSQL,关系型数据库代表MySQL 对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很耗费时间和资源,尤其是数据是需要从磁盘里去检索
- NoSQL数据库存储原理非常简单(典型的数据类型为k-v),不存在繁杂的关系链,比如mysql查询的时候,需要找到对应的库、表(通常是多个表)以及字段。
- NoSQL数据可以存储在内存里,查询速度非常快
- NoSQL在性能表现上虽然能优于关系型数据库,但是它并不能完全替代关系型数据库
- NoSQL因为没有复杂的数据结构,扩展非常容易,支持分布式
常见NoSQL数据库
- k-v形式的:memcached、redis 适合储存用户信息,比如会话、配置文件、参数、购物车等等。这些信息一般都和ID(键)挂钩,这种情景下键值数据库是个很好的选择。
- 文档数据库:mongodb 将数据以文档的形式储存。每个文档都是一系列数据项的集合。每个数据项都有一个名称与对应的值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用XML、JSON或者JSONB等多种形式存储。
- 列存储 Hbase
- 图 Neo4J、Infinite Graph、OrientDB
** NoSQL数据库的四大分类**
键值(Key-Value)存储数据库
- 这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort,
Oracle BDB. 列存储数据库。
- 这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.
文档型数据库
- 文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。
图形(Graph)数据库
- 图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。如:Neo4J, InfoGrid, Infinite Graph.
因此,我们总结NoSQL数据库在以下的这几种情况下比较适用:1、数据模型比较简单;2、需要灵活性更强的IT系统;3、对数据库性能要求较高;4、不需要高度的数据一致性;5、对于给定key,比较容易映射复杂值的环境。
21.2 memcached介绍
- Memcached是国外社区网站LiveJournal团队开发,目的是为了通过缓存数据库查询结果,减少数据库访问次数,从而提高动态web站点性能。
- 官方站点http://www.memcached.org/
- 数据结构简单(k-v),数据存放在内存里
- 多线程
- 基于c/s架构,协议简单
- 基于libevent的事件处理
- 自主内存存储处理(slab allowcation)
- 数据过期方式:Lazy Expiration 和LRU
Slab Allocation的原理
- 将分配的内存分割成各种尺寸的块(chunk), 并把尺寸相同的块分成组(chunk的集合),每个chunk集合被称为slab。
- Memcached的内存分配以Page为单位,Page默认值为1M,可以在启动时通过-I参数来指定。
- Slab是由多个Page组成的,Page按照指定大小切割成多个chunk。
Growth factor
- Memcached在启动时通过-f选项可以指定 Growth Factor因子。该值控制chunk大小的差异。默认值为1.25。
- 通过memcached-tool命令查看指定Memcached实例的不同slab状态,可以看到各Item所占大小(chunk大小)差距为1.25
- 命令:# memcached-tool 127.0.0.1:11211 display
Memcached的数据过期方式
- Lazy Expiration:Memcached 内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。因此,Memcached不会在过期监视上耗费CPU时间。
- LRU:Memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除“最近最少使用”的记录的机制。因此,当内存空间不足时(无法从slab class获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。
21.3 安装memcached
- memcached可以通过yum安装,当然也可以去官网下载相应的源码包进行编译安装,如果是初次接触的话,先用最简单的安装方式或许会比较好一点,先来看看yum中可以安装的memcached版本:
[root@aming2 ~]# yum list |grep memcached libmemcached.x86_64 1.0.16-5.el7 @base memcached.x86_64 1.4.15-10.el7_3.1 @base libmemcached.i686 1.0.16-5.el7 base libmemcached-devel.i686 1.0.16-5.el7 base libmemcached-devel.x86_64 1.0.16-5.el7 base memcached-devel.i686 1.4.15-10.el7_3.1 base memcached-devel.x86_64 1.4.15-10.el7_3.1 base opensips-memcached.x86_64 1.10.5-3.el7 epel php-ZendFramework-Cache-Backend-Libmemcached.noarch php-pecl-memcached.x86_64 2.2.0-1.el7 epel python-memcached.noarch 1.48-4.el7 base uwsgi-router-memcached.x86_64 2.0.16-1.el7 epel
- 安装包:
yum install -y memcached libmemcached libevent
- 启动memcached服务:
systemctl start memcached
- 查看进程:
[root@aming2 ~]# ps aux|grep memcached memcach+ 1217 0.0 0.1 325604 1196 ? Ssl 14:02 0:00 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024 127.0.0.1 root 1224 0.0 0.0 112720 980 pts/0 R+ 14:02 0:00 grep --color=auto memcached
想要更改启动的配置选项有俩种办法
- 第一种是使用绝对路径来启动,然后通过选项来指定参数,例如:
/usr/bin/memcached -u memcached -p XXXX -m 32 -c 2024
- 第二种方式是修改配置文件:
[root@aming2 ~]# vi /etc/sysconfig/memcached [root@aming2 ~]# cat /etc/sysconfig/memcached PORT="11211" USER="memcached" MAXCONN="1024" CACHESIZE="64" OPTIONS="127.0.0.1"
- 如果需要加上监听的ip,可以把OPTIONS="" 改为OPTIONS="127.0.0.1"
21.4 查看memcached状态
三种方式查看memcached状态:
自带工具memcached-tool 命令:memcached-tool 127.0.0.1:11211 stats
或者echo stats |nc 127.0.0.1 11211 需要安装nc工具yum install -y nc
若安装libmemcached后,可以使用命令
memstat --servers=127.0.0.1:11211 查看memcached服务状态
[root@aming2 ~]# memcached-tool 127.0.0.1:11211 stats #127.0.0.1:11211 Field Value accepting_conns 1 auth_cmds 0 auth_errors 0 bytes 0 bytes_read 7 bytes_written 0 cas_badval 0 cas_hits 0 cas_misses 0 cmd_flush 0 cmd_get 0 cmd_set 0 cmd_touch 0 conn_yields 0 connection_structures 11 curr_connections 10 curr_items 0 decr_hits 0 decr_misses 0 delete_hits 0 delete_misses 0 evicted_unfetched 0 evictions 0 expired_unfetched 0 get_hits 0 get_misses 0 hash_bytes 524288 hash_is_expanding 0 hash_power_level 16 incr_hits 0 incr_misses 0 libevent 2.0.21-stable limit_maxbytes 67108864 listen_disabled_num 0 pid 1217 pointer_size 64 reclaimed 0 reserved_fds 20 rusage_system 0.123812 rusage_user 0.017687 threads 4 time 1535094151 total_connections 11 total_items 0 touch_hits 0 touch_misses 0 uptime 3607 version 1.4.15
- 我们平时需要关注get_hits(命中数量)以及curr_items(存在memcached中的项目)的值,使用get_hits的值除以curr_items的值,可以计算出命中率。这是为了检测memcached是否有缓存了数据以及是否能被正常的访问这些缓存的数据
21.5 memcached命令行
- 利用telnet命令连接memcached数据库
yum install -y telnet telnet 127.0.0.1 11211
[root@aming2 ~]# telnet 127.0.0.1 11211 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'
- 使用set命令创建数据:
set key1 0 30 2 12 STORED
解析:set key1 0 30 2 set: 创建数据命令(command name) key2: 创建一个名为key1的key (key) 0 : 特殊标记位(flags) 30 : 定义这个数据的过期时间为30秒(exptime) 2 : 定义这个key所能够存储的value长度,单位是字节 (bytes)
获取数据:(不超时)超时则值不存在
get key1 VALUE key1 0 2 12 END get key2 VALUE key2 0 3 abc END
Memcached语法规则 <command name> <key> <flags> <exptime> <bytes>\r\n <data block>\r\n 注:\r\n在windows下是Enter键 <command name> 可以是set, add, replace set表示按照相应的<key>存储该数据,没有的时候增加,有的时候覆盖 add表示按照相应的<key>添加该数据,但是如果该<key>已经存在则会操作失败 replace表示按照相应的<key>替换数据,但是如果该<key>不存在则操作失败。 <key> 客户端需要保存数据的key <flags> 是一个16位的无符号的整数(以十进制的方式表示)。该标志将和需要存储的数据一起存储,并在客户端get数据时返回。客户端可以将此标志用做特殊用途,此标志对服务器来说是不透明的。 <exptime> 为过期的时间。若为0表示存储的数据永远不过期(但可被服务器算法:LRU 等替换)。如果非0(unix时间或者距离此时的秒数),当过期后,服务器可以保证用户得不到该数据(以服务器时间为标准)。 <bytes> 需要存储的字节数,当用户希望存储空数据时<bytes>可以为0 <data block>需要存储的内容,输入完成后,最后客户端需要加上\r\n(直接点击Enter)作为结束标志。
21.6 memcached数据导出和导入
- 因为memcached的数据是存储在内存中的,当服务需要重启的时候,需要先让memcached里的数据写到磁盘中,不然数据会丢失。所以介绍一下memcached如何导出和导入数据。
- memcached中添加了如下几个不过期的数据:
[root@aming2 ~]# telnet 127.0.0.1 11211 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. set name 1 0 5 12345 STORED set name 1 0 2 12 STORED
添加完之后,按CTRL+]然后输入quit退出telnet
- 查看memcached的状态如下:
[root@aming2 ~]# memcached-tool 127.0.0.1 stats #127.0.0.1:11211 Field Value accepting_conns 1 auth_cmds 0 auth_errors 0 bytes 71 bytes_read 228 bytes_written 1148 cas_badval 0 cas_hits 0 cas_misses 0 cmd_flush 0 cmd_get 8 cmd_set 6 cmd_touch 0 conn_yields 0 connection_structures 11 curr_connections 10 curr_items 1 decr_hits 0 decr_misses 0 delete_hits 0 delete_misses 0 evicted_unfetched 0 evictions 0 expired_unfetched 1 get_hits 1 get_misses 7 hash_bytes 524288 hash_is_expanding 0 hash_power_level 16 incr_hits 0 incr_misses 0 libevent 2.0.21-stable limit_maxbytes 67108864 listen_disabled_num 0 pid 1217 pointer_size 64 reclaimed 2 reserved_fds 20 rusage_system 0.148276 rusage_user 0.049425 threads 4 time 1535095979 total_connections 17 total_items 5 touch_hits 0 touch_misses 0 uptime 5435 version 1.4.15
-
其中 cmd_set: 6 是刚刚创建的数据项目数量;delete_hits: 刚删除的项目;
-
把数据导出:
[root@aming2 ~]# memcached-tool 127.0.0.1:11211 dump > data.txt Dumping memcache contents Number of buckets: 1 Number of items : 1 Dumping bucket 1 - 1 total items
- 查看导出文件内容:
[root@aming2 ~]# cat data.txt add name 1 1535090544 2 12
-
注意:导出的数据是带有一个时间戳的,这个时间戳就是该条数据过期的时间点,如果当前时间已经超过该时间戳,那么是导入不进去的,其中1535090544这样的就是时间戳
-
重启服务后将数据导入到memcached里并获取数据:
[root@aming2 ~]# systemctl restart memcached [root@aming2 ~]# nc 127.0.0.1 11211 < data.txt STORED
如果导入后发现没有数据,这是因为备份文件里记录的时间戳已经过期了,可以修改文件中的时间戳保证数据的有效期。可以写一个简单的脚本批量替换这些文件中的时间戳:
[root@aming2 ~]# vi replace.sh #!/bin/bash hour=`date -d "+1 hour" +%s` data_time=`cat data.txt |grep add |awk '{print $4}' |sort -n |uniq` for i in $data_time do sed -i "s/$i/$hour/g" `grep $i -rl /root/data.txt` done [root@aming2 ~]# sh replace.sh
再次导入:
[root@aming2 ~]# nc 127.0.0.1 11211 < data.txt
21.7 php连接memcached
- 在LNMP、LAMP等环境下,我们需要让php与memcached进行交互,就像php与mysql交互那样,php也得通过某个模块连接memcached后,才能进行数据的呈现、交互等操作。
- 先安装php的memcache扩展,我这里的php是LNMP环境的并且在之前已经安装好了,所以现在进行扩展即可:
[root@aming2 ~]# cd /usr/local/src/ [root@aming2 src]# wget http://www.apelearn.com/bbs/data/attachment/forum/memcache-2.2.3.tgz --2018-08-24 16:47:16-- http://www.apelearn.com/bbs/data/attachment/forum/memcache-2.2.3.tgz 正在解析主机 www.apelearn.com (www.apelearn.com)... 47.104.7.242 正在连接 www.apelearn.com (www.apelearn.com)|47.104.7.242|:80... 已连接。 已发出 HTTP 请求,正在等待回应... 200 OK 长度:27366 (27K) [application/octet-stream] 正在保存至: “memcache-2.2.3.tgz” 100%[==============================================================================>] 27,366 --.-K/s 用时 0.07s 2018-08-24 16:47:16 (390 KB/s) - 已保存 “memcache-2.2.3.tgz” [27366/27366]) [root@aming2 src]# tar zxf memcache-2.2.3.tgz [root@aming2 src]# cd memcache-2.2.3 [root@aming2 memcache-2.2.3]# ls config9.m4 CREDITS memcache_consistent_hash.c memcache_queue.h php_memcache.h config.m4 example.php memcache.dsp memcache_session.c README config.w32 memcache.c memcache_queue.c memcache_standard_hash.c [root@aming2 memcache-2.2.3]# /usr/local/php-fpm/bin/phpize # 生成config文件 Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226 Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script.
安装M4、AUTOCONF包
# yum install m4 # yum install autoconf
编译安装:
[root@aming2 memcache-2.2.3]# /usr/local/php-fpm/bin/phpize Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226 [root@aming2 memcache-2.2.3]# ./configure --with-php-config=/usr/local/php-fpm/bin/php-config [root@aming2 memcache-2.2.3]# make && make install Installing shared extensions: /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
- 安装完后会有类似这样的提示:Installing shared extensions: /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/ 会在这个路径下生成memcache.so的文件
[root@aming2 memcache-2.2.3]# ls /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/ memcache.so opcache.a opcache.so
- 然后修改php.ini添加一行extension="memcache.so“
[root@aming2 memcache-2.2.3]# vim /usr/local/php-fpm/etc/php.ini 找到extension= 添加一行extension="memcache.so"
- 检查/usr/local/php-fpm/bin/php -m里是否有memcache模块:
[root@aming2 memcache-2.2.3]# /usr/local/php-fpm/sbin/php-fpm -m|grep memcache memcache
下载测试脚本
curl www.apelearn.com/study_v2/.memcache.txt > 1.php 2>/dev/null
- 执行测试脚本:
[root@aming2 memcache-2.2.3]# /usr/local/php-fpm/bin/php 1.php Get key1 value: This is first value<br>Get key1 value: This is replace value<br>Get key2 value: Array ( [0] => aaa [1] => bbb [2] => ccc [3] => ddd )
- 或者将1.php放到某个虚拟主机根目录下面,在浏览器访问,即可看到效果
21.8 memcached中存储session
-
在负载均衡集群中,用户第一次访问的是A服务器,并且在该服务器上登录了账户,这个登录信息就保存在session中。由于是集群的关系,所以用户可能下一次再访问的时候就不是访问到A服务器上,而是访问到B服务器上了。但是之前的session却保存在A服务器上,那么用户在B服务器上就只能重新登录一次,因为在B服务器上并没有session信息。所以为了让集群中的服务器都能够共享session,就可以把session存储在一个memcached服务器中,所有的web服务器往这台memcached服务器上读session信息,就能做到简单的session共享。
-
查看session存放方式
vim /usr/local/php-fpm/etc/php.ini session.save_handler = files
files表示sesision存放在本地/tmp/,每产生一个session会产生一个文件
- 把会话文件存到memcached,如下操作: php-fpm.conf对应的pool中添加以下两行:
[root@aming2 ~]# vim /usr/local/php-fpm/etc/php-fpm.conf php_value[session.save_handler] = memcache php_value[session.save_path] = " tcp://192.168.222.111:11211"
- 重启服务,测试
[root@aming2 ~]# /etc/init.d/php-fpm restart [root@aming2 ~]#wget http://study.lishiming.net/.mem_se.txt [root@aming2 ~]#mv .mem_se.txt /data/wwwroot/default/1.php [root@aming2 ~]#curl localhost/1.php
进入memcached命令行,看看有没有存储到对应的session数据。