Nosql(一)_memcached

部署环境

Name Version
CentOS 7 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
NoSQL  
Memcached memcached.x86_64 0:1.4.15-10.el7_3.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

Memcached介绍

  • Memcached是国外社区网站LiveJournal团队开发,目的是为了通过缓存数据库查询结果,减少数据库访问次数,从而提高动态web站点性能。

  • 官方站点 http://www.memcached.org/ 

  • 数据结构简单(k-v),数据存放在内存里(重启该服务,数据会丢失;数据很重要必须保存到mysql)

  • 多线程

  • 基于c/s架构,协议简单

  • 基于libevent的事件处理

  • 自主内存存储处理(slab allowcation)

  • 数据过期方式:Lazy Expiration 和 LRU

Memcached的数据流向

Slab allocation

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获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。

Memcached安装

# yum install -y memcached

安装memcached的前提是要先安装libevent,可以rpm -qa查看一下,实际上系统已经安装好,我们直接yum安装memcached就好。

# rpm -qa libevent
libevent-2.0.21-4.el7.x86_64

启动memcached,-u指定用户,-p指定监听的端口,-m分配内存多大单位M,-c最大的并发数。

# systemctl start memcached
# ps aux |grep memcached
memcach+  1774  0.0  0.0 325604  1196 ?        Ssl  20:17   0:00 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024
root      1781  0.0  0.0 112720   972 pts/0    R+   20:17   0:00 grep --color=auto memcached
# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      1774/memcached

如果要指定参数有两种方法,其实各参数都不用怎么改,改下-m就够了。

1、不要用systemctl start memcached目录启动服务,改为/usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024绝对命令启动,各选项后面参数自定义。

2、vim /etc/sysconfig/memcached 可以配置参数,比如加上监听的ip,可以把OPTIONS="" 改为OPTIONS="127.0.0.1" ;其中-m指定memcached分配内存, -c指定最大并发数, -u指定运行memcached服务的用户。

查看Memcached运行状态

可以用memcached本身自带的工具

# 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        1774
            pointer_size          64
               reclaimed           0
            reserved_fds          20
           rusage_system    0.030205
             rusage_user    0.080107
                 threads           4
                    time  1534682827
       total_connections          11
             total_items           0
              touch_hits           0
            touch_misses           0
                  uptime        1808
                 version      1.4.15

重要的两个参数:curr_items 0和get_hits 0;项目数和命中的个数,两者可以相除得出命中率。

也可以用nc工具,但要先安装

# yum install -y nc
...
已安装:
  nmap-ncat.x86_64 2:6.40-13.el7

查看命令

# echo stats |nc 127.0.0.1 11211
STAT pid 1774
STAT uptime 2519
STAT time 1534683538
STAT version 1.4.15
STAT libevent 2.0.21-stable
STAT pointer_size 64
STAT rusage_user 0.109273
STAT rusage_system 0.046831
STAT curr_connections 10
STAT total_connections 12
STAT connection_structures 11
STAT reserved_fds 20
STAT cmd_get 0
STAT cmd_set 0
STAT cmd_flush 0
STAT cmd_touch 0
STAT get_hits 0
STAT get_misses 0
STAT delete_misses 0
STAT delete_hits 0
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 13
STAT bytes_written 1025
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT bytes 0
STAT curr_items 0
STAT total_items 0
STAT expired_unfetched 0
STAT evicted_unfetched 0
STAT evictions 0
STAT reclaimed 0
END

查看memcached的服务状态,需要先安装libmemcached

# yum install -y libmemcached
...
已安装:
  libmemcached.x86_64 0:1.0.16-5.el7

查看

# memstat --servers=127.0.0.1:11211
Server: 127.0.0.1 (11211)
     pid: 1774
     uptime: 2902
     time: 1534683921
     version: 1.4.15
     libevent: 2.0.21-stable
     pointer_size: 64
     rusage_user: 0.129316
     rusage_system: 0.048493
     curr_connections: 10
     total_connections: 13
     connection_structures: 11
     reserved_fds: 20
     cmd_get: 0
     cmd_set: 0
     cmd_flush: 0
     cmd_touch: 0
     get_hits: 0
     get_misses: 0
     delete_misses: 0
     delete_hits: 0
     incr_misses: 0
     incr_hits: 0
     decr_misses: 0
     decr_hits: 0
     cas_misses: 0
     cas_hits: 0
     cas_badval: 0
     touch_hits: 0
     touch_misses: 0
     auth_cmds: 0
     auth_errors: 0
     bytes_read: 30
     bytes_written: 2070
     limit_maxbytes: 67108864
     accepting_conns: 1
     listen_disabled_num: 0
     threads: 4
     conn_yields: 0
     hash_power_level: 16
     hash_bytes: 524288
     hash_is_expanding: 0
     bytes: 0
     curr_items: 0
     total_items: 0
     expired_unfetched: 0
     evicted_unfetched: 0
     evictions: 0
     reclaimed: 0

