Linux笔记:高并发下的Web架构之Memcached缓存技术

概述

在我们把系统做好反向代理和负载均衡之后, 还有一个性能问题没有解决,就是我们的数据库,此时如果并发量大了,数据库将是一个很大的瓶颈。假如我们有一台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
发布了403 篇原创文章 · 获赞 198 · 访问量 69万+

猜你喜欢

转载自blog.csdn.net/Tyro_java/article/details/104138467