精华内容
下载资源
问答
  • 解决Redis缓存和数据库值不一致问题

    千次阅读 2020-10-23 16:12:56
    为什么会发生数据库和缓存数据的不一致问题。 一致性是什么,一致性包含了以下两种: 缓存中有数据,那么数据库的数据必须要和缓存的数据要一致。 缓存中没有数据,在数据库值必须要是最新的数据。 不符合以上两...

    为什么会发生数据库和缓存数据的不一致问题。

    一致性是什么,一致性包含了以下两种:

    1. 缓存中有数据,那么数据库的数据必须要和缓存的数据要一致。
    2. 缓存中没有数据,在数据库值必须要是最新的数据。

    不符合以上两种情况的数据就是发生了数据不一致问题,对于读写缓存来说,就会发生这样的问题,此时我们要需要相应的策略去做做同步还是异步:

    1. 同步写回策略:就是写入缓存时,必须要写入数据库,保证数据一致性。
    2. 异步写回策略:想写入缓存,等到缓存失效或者淘汰的时候,再写入数据库,此时如果还没有写入数据库,缓存就挂了,这样数据就会丢失,数据库就没有最新的值了。

    对于读写缓存来说,要想数据一致性就要采用同步写回策略,如果数据不是必要的数据,可以采用数据的异步写回策略,比如电商商品的非重要参数。
    如果我们采用同步写回策略,就要保证写入缓存和数据的数据能到保证原子性,也就是说,缓存和数据的数据要同时增删改,一起更新或者都不更新。

    删除数据怎么保Redis和数据库的一致性问题

    数据删除时,先选择删除数据库还是先选择缓存。
    一,选择先删除数据库。

    1. 当我们删除数据的时候,先选择删除数据库,后选择删除缓存时,会在一定事件内发生数据不一致问题,比如线程A和B还有其他,A在删除数据数据的时候,B和其他线程来读取数据,这个时候,B和其他线程会读取到旧值,当A线程删除完成删除缓存后就可以消除读取旧值问题。这个会造成一小段时间内会读取到旧值。
    2. 当我们删除数据的时候,先选择删除数据库,在删除缓存时,删除缓存失败了,会造成旧数据一直会读取。比如线程A和B还有其他,A在删除数据库成功了,A和其他线程删除缓存失败。就会造成B和其他线程一直在读取旧值。解决方法选择删除数据库的时候,通过消息中间件MQ或者Kafka发送一条删除指令,在数据库删除完成之后启动一个线程去删除缓存,如果删除失败一直做删除操作,一直到删除成功。

    二,选择先删除缓存。

    1. 1.当我们删除数据的时候,先选择删除缓存,后选择删除数据库,会导致缓存出问题,比如线程A和B还有其他线程,A线程删除了缓存,还没有来及删除数据库(比如网络延迟),此时B和其他线程来读取消息,会发生缓存中没有数据,就会去数据库查询数据,数据库中的值还是以前的值,这样会造成缓存被重新更新为旧值,解决方法:可以使用缓存双删,可以把线程A休眠一段时间,这个时间是B线程读取数据被把数据写到缓存中的时间,这个时间还需要开发者在测试中找到比较准确的时间,来设置这个A线程的休眠时间。
    2. 当我们删除数据的时候,先选择删除缓存,后选择删除数据库时删除失败了,这样会造成缓存数据一直在数据库没有被删除,导致一直读取的时旧值,这样可以通过消息中间件去操作,直到数据库更新成功,在去删除缓存,这样的实现用到了缓存双删和消息中间件。

    三,自我认为还是选择先删除数据库在去删缓存。

    1. 1.首先如果删除缓存,缓存缺失,会给数据库带来一定的压力。
    2. 2.如果业务中读数据和写缓存的时间控制的不好设置,那么双删的等待时间就不好设置。

    四,如果业务中必须要准确的数据,保证数据一致性。

    1. 当删除数据库的值时,其他客户端短暂把并发请求暂存,等数据库删除和缓存更新之后再去发起请求,从而保证数据的一致性。这样下来并发就减小了。

    添加数据怎么保Redis和数据库的一致性问题

    一,选择先添加数据库。

    1. 当把数据先添加数据库时,添加缓存的操作出了问题,下一次查询数据导致缓存中没有数据,对数据库的压力较大。

    二,选择先添加缓存。

    1. 当把数据先添加缓存时,添加数据库的操作出了问题,我们可以采用Mq或Kafka消息中间件发送添加指令,知道数据添加到数据库,则结束操作。

    修改数据怎么保Redis和数据库的一致性问题
    一.选择先更新数据库,对于读写缓存的读写并发操作

    1. 当先更新数据到新数据库时,数据库更新完毕后,在更新缓存,当缓存更新失败,会导致访问命中的缓存一直都是旧值,直到这个缓存失效或者淘汰,才能得到新的数据。

    2. 比如A和B其他线程,A线程更新数据库,数据库更新数据完毕后,更新缓存,当缓存更新失败,B和其他线程就会一直读取旧值,直到此数据失效或者淘汰之后,才能读取到新的值。

    二.选择先更新缓存,对于读写缓存的读写并发操作

    1. 当先更新数据到缓存,数据更新完毕之后,在更新数据库,此时数据库跟新失败,会导致访问命中的缓存是最新值,当数据失效或者淘汰之后再去读取数据,还是读取的数据库的旧值,这样数据就会不一致。比如A和B其他线程,A线程先去更新缓存的值时,更新数据库的值失败之后,B和其他线程读取的时最新的数据,等到数据失效,B和其他线程读取的值就是旧值。

    解决以上者两种修改操作,我们可以利用消息中间件可以做到,当失败了一直等到数据一致,保证数据库能更新,和缓存数据能够写进去,和删除的效果是一致的。

    三.选择先更新数据库,对于读写缓存的写写并发操作

    1. 当先更新数据到数据库时,有两个线程A和B线程时,当A线程去修改数据库,B线程也去修改数据库,B线程去修改缓存,A线程在去修改缓存,会造成数据不一致问题。

    四.选择先更新缓存,对于读写缓存的写写并发操作

    1. 当先更新数据到缓存时,有两个线程A和B线程时,当A线程去修改缓存,B线程也去修改缓存,B线程去修改数据库,A线程在去修改数据库,会造成数据不一致问题。

    解决以上两种方案是,对于写请求,需要配合分布式锁使用。写请求进来时,针对同一个资源的修改操作,先加分布式锁,这样同一时间只允许一个线程去更新数据库和缓存,没有拿到锁的线程把操作放入到队列中,延时处理。用这种方式保证多个线程操作同一资源的顺序性,以此保证一致性。

    综上使用读写缓存读写并发的时候,可以使用消息中间件来维护数据不一致问题,在读写模式下对业务造成的影响不是很大。当使用读写缓存写写并发的时候,可以使用加分布式锁来维护数据不一致问题。

    另外,读写缓存模式由于会同时更新数据库和缓存,优点是,缓存中一直会有数据,如果更新操作后会立即再次访问,可以直接命中缓存,能够降低读请求对于数据库的压力(没有了只读缓存的删除缓存导致缓存缺失和再加载的过程)。缺点是,如果更新后的数据,之后很少再被访问到,会导致缓存中保留的不是最热的数据,缓存利用率不高(只读缓存中保留的都是热数据),所以读写缓存比较适合用于读写相当的业务场景。

     

     

    展开全文
  • 使用RedisJava进行数据库缓存

    千次阅读 2019-03-31 21:45:01
    数据库缓存是处理这些性能问题的最常见策略之一。...保持数据库和缓存同步并保持最新可能比您预期的更棘手。在下一节中,我们将讨论一些最常见的数据库缓存策略。 什么是不同的缓存策略? 手动缓存(也称为...

    使用Redis和Java进行数据库缓存

     

    数据库缓存是处理这些性能问题的最常见策略之一。缓存涉及将数据库查询的结果保存在更快,更容易访问的位置。正确完成后,缓存将减少查询响应时间,减少数据库负载并降低成本。

    但是,缓存也需要小心处理,因为它们实际上是在另一个位置创建另一个信息副本。保持数据库和缓存同步并保持最新可能比您预期的更棘手。在下一节中,我们将讨论一些最常见的数据库缓存策略。

    什么是不同的缓存策略?

    手动缓存(也称为缓存搁置策略)涉及直接管理数据库和缓存。您的应用程序在启动数据库查询之前检查缓存,并在对数据库进行任何更改后更新缓存。

    虽然如果正确实现有效,但手动缓存可能非常繁琐,尤其是在您需要查询多个数据库时。出于这些原因,开发人员发明了许多替代性的缓存策略。

    直读缓存策略

    在读取缓存中,应用程序首先查询缓存以查看其所需的信息是否在内部。如果没有,它将从数据库中检索信息并使用它来更新缓存。缓存提供程序或缓存库负责查询和更新缓存的详细逻辑。

    当应用程序重复请求相同的数据时,读取策略最适合读取繁重的工作负载:例如,一遍又一遍地加载相同文章的新闻网站。

    读取策略的一个缺点是对缓存的第一次查询将始终导致未命中,因为保证所请求的信息不在内部。为了解决这个问题,开发人员通常会使用用户可能要求的信息提前“加热”缓存。

    直写缓存策略

    在直写式高速缓存中,首先对高速缓存进行更新,然后对数据库进行更新。从应用程序到缓存以及从缓存到数据库都有一条直接线。与直读式缓存结合使用时,直写式策略可确保您的数据保持一致,从而无需手动缓存失效。

    后写缓存策略

    在后写式缓存(也称为回写式高速缓存)中,应用程序首先将数据写入高速缓存。经过一段设定的延迟后,缓存也会将此信息写入数据库。后写缓存最适合写入繁重的工作负载,即使出现一些故障和停机也可以很好地执行。

    基于Java的Redis缓存与Redisson

    Redis是NoSQL数据库最受欢迎的选项之一,它使用键值系统来存储数据。Redisson是Java编程语言中的Redis客户端库,可以使用所有熟悉的Java集合轻松访问Redis功能。

    Redisson允许您将数据放在外部存储中的地图中。您可以使用此功能实现数据库,Web服务或任何其他数据源的缓存。

    Redis中的直读缓存

    下面是一个Java示例,说明如何在Redis和Redisson中使用直读缓存。

    如果请求的条目在缓存中不存在,则它将由MapLoader对象加载:

    MapLoader<String, String> mapLoader = new MapLoader<String, String>() {
     @Override
     public Iterable<String> loadAllKeys() {
     List<String> list = new ArrayList<String>();
     Statement statement = conn.createStatement();
     try {
     ResultSet result = statement.executeQuery("SELECT id FROM student");
     while (result.next()) {
     list.add(result.getString(1));
     }
     } finally {
     statement.close();
     }
     return list;
     }
     @Override
     public String load(String key) {
     PreparedStatement preparedStatement = conn.prepareStatement("SELECT name FROM student where id = ?");
     try {
     preparedStatement.setString(1, key);
     ResultSet result = preparedStatement.executeQuery();
     if (result.next()) {
     return result.getString(1);
     }
     return null;
     } finally {
     preparedStatement.close();
     }
     }
    };

    配置使用案例:

    MapOptions<K, V> options = MapOptions.<K, V>defaults()
     .loader(mapLoader);
    RMap<K, V> map = redisson.getMap("test", options);
    // or
    RMapCache<K, V> map = redisson.getMapCache("test", options);
    // or with boost up to 45x times 
    RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
    // or with boost up to 45x times 
    RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

    Redis中的直写缓存

    下面是一个Java示例,说明如何在Redis中使用Redis中的Redis使用直写缓存。

    在MapWriter对象更新缓存和数据库之前,缓存更新方法不会返回:

    MapWriter<String, String> mapWriter = new MapWriter<String, String>() {
     @Override
     public void writeAll(Map<String, String> map) {
     PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");
     try {
     for (Entry<String, String> entry : map.entrySet()) {
     preparedStatement.setString(1, entry.getKey());
     preparedStatement.setString(2, entry.getValue());
     preparedStatement.addBatch();
     }
     preparedStatement.executeBatch();
     } finally {
     preparedStatement.close();
     }
     }
     @Override
     public void write(String key, String value) {
     PreparedStatement preparedStatement = conn.prepareStatement("INSERT INTO student (id, name) values (?, ?)");
     try {
     preparedStatement.setString(1, key);
     preparedStatement.setString(2, value);
     preparedStatement.executeUpdate();
     } finally {
     preparedStatement.close();
     }
     }
     @Override
     public void deleteAll(Collection<String> keys) {
     PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");
     try {
     for (String key : keys) {
     preparedStatement.setString(1, key);
     preparedStatement.addBatch();
     }
     preparedStatement.executeBatch();
     } finally {
     preparedStatement.close();
     }
     }
     @Override
     public void delete(String key) {
     PreparedStatement preparedStatement = conn.prepareStatement("DELETE FROM student where id = ?");
     try {
     preparedStatement.setString(1, key);
     preparedStatement.executeUpdate();
     } finally {
     preparedStatement.close();
     }
     }
    };

    使用配置案例:

    MapOptions<K, V> options = MapOptions.<K, V>defaults()
     .writer(mapWriter)
     .writeMode(WriteMode.WRITE_THROUGH);
    RMap<K, V> map = redisson.getMap("test", options);
    // or
    RMapCache<K, V> map = redisson.getMapCache("test", options);
    // or with boost up to 45x times 
    RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
    // or with boost up to 45x times 
    RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

    Redis中的后写缓存

    MapWriter接口还用于异步提交对Map对象(缓存)和外部存储(数据库)的更新。后台写入操作执行中使用的线程数量通过 writeBehindThreads设置设置。

    下面,我们看到Redisson中基于Redis的后写缓存实现的配置的Java示例:

    MapOptions<K, V> options = MapOptions.<K, V>defaults()
     .writer(mapWriter)
     .writeMode(WriteMode.WRITE_BEHIND)
     .writeBehindThreads(8);
    RMap<K, V> map = redisson.getMap("test", options);
    // or
    RMapCache<K, V> map = redisson.getMapCache("test", options);
    // or with boost up to 45x times 
    RLocalCachedMap<K, V> map = redisson.getLocalCachedMap("test", options);
    // or with boost up to 45x times 
    RLocalCachedMapCache<K, V> map = redisson.getLocalCachedMapCache("test", options);

    上述所有讨论的策略可用于Redisson的RMap,RMapCache,RLocalCachedMap和RLocalCachedMapCache对象。使用后两个对象可以使Redis中的读取操作速度提高45倍。

    获取以上Java高级架构最新视频,欢迎

    加入Java进阶架构交流群:142019080。直接点击链接加群。https://jq.qq.com/?_wv=1027&k=5lXBNZ7

    展开全文
  • redis缓存数据库

    万次阅读 2018-09-09 16:11:11
    一般大型网站,它的数据并不是存在数据库里的,而是存在...缓存数据库介绍 NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系数据库在应付web2....

    一般大型网站,它的数据并不是存在数据库里的,而是存在缓存里的,缓存是存在内存里的,这样它的访问速度就会特别快。存在数据库的,是存在硬盘上的,从硬盘上读数据肯定没有从内存读数据快。缓存应用一般是为了提高访问速度。

    缓存数据库介绍

    NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS(社交网络)类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展,NoSQL数据库的生产就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。

    NoSQL数据库的四大类型

    键值(Key-Value)存储数据库
    这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。[3] 举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.

    列存储数据库
    这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.

    文档型数据库
    文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。

    图形(Graph)数据库
    图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。[2] 如:Neo4J, InfoGrid, Infinite Graph.

    因此,我们总结NoSQL数据库在以下的这几种情况下比较适用:
    1、数据模型比较简单;
    2、需要灵活性更强的IT系统;
    3、对数据库性能要求较高;
    4、不需要高度的数据一致性;
    5、对于给定key,比较容易映射复杂值的环境。

    NoSQL数据库的四大分类表格分析

    分类 Examples举例 典型应用场景 数据模型 优点 缺点
    键值(key-value)[3] Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。[3] Key 指向 Value 的键值对,通常用hash table来实现[3] 查找速度快 数据无结构化,通常只被当作字符串或者二进制数据[3]
    列存储数据库[3] Cassandra, HBase, Riak 分布式的文件系统 以列簇式存储,将同一列数据存在一起 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限
    文档型数据库[3] CouchDB, MongoDb Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) Key-Value对应的键值对,Value为结构化数据 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 查询性能不高,而且缺乏统一的查询语法
    图形(Graph)数据库[3] Neo4J, InfoGrid, Infinite Graph 社交网络,推荐系统等。专注于构建关系图谱 图结构 利用图结构相关算法。比如最短路径寻址,N度关系查找等 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案

    redis

    介绍
    redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件(保证数据的持久化,memcached是只在内存里的,不能持久化),并且在此基础上实现了master-slave(主从)同步。

    redis的优点:

    • 异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。它是单线程或者单进程的,之所以快,是因为它底层是使用的IO多路复用epoll。
    • 支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。
    • 操作都是原子的 : 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。
    • MultiUtility工具:Redis是一个多功能实用工具,可以在很多如:缓存,消息传递队列中使用(Redis原生支持发布/订阅),在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据;

    安装Redis环境
    要在 Ubuntu 上安装 Redis,打开终端,然后输入以下命令:
    sudoaptgetupdatesudo apt-get install redis-server
    这将在您的计算机上安装Redis
    启动 Redis

    $redis-server
    查看 redis 是否还在运行

    $redis-cli
    这将打开一个 Redis 提示符,如下所示:
    redis 127.0.0.1:6379>
    在上面的提示信息中:127.0.0.1 是本机的IP地址,6379是 Redis 服务器运行的端口。现在输入 PING 命令,如下所示:
    redis 127.0.0.1:6379> ping
    PONG
    这说明现在你已经成功地在计算机上安装了 Redis。

    redis string操作:
    存数据
    set(name, value, ex=None, px=None, nx=False, xx=False)
    ex,过期时间(秒)
    px,过期时间(毫秒)
    nx,如果设置为True,则只有name不存在时,当前set操作才执行
    xx,如果设置为True,则只有name存在时,岗前set操作才执行

    • 比如我想存个名字叫huangyongpeng
      set name “huangyongpeng”
      存个年龄是22的
      set age 22
      其中name和age都是key

    • 如果我想取
      get name
      get age就行

    • 查看所有的key
      keys *

    • 如果想设置超时时间
      set sex ‘male’ ex 3
      这样性别这个记录3秒后就会消失

    • 批量设置
      mset oppo 3000 iphone 5000 mi 3350

    • 批量获取
      mget oppo iphone mi
    • 设置新值并获取原来的值
      getset oppo 4000
      它将oppo改为4000,但它给你返回的是原来的3000
    • 将字符串切片
      getrange name 0 2
      它给你返回hua
    • 切片修改
      setrange name 2 kkkkk
      它给你返回hukkkkk,它会覆盖后面的。
    • strlen(name)
      返回name对应值的字节长度(一个汉字3个字节)
    • incr(self, name, amount=1)
      自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
    • decr(self, name, amount=1)
      自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
    • append(key, value)
      在redis name对应的值后面追加内容
    • setbit(name, offset, value)
      对name对应值的二进制表示的位进行操作
      参数:
      name,redis的name
      offset,位的索引(将值变换成二进制后再进行索引)
      value,值只能是 1 或 0
      注:如果在Redis中有一个对应: n1 = “foo”,
      那么字符串foo的二进制表示为:01100110 01101111 01101111
      所以,如果执行 setbit(‘n1’, 7, 1),则就会将第7位设置为1,
      那么最终二进制则变成 01100111 01101111 01101111,即:”goo”
    • getbit(name, offset)
      获取name对应的值的二进制表示中的某位的值 (0或1)
    • bitcount(key, start=None, end=None)
      获取name对应的值的二进制表示中 1 的个数

    网站访问量,如何省空间
    假如有一个要求是一个千万级网站,需要实现看每天有多少个用户登录过以及哪些用户登录过:
    你可以设置一个二进制中为0值usercount,每来一个用户就将用户id的位数的0设为1
    假如id为400的用户登录,则
    setbit usercount 400 1就可以了
    你要查看一天有多少人登录直接
    bitcount usercount
    你要看id为400的用户今天登录没,则
    getbit usercount 400就行了

    redis hash操作
    hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据 , redis中Hash在内存中的存储格式如下图:
    这里写图片描述

    • 设置值hset(name, key, value)
      name,redis的name
      key,name对应的hash中的key
      value,name对应的hash中的value
      如:
      hset info name huang
      hset info age 22
      就是在name为info中设置了一个小字典。
    • 对应的也有批量设置hmset(name, mapping)
      如:
      hmset info sex male hobby reading

    • 取值hget(name,key)
      在name对应的hash中获取根据key获取value
      如:
      hget info name —–>huang

    • 取多个值hmget(name, keys, *args)
      如:
      hmget info name age sex —–>huang 22 male

    • 获取name对应hash的所有键值
      hgetall(name)

    • 获取name对应的hash中键值对的个数
      hlen(name)

    • 获取name对应的hash中所有的key的值
      hkeys(name)

    • 获取name对应的hash中所有的value的值
      hvals(name)

    • 检查name对应的hash是否存在当前传入的key
      hexists(name, key)
      如:
      hexists info name

    • 将name对应的hash中指定key的键值对删除
      hdel(name,*keys)

    • hscan(name, cursor=0, match=None, count=None)
      假如hash表如info 里面有上万个键值对,而我只需要其中的几条,这时候我们就可以通过hscan来进行简单的模糊匹配
      如:
      我想在info 中找到以a开头的键
      hscan info 0 match a*
      其中0是全局匹配
      如果我想匹配包含a的键
      hscan info 0 match *a*
      这样就匹配出name和age俩对键值对了

    redis list操作
    List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:
    这里写图片描述

    • lpush(name,values)
      在name对应的list中添加元素,每个新的元素都添加到列表的最左边
      如:
      lpush h_list huangyongpeng xiaoming zhangsan

    • rpush(name,values)
      在name对应的list中添加元素,每个新的元素都添加到列表的最右边

    • lrange(name, start, end)
      在name对应的列表分片获取数据
      如:
      lrange h_list 0 -1—–>zhangsan xiaoming huangyongpeng

    • llen(name)
      name对应的list元素的个数

    • linsert(name, where, refvalue, value))
      在name对应的列表的某一个值前或后插入一个新值
      如:
      linsert h_list before xiaoming lisi—–>zhangsan lisi xiaoming huangyongpeng

    • lset(name, index, value)
      对name对应的list中的某一个索引位置重新赋值
      如:
      lset h_list 1 Lisi——->zhangsan Lisi xiaoming huangyongpeng

    • lrem(name, value, num)
      在name对应的list中删除指定的值
      如:
      lrem h_list 1 Lisi
      其中1是删除几个

    • lpop(name)
      在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
      rpop 是从右边开始删除

    • lindex(name, index)
      在name对应的列表中根据索引获取列表元素
      如:
      lindex h_list 1——->huangyongpeng(列表中zhangsan huangyongpeng)

    • rpoplpush(src, dst)
      从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边
      src,要取数据的列表的name
      dst,要添加数据的列表的name

    redis set 集合操作
    Set操作,Set集合就是不允许重复的列表

    • sadd(name,values)
      name对应的集合中添加元素
      如:
      sadd s_set 1 2 3 2 5
      其中一个2会去除

    • smembers(name)
      获取name对应的集合的所有成员
      如:
      smembers s_set——->1 2 3 5

    • scard(name)
      获取name对应的集合中元素个数

    • sdiff(keys, *args)
      在第一个name对应的集合中且不在其他name对应的集合的元素集合
      如:
      sadd s_set2 2 4 5 6 7
      sdiff s_set s_set2—–>1 3

    • sdiffstore(dest, keys, *args)
      获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中
      如:
      sdiffstore s_set3 s_set s_set2
      smembers s_set3——–>1 3

    • sinter(keys, *args)
      获取多一个name对应集合的交集

    • sinterstore(dest, keys, *args)
      获取多一个name对应集合的交集,再讲其加入到dest对应的集合中

    • sismember(name, value)
      检查value是否是name对应的集合的成员

    • smove(src, dst, value)
      将某个成员从一个集合中移动到另外一个集合

    • spop(name)
      从集合的右侧(尾部)移除一个成员,并将其返回

    • srandmember(name, numbers)
      从name对应的集合中随机获取 numbers 个元素

    • srem(name, values)
      在name对应的集合中删除某些值

    • sunion(keys, *args)
      获取多一个name对应的集合的并集

    • sscan(name, cursor=0, match=None, count=None)
      类似上面的hscan

    有序集合
    在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

    • zadd(name, *args, **kwargs)
      在name对应的有序集合中添加元素
      如:
      zadd z_set 1 huang
      zadd z_set 10 yong
      zadd z_set 8 peng
      zadd z_set -1 hao

      zrange z_set 0 -1——>hao huang peng yong
      zrange z_set 0 -1 withscores—->hao -1 huang 1 peng 8 yong 10

    • zcard(name)
      获取name对应的有序集合元素的数量

    • zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
      按照索引范围获取name对应的有序集合的元素
      如:
      zrange z_set 0 -1——>hao huang peng yong

    • zrevrange(name, start, end, withscores=False, score_cast_func=float)
      从大到小

    • zrangebyscore(name, min, max)
      根据分数范围查找
      如:
      zrangebyscore z_set 1 8——>huang peng

    • zrank(name, value)
      获取某个值在 name对应的有序集合中的排行(从 0 开始)
      如:
      zrank z_set huang——->1

    • zrem(name, values)
      删除name对应的有序集合中值是values的成员

    • zscore(name, value)
      获取name对应有序集合中 value 对应的分数

    • zinterstore(dest, keys, aggregate=None)
      获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
      aggregate的值为: SUM MIN MAX

    其他常用的命令

    • delete(*names)
      根据删除redis中的任意数据类型
    • exists(name)
      检测redis的name是否存在
    • keys(pattern=’*’)
      根据模型获取redis的name
      如:
      查询以z开头的
      keys z*——->z_set

    • expire(name ,time)
      为某个redis的某个name设置超时时间

    • rename(src, dst)
      对redis的name重命名为
      如:
      将iphone改名为phone
      rename iphone phone

    • randomkey()
      随机获取一个redis的name(不删除)

    • type(name)
      获取name对应值的类型

    • scan(cursor=0, match=None, count=None)
      全局的模糊查询

    • move(name, db))
      将redis的某个值移动到指定的db下

    这儿得说下redis的使用,每个调用redis的都有自己独立的db,互不影响,比如qq 使用redis时创建了一个name的键,微信使用redis时也创建了一个那么的键,这俩个是互不影响的,它们都有自己独立的db(redis最多支持16个db)。

    切换db用select
    如:我想切换到第二个db下:
    select 1

    python连接redis

    import redis
    
    r = redis.Redis(host='127.0.0.1', port=6379)
    r.set('foo', 'Bar')
    print(r.get('foo'))
    print(r.keys())

    管道
    edis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。

    import redis
    
    pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
    
    r = redis.Redis(connection_pool=pool)
    
    # pipe = r.pipeline(transaction=False)
    pipe = r.pipeline(transaction=True)
    
    pipe.set('name', 'haha')
    pipe.set('role', 'gg')
    
    pipe.execute()
    
    展开全文
  • 数据库缓存

    千次阅读 2018-08-21 20:51:59
    数据库缓存 ...Memcahe/redis是高性能的分布式内存缓存服务器,通过缓存数据库查询结果,减少数据库访问次数,以提高动态web等应用速度,提高可扩展性。 简而言之:缓存数据库查询结果,加快访问...

    数据库缓存

    许多web停用都将数据保存到RDBMS(关系型数据库)中,应用服务器中读取数据并在浏览器中显示。但随着数据量增大、访问的集中,就会出现RDBMS的负担加重,数据库响应恶化,网站显示延迟等重大影响。

    Memcahe/redis是高性能的分布式内存缓存服务器,通过缓存数据库查询结果,减少数据库访问次数,以提高动态web等应用速度,提高可扩展性。

    简而言之:缓存数据库查询结果,加快访问速度,缓解数据库压力。

    Nosql

    非关系型数据库(not only sql)

    • 为弥补关系型数据库的不足
    • 以键值方式存储数据
    • 缓存数据库
    • 产品有redis、memcached、mongoDB

    Memcache

    特点

    • 内置内存存储方式(重启操作系统会导致全部数据消失)
    • 简单的key/value存储
    • 不互相通信的分布式

    缓存原理

    1. 检查用户请求的数据时缓存中是否存在,若存在直接返回,无需查询数据库。
    2. 若请求数据在缓存中查询不到,去查询数据库,返回数据,同时把数据存储到缓存中一份。
    3. 保持缓存的“新鲜性”,每当数据发生变化的时候,要同步更新缓存的信息,确保用户不会在缓存取到旧的数据。

    Redis

    redis是一个开源的,使用C语言编写的,支持网络交互的,可基于内存也可持久化的key-Value数据库。

    官网:redis.io

    特点

    1. 丰富的数据结构
    2. 支持持久化
    3. 支持事物(事物:一个完整的动作,要么全部执行,要么什么都没做。)
    4. 支持主从

    安装

    从reids.io下载最新版redis-X.Y.Z.tar.gz后解压。然后进入redis-X.Y.Z文件夹make即可。

    # wget http://download.redis.io/releases/redis-4.0.9.tar.gz
    # tar xzf redis-4.0.9.tar.gz -C /
    # cd redis-4.0.9
    # make

    ^若因缺包报错,在安装完缺失的包之后需重新解压新包进行make安装,若没有编译工具需要先安装yum -y install gcc make

    启动redis(默认非daemon形式启动)
    # ./src/redis-server
    指定配置文件启动
    # ./src/redis-server ../redis.conf

    设置开机启动

    1.# mkdir /etc/redis
    2.# cp   /redis-4.0.9/redis.conf  /etc/redis/6379.conf
    启动脚本
    # vim /etc/init.d/redis
    
    #!/bin/sh
    # chkconfig: 2345 10 90  
    # description: Start and Stop redis 
    REDISPORT=6379
    EXEC=/redis-4.0.9/src/redis-server
         #(可更改)
    CLIEXEC=/redis-4.0.9/src/redis-cli
            #(可更改)     
    PIDFILE=/var/run/redis_${REDISPORT}.pid
    CONF="/etc/redis/${REDISPORT}.conf"
    
    case "$1" in
        start)
            if [ -f $PIDFILE ]
            then
                    echo "$PIDFILE exists, process is already running or crashed"
            else
                    echo "Starting Redis server..."
                    $EXEC $CONF &   #(增加)
            fi
            ;;
        stop)
            if [ ! -f $PIDFILE ]
            then
                    echo "$PIDFILE does not exist, process is not running"
            else
                    PID=$(cat $PIDFILE)
                    echo "Stopping ..."
                    $CLIEXEC -p $REDISPORT shutdown
                    while [ -x /proc/${PID} ]
                    do
                        echo "Waiting for Redis to shutdown ..."
                        sleep 1
                    done
                    echo "Redis stopped"
            fi
            ;;
        restart)
            "$0" stop
            sleep 3
            "$0" start
            ;;
        *)
            echo "Please use start or stop as first argument"
            ;;syst
    esac
    授权
    # chmod 777 /etc/init.d/redis
    加入开机启动
    # chkconfig --add redis
    # chkconfig redis on
    # systemctl daemon-reload   //重新加载自启动系统
    启动方式
    # /etc/init.d/redis start   6
    # systemctl start redis
    端口

    默认服务端口为6379

    测试
    # ./src/redis-cli 
    
    127.0.0.1:6379> set name hello
    OK
    127.0.0.1:6379> get name
    "hello"
    127.0.0.1:6379> save   //保存数据到磁盘
    
    127.0.0.1:6379> shutdown  //通过客户端来关闭redis服务端  禁用

    数据结构

    redis 是一种高级的key:value存储系统,它的value支持五种数据类型:

    • 字符串(strings)
    • 字符串列表(lists)
    • 字符串集合(sets)
    • 有序字符串集合(sorted sets)
    • 哈希(hashes)

    注意:

    1. key不可太长,尽量不要超过1024字节,这样不仅会小孩内存,而且会降低查找效率。
    2. key也不要太短,太短的话,key的可读性会降低。
    3. 在项目中,建议key使用统一的命名格式。

    redis持久化

    开启持久化功能后,重启redis,数据会自动通过持久化文件恢复。

    RDB(默认开启)

    在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上。RDB方式,是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

    redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束,才会用这个临时文件替换上次持久换文件。这种特性可让我们随时备份文件,因为快照文件总是完整可用的。

    特点
    • 周期性

    • 不影响数据写入

      RDB会启动子进程,备份所有数据。当前进程继续提供数据读写,当备份完成替换老的备份文件。

    • 高效,一次性还原所有数据

    • 完美性较差

      故障点到上一次备份之间的数据无法恢复。

    查看RDB开启状态
    vim /redis-4.0.9/redis.conf 
    
    dbfilename dump.rdb
    #dbfilename:持久化数据存储在本地的文件
    
    dir ./
    #dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/src下启动的redis-cli,则数据会存储在当前src目录下
    
    save 900 1
    save 300 10
    save 60 10000
    ##snapshot触发的时机,save <seconds> <changes>  
    ##如下为900秒后,至少有一个变更操作,才会snapshot  
    ##对于此值的设置,需要谨慎,评估系统的变更操作密集程度  
    ##可以通过“save “””来关闭snapshot功能  
    #save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
    
    stop-writes-on-bgsave-error yes 
    ##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等  
    
    rdbcompression yes  
    ##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间  
    AOF

    AOF,英文是Append Only File ,即只允许追加不允许改写的文件。

    AOF,将redis执行过得所有写指令(每秒钟),记录在日志里,再次redis重新启动时只要把这些写指令从前到后再重复执行一遍,就可实现数据恢复。

    特点
    • 实时性

    • 完整性较好

    • 体积大

      记录/删除数据的指令,都会被记录。恢复速度慢于RDB。

    开启AOF
    vim /redis-4.0.9/redis.conf
    
    appendonly yes  
    ##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能  
    ##只有在“yes”下,aof重写/文件同步等特性才会生效  
    
    appendfilename appendonly.aof  
    ##指定aof文件名称 
    
    appendfsync everysec  
    ##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec  
    
    no-appendfsync-on-rewrite no  
    ##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”  
    
    auto-aof-rewrite-min-size 64mb 
    ##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”  
    
    auto-aof-rewrite-percentage 100  
    ##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。  
    ##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后  
    ##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。
    默认的AOF持久化策略

    每秒钟fsync(把缓存中的写指令记录到磁盘中)一次,在这种情况下,redis,仍可以保持良好的处理性能,即使redis故障也只会丢失最近一秒的数据。

    AOF日志修复

    若在追加日志时,恰好遇到磁盘空间满,inode满或断电等情况导致日志写入不完整,redis并不会贸然加载这个有问题的AOF文件,而是报错退出。

    可使用redis的提供的redis-check-aof工具,可以用来进行日志修复。

    1.备份被写坏的AOF文件
    2.运行redis-check-aof –fix进行修复
    3.用diff -u来看下两个文件的差异,确认问题点
    4.重启redis,加载修复后的AOF文件
    AOF重写

    AOF使用追加模式,若不做任何处理,AOF文件会越来越大,因此,redis提供了重写机制(rewrite)机制。

    文件重写机制(rewrite):当AOF文件大小超过所设定的阈值时,redis会启动AOF的内容压缩,只保留可以恢复数据的最小指令集。

    原理:

    • 重写即将开始之际,redis会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
    • 与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
    • 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。
    • 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中了。
    通过AOF恢复数据

    若意外执行了FLUSHALL,导致redis内存中数据被清空。只要redis配置了AOF持久化方式,且AOF文件还没被重写,可以执行以下操作恢复。

    • 暂停redis
    • 编辑AOF文件将最后一行的FLUSHALL删除
    • 重启redis
    持久化选择RDB和AOF的选择方式
    • 官方建议两个同时使用这样可以提供更可靠的持久化方案。

      这种情况下redis重启的话,会优先采用AOF方式来进行数据恢复(AOF恢复数据完整度更高。)

    • AOF写入数据快,RDB写入速度慢

    • 如果没有数据持久化需求,可以关闭RDB和AOF方式,这样的话redis将变成一个纯内存数据库,就像memcache一样。

    redis主从、哨兵

    ^注: 摘自https://blog.csdn.net/u012152619/article/details/52854465

    主从同步

    redis同mysql一样支持主从同步(同时也支持一主多从以及多级从结构)

    redis的主从同步是异步进行的,这种模式的优点是主从同步不会影响主逻辑,也不会降低redis的处理性能。

    使用主从结构的原因
    • 纯碎的冗余备份
    • 提升读性能,比如很小号性能的SORT就可以有从服务器来承担。
    优化
    • 可以考虑关闭主服务器的数据持久化功能,只让从服务器持久化,这样可以提高主服务器的处理性能。
    • 将从服务器设置为只读模式,这样可以避免从服务器数据被误修改,但从服务器仍然可以接受CONRG指令,因此不应将从服务器直接暴露到不安全的网络环境中。(如必须如此,那可以考虑给重要指令进行重命名。)
    原理

    redis主从同步

    1. 如果设置了一个Slave,无论是第一次连接还是重连到Master,它都会发出一个SYNC命令;

    2. 当Master收到SYNC命令之后,会做两件事:

      a) Master执行BGSAVE,即在后台保存数据到磁盘(rdb快照文件);
      
      b) Master同时将新收到的写入和修改数据集的命令存入缓冲区(非查询类);
      
    3. 当Master在后台把数据保存到快照文件完成之后,Master会把这个快照文件传送给Slave,而Slave则把内存清空后,加载该文件到内存中;

    4. 而Master也会把此前收集到缓冲区中的命令,通过Reids命令协议形式转发给Slave,Slave执行这些命令,实现和Master的同步;

    5. Master/Slave此后会不断通过异步方式进行命令的同步,达到最终数据的同步一致;

    6. 需要注意的是Master和Slave之间一旦发生重连都会引发全量同步操作。但在2.8之后版本,也可能是部分同步操作。

    部分复制

    2.8开始,当Master和Slave之间的连接断开之后,他们之间可以采用持续复制处理方式代替采用全量同步。

    Master端为复制流维护一个内存缓冲区(in-memory backlog),记录最近发送的复制流命令;同时,Master和Slave之间都维护一个复制偏移量(replication offset)和当前Master服务器ID(Masterrun id)。当网络断开,Slave尝试重连时:

    a. 如果MasterID相同(即仍是断网前的Master服务器),并且从断开时到当前时刻的历史命令依然在Master的内存缓冲区中存在,则Master会将缺失的这段时间的所有命令发送给Slave执行,然后复制工作就可以继续执行了;

    b. 否则,依然需要全量复制操作;

    sentinel

    sentinel(哨兵)

    Sentinel(哨兵)是用于监控redis集群中Master状态的工具,其已经被集成在redis2.4+的版本中

    setinel作用
    1. Master状态检测
    2. 如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave
    3. Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换
    sentinel工作方式
    1. 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令
    2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
    3. 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 an>
    4. 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线
    5. 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令
    6. 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
    7. 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
    主观下线和客观下线
    • 主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。

    • 客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover.

    举个栗子
    环境
    三台服务器保持通讯畅通,并部署redis。
    master  slave1 slave2
    配置主从
    • master
    # vim /etc/redis/6379.conf 
    
    master:
    bind 0.0.0.0            //监控本地所有网卡IP
    protected-mode no
    • slave1/2
    # vim /etc/redis/6379.conf 
    
    bind 0.0.0.0
    slaveof master_ip master_port   //修改master_ip和port
    protected-mode no  
    测试
    # /redis-4.0.9/src/redis-cli 
    127.0.0.1:6379> info replication
    master结果
    127.0.0.1:6379> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=192.168.0.113,port=6379,state=online,offset=2212,lag=1
    slave1:ip=192.168.0.112,port=6379,state=online,offset=2212,lag=0
    
    slave结果
    127.0.0.1:6379> info replication
    # Replication
    role:slave
    master_host:192.168.0.109
    master_port:6379
    master_link_status:up
    配置sentienl
    1. 每台机器上修改redis主配置文件设置:bind 0.0.0.0

    2. 每台机器上修改sentinel配置文件:添加如下配置

      
      # vim /redis-4.0.9/sentinel.conf
      
      sentinel monitor mymaster MASTERIP 6379 2
      //当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。
      sentinel down-after-milliseconds mymaster 3000  //单位毫秒
      sentinel failover-timeout mymaster 10000
      protected-mode no
    3. 每台机器启动服务

         # ./src/redis-sentinel sentinel.conf
    4. 关闭主服务器,观察从服务器状态

       # /redis-4.0.9/src/redis-cli 
       #info replication
    展开全文
  • 如何保证缓存数据库的双写一致性?

    万次阅读 多人点赞 2019-02-03 10:45:04
    一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求写请求串行化,串到一个内存队列里...
  • 相关文章:Centos7.0 安装Redis 3.2.1详细过程和使用常见问题Redis简介Redis 是一个开源的内存中的数据结构存储系统,它可以用作数据库缓存和消息中间件。 它支持多种类型的数据结构,如字符串(Strings),散列...
  • 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求写请求串行化,串到一个内存队列里去。...
  • 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求“缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求写请求串行化,串到一个内存队列里...
  • 数据库和缓存面试题

    千次阅读 2020-02-11 21:26:53
    数据库和缓存面试题 1.列举常见的关系型数据库和非关系型都有那些? 关系型数据库: Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL 非关系型数据库: NoSql、Cloudant、MongoDb、redis、HBase 两种...
  • Redis面试 - 如何保证缓存与数据库的双写一致性? 面试题 ...一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求“缓存+数据库” 必须保持一致性...
  • 一般来说,如果你的系统不是严格要求缓存+数据库必须一致性的话,允许缓存可以稍微的跟数据库偶尔有不一致的情况。最好不要做这个方案。读请求写请求串行化,串到一个内存队列里。这样就可以保证一定不会出现不...
  • 传统企业中为了解决高并发大流量的问题,通常使用缓存+数据库的方式来支撑高QPS的...关于缓存数据库数据一致性的解决方案,网上有很多,但是大都是偏向理论的,且大多数使用分布式锁来实现的,分布式锁也是一种解...
  • 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求“缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求写请求串行化,串到一个内存队列里去。...
  • 数据库缓存

    千次阅读 2011-01-28 13:13:00
    数据库缓存允许你把数据库查询结果保存在文本文件中以减少数据库访问。 重要提示: 本类在激活后会随数据库驱动自动初始化。切勿手动加载。 <br />另: 并非所有查询结果都能被缓存。请仔细阅读...
  • 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求写请求串行化,串到一个内存队列里去。...
  • 先写数据库还是先写缓存

    千次阅读 2020-02-05 08:49:23
    核心思想是数据库和缓存之间追求最终一致性,不追求强一致性。 (1) 在缓存作为提升系统性能手段的背景下,不需要保证数据库和缓存的强一致性。如果非要保证二者的强一致性,会增大系统的复杂度,完全没有必要 (2) ...
  • 一般来说生产环境中,我们为了保证数据响应的速度,会将数据保存在数据库中,但是会将部分数据...如何保证数据库和缓存数据的一致。 简单的处理 目前关于简单保证缓存一致性的方案主要有下面几个 先写缓存再写DB\先...
  • Django构建数据库缓存

    千次阅读 2019-02-20 13:02:47
    由于Django构建得是动态网站,每次客户端请求都要严重依赖数据库,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用缓存缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问...
  • 一级缓存:session级别的,默认开启,不可卸除,一般都会用到 二级缓存:sessionfactory(创建session,hibernate的初始化)级别的,适合1、很少别...注意:不允许出现并发问题的数据不可以放在二级缓存中(财务问题)
  •  在前面一个 ADO.NET 数据库文章中 我说过 ADO.NET 允许用户在断网的情况下 对数据库进行 "操作" ,注意这里的操作 我带了 引号 !!!  其实在ADO.NET 中 我们可以先从数据库将 一个数据库的子集下载 到本地...
  • SQL数据库缓存依赖

    千次阅读 2011-10-11 00:17:10
    SQL缓存依赖,可以将数据库中的数据放入Cache缓存缓存,既当数据库中有相应的更新,程序也会及时监听到,并获取更新最新的缓存版本。 优点:能直接从缓存中取数据,加快了程序的执行效率。缺点:不能进行...
  • Redis及其他缓存数据库的区别

    千次阅读 2018-05-27 11:16:57
    文章转自:「每天一个知识点」Redis及其他缓存数据库的区别前面文章讲过Redis为什么这么快,为什么是单线程的。这篇文章整理一下Redis及其他缓存数数据库的区别。Redis的优点性能极高。因为数据存在内存中,类似于...
  • 系统缓存全解析6:数据库缓存依赖

    千次阅读 2009-07-08 09:56:00
    更多的时候,我们的服务器性能损耗还是在查询数据库的时候,所以对数据库缓存还是显得特别重要,上面几种方式都可以实现部分数据缓存功能。但问题是我们的数据有时候是在变化的,这样用户可能在缓存期间查询的数据...
  • php 数据库缓存实现思路

    千次阅读 2012-09-23 22:22:33
    缓存查询结果能极大地改进脚本执行时间资源需求。 缓存SQL查询结果也允许你通过后期处理数据。如果你用文件缓存去存储全部脚本的输出结果(HTML输出),这样可能是行不通的。 当你执行一个SQL查询时,点典的处理...
  • 数据库缓存依赖详解

    千次阅读 2012-06-20 10:03:01
    本节从缓存命名空间的总体简介组成结构入手,从整体上对System.Web.Caching进行概述。 16.1.1 System.Web.Caching概述 System.Web.Caching 是用来管理缓存的命名空间。缓存就是将服务器端的数据暂时保存在...
  • 数据库常用的连接池和缓存分析

    千次阅读 2018-04-26 11:08:36
    数据库连接池是什么?...jdbc是一种连接数据库的方式,我们每一次和数据库交互的时候都要连接一次。如果自己做一些练习或者项目非常的小话,可以用jdbc连接。如果正常的项目或者大型的互联网的项目用...
  • 用Redis缓存来提升数据库查询性能

    千次阅读 2015-05-26 14:06:36
    如果对数据模型优化对查询调优不起作用,DBA就可以使用缓存系统,比如Redis,它是一个可以提供内存永久数据存储的键值数据存储系统。 由于Redis能够将数据快速读写至数据存储系统,比起关系型数据库它更具...
  • 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 缓存 + 数据库 必须保持一致性的话,最好不要做这个方案。即:读请求写请求串行化,串到一个内存队列里去。 ...
  • 清空数据库:flushdb // 清除当前数据库的所有keysflushall // 清除所有数据库的所有keysRedis常用命令集,清空redis缓存数据库1)连接操作命令quit:关闭连接(connection)auth:简单密码认证help cmd: 查看cmd...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 269,039
精华内容 107,615
关键字:

允许使用网站缓存和数据库