Memcached命令行

先安装telnet

# yum install -y telnet
...
已安装:
  telnet.x86_64 1:0.17-64.el7

进入memcached,进入后不要乱按,memcached不像mysql这样好用,输入错误很容易出错;set key2 0 30 2中的最后的2代表输入2位的数据,接着的30是过期时间为30秒,过了30秒之前存储的2位数据就会被清除

# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
ERROR
set key2 0 30 2
ab
STORED
get key2
VALUE key2 0 2
ab
END
set key1 020 3
ERROR
set key1 0 20 3
123
STORED
get key1
VALUE key1 0 3
123
END
get key2
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)作为结束标志。

Memcached数据示例:set存储(可覆盖)、add增加(不可覆盖)、replace替换、delete删除

set key3 1 100 4
asbd
STORED
get key3
VALUE key3 1 4
asbd
END
replace key3 1 1000 6
123456
STORED
get key3
VALUE key3 1 6
123456
END
delete key3
DELETED
get key3
END

memcached退出:按键Ctrl+]输入quit即可退出memcached

Memcached数据导出和导入

先保存几个永久的数据:

# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set zyshan 1 0 6
zyshan
STORED
set jj 1 0 3
sai
STORED
set uu 1 0 2
12    
STORED
^]
telnet> quit
Connection closed.
# memcached-tool 127.0.0.1:11211 dump
Dumping memcache contents
  Number of buckets: 1
  Number of items  : 3
Dumping bucket 1 - 3 total items
add jj 1 1534681019 3
sai
add uu 1 1534681019 2
12
add zyshan 1 1534681019 6
zyshan

导出、导入:导入失败,是由于该数据已存在,add不能覆盖,所有要重启服务清除数据后,再导入就成功。

ps:想清除数据,只要重启服务或机器都可以。

# memcached-tool 127.0.0.1:11211 dump > data.txt
Dumping memcache contents
  Number of buckets: 1
  Number of items  : 3
Dumping bucket 1 - 3 total items
# cat data.txt 
add jj 1 1534681019 3
sai
add uu 1 1534681019 2
12
add zyshan 1 1534681019 6
zyshan
# nc 127.0.0.1 11211 < data.txt 
NOT_STORED
NOT_STORED
NOT_STORED
# systemctl stop memcached
# systemctl start memcached
# nc 127.0.0.1 11211 < data.txt 
STORED
STORED
STORED

虽然导入成功,但进入查看却没有数据:是因为数据被导出的时候,系统给了该数据一个时间戳,是失效时间,该时间戳比当前时间戳小所以导入的数据就失效了,所以没有数据;如果想导入有效数据,必须修改导出的数据的时间戳。

# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get zyshan
END
get uu
END
get jj
END
^]
telnet> quit
Connection closed.
当前时间戳# date +%s
1534687874
数据的时间戳都比当前的时间戳小所以失效# cat data.txt 
add jj 1 1534681019 3
sai
add uu 1 1534681019 2
12
add zyshan 1 1534681019 6
zyshan
当前时间1小时后的时间戳# date -d "+1 hour" +%s
1534691421
修改导出数据# vi data.txt
add jj 1 1534691421 3
sai
add uu 1 1534681019 2
12
add zyshan 1 1000 6
zyshan
重启服务清除数据# systemctl stop memcached
# systemctl start memcached
再次导入数据# nc 127.0.0.1 11211 < data.txt 
STORED
STORED
STORED
导入的数据可以查看到了,确实于时间戳有关# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get jj
VALUE jj 1 3
sai
END
get uu
END
get zyshan
VALUE zyshan 1 6
zyshan
END
^]
telnet> quit
Connection closed.

总结:导出的数据是带有一个时间戳的,这个时间戳就是该条数据过期的时间点,如果当前时间已经超过该时间戳,那么是导入不进去的

PHP连接Memcached

查看php的模块

# /usr/local/php-fpm/sbin/php-fpm -m
[PHP Modules]
cgi-fcgi
Core
ctype
curl
date
dom
ereg
exif
fileinfo
filter
ftp
gd
hash
iconv
json
libxml
mbstring
mcrypt
mysql
mysqli
openssl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
Reflection
session
SimpleXML
soap
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
​
[Zend Modules]

没有memcache这个中间件,需要下载,先进入目录

# cd /usr/local/src

下载包

# wget http://www.apelearn.com/bbs/data/attachment/forum/memcache-2.2.3.tgz

解压下载的包

# tar zxf memcache-2.2.3.tgz

注意:memcache不是memcached,它是php的一个扩展,也就是各源码包需要编译安装。

