基于内存的类似redis的缓存方法

项目中需要用到redis,业务起来之后用到的地方更多,问题来了,因为操作redis太频繁,导致操作redis成为整个项目的瓶颈,经过调研和比较这时候基于内存的cache登场,简单来说就是纯内存层面的cache,可以实现
1、缓存数量的限制(不能无限制的堆内存,会撑爆)
2、能设置过期时间(内存中只缓存高频出现的数据)

放上业务流程的对比图,就是在redis之前加了一层,比较redis虽然基于内存但是连接包括操作还是得产生网络io操作

下面是我做的对比测试:

普通数据:

1、假设全部不命中(内存和redis都没有):
    [[email protected] test]# python 6.py
    这是100次的结果
    内存:[0.006078958511352539, 0.00607609748840332, 0.006433963775634766]
    redis:[0.00573420524597168, 0.007025003433227539, 0.005178928375244141]
    这是1000次的结果
 内存:[0.07438397407531738, 0.07421493530273438, 0.0615389347076416]
    redis:[0.04864096641540527, 0.04749107360839844, 0.05013895034790039]
    这是10000次的结果
    内存:[0.5369880199432373, 0.48474812507629395, 0.4684739112854004]
    redis:[0.4230480194091797, 0.5131900310516357, 0.43289995193481445]
    这是100000次的结果
    内存:[5.565299987792969, 5.5354228019714355, 5.658163070678711]
    redis:[4.795120000839233, 5.0205230712890625, 4.469913005828857]
2、假设全部命中:
    [[email protected] test]# python 6.py
    这是100次的结果
    内存:[0.00040602684020996094, 0.00021195411682128906, 0.00021600723266601562]
    redis:[0.005956888198852539, 0.005934000015258789, 0.005537986755371094]
    这是1000次的结果
    内存:[0.0021610260009765625, 0.0020508766174316406, 0.002026081085205078]
    redis:[0.0546720027923584, 0.04969382286071777, 0.04725193977355957]
    这是10000次的结果
    内存:[0.014709949493408203, 0.01748490333557129, 0.016735076904296875]
    redis:[0.500324010848999, 0.6110620498657227, 0.5946261882781982]
    这是100000次的结果
    内存:[0.20346498489379883, 0.20162200927734375, 0.15467381477355957]
    redis:[5.065227031707764, 5.543213844299316, 5.167007207870483]

json格式的数据:

1、假设全部不命中:
    [[email protected] test]# python json_test.py
    这是100次的结果
    内存  [0.00627589225769043, 0.006350040435791016, 0.006167888641357422]
    redis [0.00538182258605957, 0.005352973937988281, 0.005239009857177734]
    这是1000次的结果
    内存  [0.06096196174621582, 0.05894589424133301, 0.0531618595123291]
    redis [0.04534316062927246, 0.04644417762756348, 0.042047977447509766]
    这是10000次的结果
    内存  [0.526871919631958, 0.49242496490478516, 0.54292893409729]
    redis [0.46350693702697754, 0.5339851379394531, 0.514045000076294]
    这是100000次的结果
    内存 [5.3060479164123535, 5.807142972946167, 4.886216163635254]
    redis [4.287613153457642, 4.528016090393066, 5.158953905105591]
2、假设全部命中:
    [[email protected] test]# python json_test.py
    这是100次的结果
    内存  [0.0005319118499755859, 0.0003058910369873047, 0.0002970695495605469]
    redis [0.006021022796630859, 0.005857944488525391, 0.006082773208618164]
    这是1000次的结果
    内存  [0.0028162002563476562, 0.002669811248779297, 0.0026869773864746094]
    redis [0.07850098609924316, 0.06138491630554199, 0.05786609649658203]
    这是10000次的结果
    内存  [0.02676105499267578, 0.026623010635375977, 0.026623010635375977]
    redis [0.6534669399261475, 0.6395609378814697, 0.47389698028564453]
    这是100000次的结果
    内存 [0.20687103271484375, 0.20745611190795898, 0.19935917854309082]
    redis [5.537367105484009, 5.8351359367370605, 4.935602903366089]

