概述
在我们把系统做好反向代理和负载均衡之后, 还有一个性能问题没有解决,就是我们的数据库,此时如果并发量大了,数据库将是一个很大的瓶颈。假如我们有一台4核8G的服务器, 它能承受的并发数通常也就在2000左右。以电商系统为例, 如果所有的商品信息都是直接从数据库中读取, 首先挂掉的将会是我们的数据库。为了解决这个问题,在DB层和业务逻辑层之间, 会加入一层缓存, 利用缓存可以很好分担数据库的压力。
缓存的分类
- DNS
- 浏览器
- App
- 代理缓存
- 服务端缓存
服务端缓存中的内存缓存
- 我们主要针对服务端缓存中的内存缓存来分析
- 在RDB中,也就是我们所说的关系型数据库,如MySQL、SQLServer等,数据保存在服务器的硬盘之中, 硬盘对数据存取比较慢
- 普通笔记本转速是5.4K转/分钟, 一般服务器硬盘转速可以达到1.5W转/分钟, 这个速度和内存读取来说也是非常慢的
- 随机访问情况下, 内存访问速度比硬盘访问速度快上10万倍以上
- 然而内存对计算机来说是紧缺的资源, 我们无法将所有数据都放在内存中, 所以程序员开发了一些缓存算法来解决这些问题
缓存算法
-
LRU(Least Recently Used)
- 最近最少使用
Memcached
主要采用此算法来淘汰数据
-
LFU(Least Frequently Used)
- 根据数据的历史访问频率来淘汰数据
关于Memcached缓存
- Memcached 是高性能的分布式内存缓存系统,一般用来缓存访问的热点数据,以减轻数据库负担
- 全球最大的Memcached用户是facebook, 已经超过28T的数据存放在Memcached中, 使用了超过800台的服务器
- 官网:https://memcached.org/
Ubantu上Memcached的安装
- $
apt update
- $
apt install -y memcached
Memcached的服务管理
- $
service memcached stop
- $
service memcached start
- $
service memcached restart
Memcached的配置
- $
vi /etc/memcached.conf
-d
守护进程-m
内存, default 64MB , 这里需要区分情况, 如果是专用的Memcached服务器可以把70%的系统内存分配-u
运行用户-l
监听的服务器IP地址-p
监听端口, 默认是11211-c
并发连接数, 默认是1024
- 如果编辑了之后,需要重启服务才能生效, $
service memcached restart
- 连接Memcached终端, $
telnet 127.0.0.1 11211
进入# 可以查看状态 stats # ... 此处输出很多信息 STAT pid 237784 # 进程ID STAT uptime 2070631 # 运行秒数 STAT version 1.4.25 # 版本 STAT libevent 2.0.21-stable # libevent版本 STAT pointer_size 64 # 系统指针(32bit/64bit) STAT curr_items 50237 # 当前实例存储的items数量 STAT total_items 1337400 # 实例启动以后存储的items总数量 STAT bytes 35169108 # 实例存储items占用的字节数 STAT curr_connections 349 # 当前打开的连接数 【重要指标】 STAT total_connections 108429 # 实例启动后打开的连接总数 STAT cmd_get 14005676 # get 命令总请求次数 STAT cmd_set 1337400 # set 命令总请求次数 STAT get_hits 12596511 # 总命中次数 【重要指标】 STAT get_misses 1409165 # 总未命中次数 【重要指标】 STAT evictions 0 # 为获取空闲内存而删除的items数 STAT bytes_read 4918928094 # 总读取字节数(请求字节数) STAT bytes_written 46027378599 # 总发送字节数(结果字节数) STAT limit_maxbytes 1572864000 # 分配的缓存大小 STAT threads 4 # 当前线程数 # 退出 quit
- Memcached的使用比较简单,我们很少在服务器上对它进行管理
- Memcached是基于内存的, 如果服务关闭,则数据全部丢失
通过python来操作Memcached
1 ) 安装
$ pip3 install python-memcached
2 ) 使用
import memcache
# 链接
mc = memcache.Client(['127.0.0.1:11211'])
# 存入
mc.set('name', 'python', 60) # 过期时间 单位为秒
# 读取
res = mc.get('name')
# 删除
mc.delete('name')
Memcached的控制台演示
- 在windows上,如果我们想要启动Memcached, 需要下载一个它的可执行程序
memcached Server
文件, 启动它,开启命令窗口 - 打开另一个命令行使用pip安装它的python扩展, $
pip install python-memcached
, 这里是window一般使用pip命令即可 - 然后开始进入python环境进行相关操作
>>> import memcache >>> mc = memcache.Client(['127.0.0.1:11211']) >>> mc.set('name', 'jack') True >>> mc.get('name') 'jack' >>> mc.delete('name') 1 >>> mc.get('name') >>> >>> mc.set('name', 'jack', 10) True >>> mc.get('name') 'jack' >>> mc.get('name') # 10s之后再次get, 发现没了 >>>
Memcached的项目演示
1 ) 新建一个cache.py文件
- 注意名称不能和将要导入的memcache重名
2 ) 一般的数据库操作
import pymysql
def get_data():
conn = pymysql.connect(host='localhost', user='root', password='你自己设置的密码', database='test', charset='utf8)
cursor = conn.cursor
sql = 'select * from product limit 3'
cursor.execute(sql)
data = cursor.fetchall()
cursor.close()
conn.close()
return data
3 ) 改造后的带Memcached缓存的数据库操作
import pymysql
import memcache
def get_data():
# 链接memcache
mc = memcache.Client(['127.0.0.1:11211'])
# 这里定义一个公共变量, 防止后期修改一处, 忘记其他地方还有可能会造成的bug
cacheKey = 'product_list'
# 首先尝试获取,如果存在那么直接使用
res = mc.get(cacheKey')
if res is not None:
return res
# 不存在则进行连接数据库查询
print('go db now >>>>')
conn = pymysql.connect(host='localhost', user='root', password='你自己设置的密码', database='test', charset='utf8)
cursor = conn.cursor
sql = 'select * from product limit 3'
cursor.execute(sql)
data = cursor.fetchall()
cursor.close()
conn.close()
# 没有数据时将数据放入memcache, 这里设置10s的有效时间
# 这个时间设置很重要, 需要根据不同的业务设置不同的时间, 这样就可以灵活控制
# 假如1s有300个并发, 那么10s就是3000次的查询, 这里设置10s, 那么在这10s内只会查询1次的数据库, 相比之下减少了2999次节约了很多资源
# 一般业务我们可能会设置更长的时间, 如果数据更新了, 那么数据仍不会变化, 这会造成一个问题,
# 解决方案是:当数据更新时, 将缓存删除或者放入新的缓存数据
mc.set(cacheKey, data, 10)
return data