再进入到解压后的目录

# cd memcache-2.2.3/

编译前需要先生成configure文件

# /usr/local/php-fpm/bin/phpize
Configuring for:
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226

接着

# ./configure --with-php-config=/usr/local/php-fpm/bin/php-config

检查命令是否正确

# echo $?
0
# make
...
安装后有路径的提示,可以查看一下# make install
Installing shared extensions:     /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
# ls /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/
memcache.so  opcache.a  opcache.so

要的就是memcache.so

然后修改php.ini在;extension=php_shmop.dll后面添加一行

# vi /usr/local/php-fpm/etc/php.ini
...
;extension=php_shmop.dll
extension=memcache.so

是否成功,查看php的模块中是否存在memcache,该模块是存在的,所以安装成功。

# /usr/local/php-fpm/sbin/php-fpm -m
[PHP Modules]
cgi-fcgi
Core
ctype
curl
date
dom
ereg
exif
fileinfo
filter
ftp
gd
hash
iconv
json
libxml
mbstring
mcrypt
memcache
mysql
mysqli
openssl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
Reflection
session
SimpleXML
soap
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib
​
[Zend Modules]

下载测试脚本

# curl www.apelearn.com/study_v2/.memcache.txt > 1.php 2>/dev/null

查看脚本内容

# cat 1.php
<?php
//连接Memcache Memcache
$mem = new Memcache;
$mem->connect("localhost", 11211);
//保存数据
$mem->set('key1', 'This is first value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val ."<br>";
//替换数据
$mem->replace('key1', 'This is replace value', 0, 60);
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br>";
//保存数组数据
$arr = array('aaa', 'bbb', 'ccc', 'ddd');
$mem->set('key2', $arr, 0, 60);
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br>";
//删除数据
$mem->delete('key1');
$val = $mem->get('key1');
echo "Get key1 value: " . $val . "<br>";
//清除所有数据
$mem->flush();
$val2 = $mem->get('key2');
echo "Get key2 value: ";
print_r($val2);
echo "<br>";
//关闭连接
$mem->close();
?>

执行脚本,如出现以下内容即成功

# /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放到某个虚拟主机根目录下面,在浏览器访问,即可看到效果最终可以看到数据如下: [0] => aaa [1] => bbb [2] => ccc [3] => ddd

Memcached中存储session

在负载均衡里用来Nginx的ip_hash的算法可以把用户的登录信息固定在同一个web服务器上;另外一种方法就是把Memcached中存储session,同样也可以达到这种需求。

  • 本实例是在lamp/lnmp环境下实现

  • 编辑php.ini添加两行

  • session.save_handler = memcache

    session.save_path = "tcp://192.168.0.9:11211"

  • 或者httpd.conf中对应的虚拟主机中添加

  • php_value session.save_handler "memcache" 

    php_value session.save_path "tcp://192.168.0.9:11211"

  • 或者php-fpm.conf对应的pool中添加

  • php_value[session.save_handler] = memcache

  • php_value[session.save_path] = " tcp://192.168.0.9:11211 "

实验前,先下载一个存session的脚本

# wget http://study.lishiming.net/.mem_se.txt

查看脚本内容

# cat .mem_se.txt 
<?php 
session_start(); 
if (!isset($_SESSION['TEST'])) { 
$_SESSION['TEST'] = time(); 
} 
$_SESSION['TEST3'] = time(); 
print $_SESSION['TEST']; 
print "<br><br>"; 
print $_SESSION['TEST3']; 
print "<br><br>"; 
print session_id(); 
?>

把脚本放到之前做虚拟主机代理的/data/wwwroot/default路径下,把txt文件改为php文件并放到目录下

# cd /data/wwwroot/default/
# ls
index.html
# mv /root/.mem_se.txt  1.php
# ls
1.php  index.html

扩展阅读:

CentOS7的/tmp目录自动清理规则https://blog.csdn.net/leonnew/article/details/79258453

memagent实现memcached集群 https://www.cnblogs.com/JohnABC/p/5752994.html

memcachedb让memcache的数据持久化 https://blog.csdn.net/longxingzhiwen/article/details/54311804

memcached和redis比较 https://www.jianshu.com/p/e94fa7340923

核心点:

数据类型

持久化

速度性能

memcached和redis使用场景比较: https://www.jianshu.com/p/0cee8085fc8f

memcached面试题集锦 https://blog.csdn.net/ywh147/article/details/47837955

memcached特性和限制 https://blog.csdn.net/ydwei918/article/details/46454627

redis面试题 https://zhuanlan.zhihu.com/p/32540678

https://www.jianshu.com/p/85d55f2ffd0a

猜你喜欢

转载自blog.csdn.net/zhengyshan/article/details/81842899