可以看到,当全部不命中(实际情况只有在第一次才会出现,不然也不用加redis了)的情况下,基于内存和基于redis的性能基本相同,但如果命中过之后这个性能就有很大提升了

直接上代码:

#!/usr/bin/env python
# -*- coding:utf8 -*-
‘‘‘
Author : mafei
Date   : 2019-09-26
‘‘‘
import time
import weakref
import collections
import ujson as json

class Base(object):
    notFound = {}

    class Dict(dict):
        def __del__(self):
            pass

    def __init__(self, maxlen=10):
        self.weak = weakref.WeakValueDictionary()
        self.strong = collections.deque(maxlen=maxlen)

    @staticmethod
    def now_time():
        return int(time.time())

    def get(self, key):
        v = self.weak.get(key, self.notFound)

        if (v is not self.notFound):
            expire = v[r‘expire‘]
            if (self.now_time() > expire):
                self.weak.pop(key)
                return self.notFound
            else:
                return v
        else:
            return self.notFound

    def set(self, key, value):

        self.weak[key] = strongRef = Base.Dict(value)
        self.strong.append(strongRef)

class MemoryCache(object):
    def __init__(self, maxlen=1000 * 10000, life_cycle=5*60):
        self.memory_cache = Base(maxlen=maxlen)
        self.maxlen = maxlen
        self.life_cycle = life_cycle

    @staticmethod
    def _compute_key(key):
        return key

    def get(self, k):
        memory_key = self._compute_key(k)
        result = self.memory_cache.get(memory_key).get(‘result‘, None)
        if result is None:
            return result
        return result

    def set(self, k, v, life_cycle=None):
        self._set_memory(k, v, life_cycle)

    def get_json(self, key):
        res = self.get(key)
        try:
            return json.loads(res)
        except:
            return res

    def set_json(self, k, v, life_cycle=None):
        try:
            v = json.dumps(v)
        except:
            pass
        self.set(k, v, life_cycle)

    def set_with_lock(self, k, v, life_cycle=None):
        self._set_memory(k, v, life_cycle)

    def _set_memory(self, k, v, life_cycle=None):
        life_cycle = life_cycle or self.life_cycle
        memory_key = self._compute_key(k)
        self.memory_cache.set(memory_key, {‘ip‘: k, r‘result‘: v, r‘expire‘: life_cycle + self.memory_cache.now_time()})

调用时只需要传入2个参数:
maxlen : 内存中最多缓存多少条数据
life_cycle: 数据失效时间

优点:
1、高效,比直接调用redis要快很多
2、不会产生网络io和磁盘io

缺点:
1、支持的结构比较单一,当然这个可以自己扩充方式实现
2、如果要更新内存中的值不太方便,可以有其他方式实现

原文地址:https://blog.51cto.com/mapengfei/2443553

时间: 2024-11-05 12:28:03

基于内存的类似redis的缓存方法的相关文章

一种简单的php使用redis做缓存方法

这里介绍的缓存方法比较简单,下面是大概思路: 例子:一个列表缓存例子,由于列表数据实时性要求不高,可以缓存1分钟. 大概思路:根据请求的url来判断:1.请求的url hash 后在redis中有记录,则直接返回redis中的数据.2.请求的url hash 后在redis中无记录,则查询数据库(mysql),保存到redis中,并返回.url格式: 模块,控制器,操作(action),page redis缓存的数据格式:分为两种:一种是html标签,也就是框架渲染完成的html页面.另一种是j

全内存的redis用习惯了?那能突破内存限制类似redis的nosql产品ssdb呢?

首先说一下背景,在双十一的时候,我们系统接受X宝的订单推送,同事原先的实现方式是使用redis的List作为推送数据的承载,在非大促的场景下, 一切运行正常,内存占用大概3-4G,机器是16G内存.由于提前预计不足,在双十一来临的时候,订单瞬时量达到了平时的10X倍,内存非常吃紧,情况算 是非常紧急了,采取的临时解决方案就是再开一个redis,将程序中的redis地址指向这台新的,重启一下程序,把数据暂时引导过去. 一:分析 redis确实是一个好东西,一个如此强大的内存数据结构服务器,全内存存

