NoSQL
NoSQL 是对Not Only SQL,非传统关系型数据库的统称
分类
Key-value Store k/v数据库:性能好 O(1) , 如: redis、memcached
Document Store 文档数据库:mongodb、CouchDB
Column Store 列存数据库,Column-Oriented DB:HBase、Cassandra,大数据领域应用广泛
Graph DB 图数据库:Neo4j
Time Series 时序数据库:InfluxDB、Prometheus
Memcached
Memcached是一个自由开源的,高性能的,分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。 Memcached基于一个存储键/值对的hashmap。其守护进程(daemon)是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
Memcached是基于内存的缓存系统,因此一旦服务器宕机或重启,缓存数据将丢失。不支持缓存持久化。
Memcached和Redis对比
比较项目 | Redis | Memcached |
---|---|---|
支持的数据结构 | 哈希、列表、集合、有序集合 | 纯key-value |
持久化支持 | 有 | 无 |
高可用支持 | redis支持集群功能,可以实现主动复制,读写分离。 官方也提供了sentinel集群管理工具,能够实现主从服务监控,故障自动转移,这一切,对于客户端都是透明的,无需程序改动,也无需人工个入 | 需要二次开发 |
存储value容量 | 最大512M | 最大1M |
内存分配 | 临时申请空间,可能导致碎片 | 预分配内存池的方式管理内存,省去分配内存时间 |
虚拟内存使用 | 有自己的VM机制,理论上能够储存比物理内存更多的数据,当数据超量时,会引发swap,把冷数据刷到磁盘上 | 所有数据存储在物理内存里 |
网络模型 | 非阻塞IO复用模型,提供一些非KV存储之外的排序,聚合功能,在执行这些功能时,复杂的CPU计算,会阻塞整个IO调度 | 非阻塞IO复用模型 |
水平拓展的支持 | redis cluster 可以横向拓展 | 暂无 |
多线程 | redis6.0 之前只支持单线程 | Memcached支持多线程,CPU利用方面Memcache优于redis |
过期策略 | 有专门线程,清除缓存数据 | 懒淘汰机制:每次往缓存放入数据的时候,都会存一个时间,在读取的时候要和设置的时间做TTL比较来判断是否过期 |
单机QPS | 约10W | 约60W |
源代码可读性 | 代码清爽简洁 | 不清爽 |
使用场景 | 负载数据结构,有持久化,高可用需求,value存储内容大 | 纯kv,数据量非常大,并发量非常大的业务 |
工作机制
内存分配机制
应用程序运行需要使用内存存储数据,但对于一个缓存系统来说,申请内存、释放内存将十分频繁,非常容易导致大量内存碎片,最后导致无连续可用内存可用,本该能存储的数据量却无法存储。
Memcached采用了Slab Allocator机制来分配、管理内存。
- Page:分配给Slab的内存空间,默认为1MB,分配后就得到一个Slab。Slab分配之后内存按照固定字节大小等分成chunk。
- Chunk:用于缓存记录k/v值的内存空间。Memcached会根据数据大小选择存到哪一个chunk中,假设chunk有128bytes、64bytes等多种,数据只有100bytes存储在128bytes中,存在少许浪费。
- Chunk最大就是Page的大小,即一个Page中就一个ChunkSlab Class:Slab按照Chunk的大小分组,就组成不同的Slab Class, 第一个Chunk大小为 96B的Slab为Class1,Chunk 120B为Class 2,如果有100bytes要存,那么Memcached会选择下图中Slab Class 2 存储,因为它是120bytes的Chunk。Slab之间的差异可以使用Growth Factor 控制,默认1.25
查看Slab Class
[root@wenzi memcached-1.6.20]#memcached -u memcached -d -f 2 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 192 perslab 5461
slab class 3: chunk size 384 perslab 2730
slab class 4: chunk size 768 perslab 1365
slab class 5: chunk size 1536 perslab 682
slab class 6: chunk size 3072 perslab 341
slab class 7: chunk size 6144 perslab 170
slab class 8: chunk size 12288 perslab 85
slab class 9: chunk size 24576 perslab 42
slab class 10: chunk size 49152 perslab 21
slab class 11: chunk size 98304 perslab 10
slab class 12: chunk size 196608 perslab 5
slab class 13: chunk size 524288 perslab 2
<22 server listening (auto-negotiate)
<23 server listening (auto-negotiate)
懒过期 Lazy Expiration
memcached不会监视数据是否过期,而是在取数据时才看是否过期,如果过期,把数据有效期限标识为0,并不清除该数据。以后可以覆盖该位置存储其它数据
LRU 最近最少使用
当内存不足时,memcached会使用LRU(Least Recently Used)机制来查找可用空间,分配给新记录使用
集群
Memcached集群,称为基于客户端 的分布式集群,即由客户端实现集群功能,即Memcached本身不支持集群。
Memcached集群内部并不互相通信,一切都需要客户端连接到Memcached服务器后自行组织这些节点,并决定数据存储的节点
安装
官方文档:http://memcached.org/downloads
[root@wenzi ~]#apt update && apt -y install gcc make libevent-dev
[root@wenzi ~]#tar -xf memcached-1.6.20.tar.gz
[root@wenzi ~]#cd memcached-1.6.20/
[root@wenzi memcached-1.6.20]#./configure --prefix=/apps/memcached
[root@wenzi memcached-1.6.20]#make && make install
[root@wenzi memcached-1.6.20]#tree /apps/memcached/
/apps/memcached/
├── bin
│ └── memcached
├── include
│ └── memcached
│ ├── protocol_binary.h
│ └── xxhash.h
└── share
└── man
└── man1
└── memcached.1
6 directories, 4 files
[root@wenzi memcached-1.6.20]#ln -s /apps/memcached/bin/memcached /usr/local/bin/
#不允许以root身份运行
[root@wenzi memcached-1.6.20]#memcached
can't run as root without the -u switch
#创建Memcached用户
[root@wenzi memcached-1.6.20]#useradd -r -s /sbin/nologin memcached
[root@wenzi memcached-1.6.20]#memcached -u memcached -d -f 2 -vv
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 192 perslab 5461
slab class 3: chunk size 384 perslab 2730
slab class 4: chunk size 768 perslab 1365
slab class 5: chunk size 1536 perslab 682
slab class 6: chunk size 3072 perslab 341
slab class 7: chunk size 6144 perslab 170
slab class 8: chunk size 12288 perslab 85
slab class 9: chunk size 24576 perslab 42
slab class 10: chunk size 49152 perslab 21
slab class 11: chunk size 98304 perslab 10
slab class 12: chunk size 196608 perslab 5
slab class 13: chunk size 524288 perslab 2
<22 server listening (auto-negotiate)
<23 server listening (auto-negotiate)
[root@wenzi memcached-1.6.20]#ss -tnlp | grep memcached
LISTEN 0 1024 0.0.0.0:11211 0.0.0.0:* users:(("memcached",pid=3929,fd=22))
LISTEN 0 1024 [::]:11211 [::]:* users:(("memcached",pid=3929,fd=23))
#准备service文件
[root@wenzi memcached-1.6.20]#vim /lib/systemd/system/memcached.service
[Unit]
Description=memcached daemon
After=network.target
[Service]
ExecStart=/usr/local/bin/memcached -u memcached -m 100 -c 10240
[Install]
WantedBy=multi-user.target
[root@wenzi memcached-1.6.20]#systemctl daemon-reload
启动说明
通过/etc/sysconfig/memcached修改memcached 运行参数
-u username memcached运行的用户身份,必须普通用户
-p 绑定的端口,默认11211
-m num 最大内存,单位MB,默认64MB
-c num 最大连接数,缺省1024
-d 守护进程方式运行
-f 增长因子Growth Factor,默认1.25
-v 详细信息,-vv能看到详细信息
-M 使用内存直到耗尽,不许LRU
-U 设置UDP监听端口,0表示禁用UDP
使用Memcached
与memcached通信的不同语言的连接器。libmemcached提供了C库和命令行工具
[root@wenzi ~]#apt -y install libmemcached-tools
#ping测Memcached是否正在运行
[root@wenzi ~]#/usr/bin/memcping --servers=192.168.28.60
#显示 Memcached 服务器的统计信息,如命中率、内存使用情况等
[root@wenzi ~]#memcstat --servers=192.168.28.60
Server: 192.168.28.60 (11211)
pid: 18797
uptime: 2018
time: 1709363976
version: 1.6.20
libevent: 2.1.12-stable
pointer_size: 64
rusage_user: 0.136119
rusage_system: 0.100906
max_connections: 10240
curr_connections: 2
total_connections: 4
rejected_connections: 0
connection_structures: 3
response_obj_oom: 0
response_obj_count: 1
response_obj_bytes: 32768
read_buf_count: 4
read_buf_bytes: 65536
read_buf_bytes_free: 16384
read_buf_oom: 0
reserved_fds: 20
cmd_get: 0
cmd_set: 0
cmd_flush: 0
cmd_touch: 0
cmd_meta: 0
get_hits: 0
get_misses: 0
get_expired: 0
get_flushed: 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
store_too_large: 0
store_no_memory: 0
auth_cmds: 0
auth_errors: 0
bytes_read: 32
bytes_written: 32
limit_maxbytes: 104857600
accepting_conns: 1
listen_disabled_num: 0
time_in_listen_disabled_us: 0
threads: 4
conn_yields: 0
hash_power_level: 16
hash_bytes: 524288
hash_is_expanding: 0
slab_reassign_rescues: 0
slab_reassign_chunk_rescues: 0
slab_reassign_evictions_nomem: 0
slab_reassign_inline_reclaim: 0
slab_reassign_busy_items: 0
slab_reassign_busy_deletes: 0
slab_reassign_running: 0
slabs_moved: 0
lru_crawler_running: 0
lru_crawler_starts: 8
lru_maintainer_juggles: 2066
malloc_fails: 0
log_worker_dropped: 0
log_worker_written: 0
log_watcher_skipped: 0
log_watcher_sent: 0
log_watchers: 0
unexpected_napi_ids: 0
round_robin_fallback: 0
bytes: 0
curr_items: 0
total_items: 0
slab_global_page_pool: 0
expired_unfetched: 0
evicted_unfetched: 0
evicted_active: 0
evictions: 0
reclaimed: 0
crawler_reclaimed: 0
crawler_items_checked: 0
lrutail_reflocked: 0
moves_to_cold: 0
moves_to_warm: 0
moves_within_lru: 0
direct_reclaims: 0
lru_bumps_dropped: 0
五种基本 memcached 命令执行最简单的操作:set、add、replace、get、delete
set、add、replace用于操作存储在 memcached 中的键值对的标准修改命令
command <key> <flags> <expiration time> <bytes>
<value>
参数说明:
command set/add/replace
key key 用于查找缓存值
flags 可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息
expiration time 在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes 在缓存中存储的字节数
value 存储的值(始终位于第二行)
#增加key,过期时间为秒,bytes为存储数据的字节数
add key flags exptime bytes
[root@wenzi ~]#telnet localhost 11211
stats
STAT pid 18797
STAT uptime 2792
STAT time 1709364750
STAT version 1.6.20
STAT libevent 2.1.12-stable
STAT pointer_size 64
STAT rusage_user 0.167935
STAT rusage_system 0.167935
STAT max_connections 10240
STAT curr_connections 2
STAT total_connections 6
STAT rejected_connections 0
STAT connection_structures 3
STAT response_obj_oom 0
STAT response_obj_count 1
STAT response_obj_bytes 65536
STAT read_buf_count 8
STAT read_buf_bytes 131072
STAT read_buf_bytes_free 49152
STAT read_buf_oom 0
STAT reserved_fds 20
STAT cmd_get 0
STAT cmd_set 0
STAT cmd_flush 0
STAT cmd_touch 0
STAT cmd_meta 0
STAT get_hits 0
STAT get_misses 0
STAT get_expired 0
STAT get_flushed 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 store_too_large 0
STAT store_no_memory 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 59
STAT bytes_written 2265
STAT limit_maxbytes 104857600
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT time_in_listen_disabled_us 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT slab_reassign_rescues 0
STAT slab_reassign_chunk_rescues 0
STAT slab_reassign_evictions_nomem 0
STAT slab_reassign_inline_reclaim 0
STAT slab_reassign_busy_items 0
STAT slab_reassign_busy_deletes 0
STAT slab_reassign_running 0
STAT slabs_moved 0
STAT lru_crawler_running 0
STAT lru_crawler_starts 10
STAT lru_maintainer_juggles 2840
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT log_watchers 0
STAT unexpected_napi_ids 0
STAT round_robin_fallback 0
STAT bytes 0
STAT curr_items 0
STAT total_items 0
STAT slab_global_page_pool 0
STAT expired_unfetched 0
STAT evicted_unfetched 0
STAT evicted_active 0
STAT evictions 0
STAT reclaimed 0
STAT crawler_reclaimed 0
STAT crawler_items_checked 0
STAT lrutail_reflocked 0
STAT moves_to_cold 0
STAT moves_to_warm 0
STAT moves_within_lru 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END
[root@wenzi ~]#telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
add mykey 1 60 4 #增加键名为mykey、描述为1、有效期60s、字节数4的值
test #mykey的值为test
STORED #已储存
get mykey #查询键名mykey的值
VALUE mykey 1 4
test
END
set mykey 1 60 2 #修改
cs
STORED
get mykey
VALUE mykey 1 2
cs
END
delete mykey #删除
DELETED
get mykey
END
flush_all #清空
OK
get mykey
END
quit
Connection closed by foreign host.
#非交互式取信息
[root@wenzi ~]#echo -e "stats\nquit" | nc 192.168.28.60 11211 | awk '/pid/{print $NF}'