初学redis分页缓存方法实现

1. 直接设置缓存,如果数据量大,操作增删改,更新缓存频率高和效率低. 2. 分页设置缓存,通过页码设置缓存. 1.新增-删除所有缓存(倒叙排序,第一页插入数据,后续页列表都改变), 2.修改-更新当前页缓存, 3.删除-更新当前页以及当前页以后的页面的缓存. <?php class ArticleClass { private $pageCount = 10;//每页显示 /** * 获取列表 * @param $page_no * @return array */ public functi

发布一个参考ssdb,用go实现的类似redis的高性能nosql:ledisdb

起因 ledisdb是一个参考ssdb,采用go实现,底层基于leveldb,类似redis的高性能nosql数据库,提供了kv,list,hash以及zset数据结构的支持. 我们现在的应用极大的依赖redis,但随着我们用户量越来越大,redis的内存越来越不够用,并且replication可能还会导致超时问题.虽然后续我们可以通过添加多台机器来解决,但是在现有机器配置下面,我们仍希望单台机器承载更多的用户.另外,因为业务的特性,我们其实并不需要将所有的数据放到内存,只需要存放当前活跃用户.

基于redis分布式缓存实现

第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来越多, 但memcache中没有, 影响开发效率 性能需求, 随着读操作的量的上升需要解决,经历的过程有: 数据库读写分离(M/S)–>数据库使用多个Slave–>增加Cache (memcache)–>转到Redis 解决写的问题: 水平拆分,对表的拆分,将有的用户放在这个表,有的用户放在

基于redis分布式缓存实现(新浪微博案例)

第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来越多, 但memcache中没有, 影响开发效率 性能需求, 随着读操作的量的上升需要解决,经历的过程有: 数据库读写分离(M/S)–>数据库使用多个Slave–>增加Cache (memcache)–>转到Redis 解决写的问题: 水平拆分,对表的拆分,将有的用户放在这个表,有的用户放在

转载自haier_jiang的专栏基于redis分布式缓存实现

简单说明下,写此文章算是对自己近一段工作的总结,希望能对你有点帮助,同时也是自己的一点小积累. 一.为什么选择redis 在项目中使用redis做为缓存,还没有使用memcache,考虑因素主要有两点: 1.redis丰富的数据结构,其hash,list,set以及功能丰富的String的支持,对于实际项目中的使用有很大的帮忙.(可参考官网redis.io) 2.redis单点的性能也非常高效(利用项目中的数据测试优于memcache). 基于以上考虑,因此选用了redis来做为缓存应用. 二.

基于内存,redis,mysql的高速游戏数据服务器设计架构

转载请注明出处,欢迎大家批评指正 1.数据服务器详细设计 数据服务器在设计上采用三个层次的数据同步,实现玩家数据的高速获取和修改. 数据层次上分为:内存数据,redis数据,mysql数据 设计目的:首先保证数据的可靠,防止数据丢失,保证数据完整.然后实现数据的高速访问,减少由玩家数量增加对数据服务器性能造成的影响.最后实现运维数据的入库,以及数据持久化. 在这个基础上数据服务器不再是一个单一服务器,它涉及到与其他服务器之间的交互. 数据服务器的核心在于redis数据层面.通过redis加快玩家

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

本文来自知乎官方技术团队的"知乎技术专栏",感谢原作者陈鹏的无私分享. 1.引言 知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动化运维服务体系,提供很多强大的功能.本文作者陈鹏是该系统的负责人,本次文章深入介绍了该系统的方方面面,值得互联网后端程序员仔细研究. (本文同步发布于:http://www.52im.net/thread-1968-1-1.html) 2.关于作者 陈鹏:现任知乎存储平台组 Redis 平