Redis入门

Nosql数据库应用场景

  • 少量数据存储,高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景。
  • 海量数据存储,分布式系统支持,数据一致性保证,方便的集群节点添加/删除。

mysql、redis、mogodb 的区别

mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据。
MongoDb相比于传统的SQL关系型数据库,最大的不同在于它们的模式设计(SchemaDesign)上的差别,正是由于这一层次的差别衍生出其它各方面的不同。
如果将关系数据库简单理解为由数据库、表(table)、记录(record)三个层次概念组成,而在构建一个关系型数据库的时候,工作重点和难点都在数据库表的划分与组织上。一般而言,为了平衡提高存取效率与减少数据冗余之间的矛盾,设计的数据库表都会尽量满足所谓的第三范式。相应的,可以认为MongoDb由数据库、集合(collection)、文档对象(Document-oriented、BSON)三个层次组成。MongoDb里的collection可以理解为关系型数据库里的表,虽然二者并不完全对等。当然,不要期望collection会满足所谓的第三范式,因为它们根本就不在同一个概念讨论范围之内。类似于表由多条记录组成,集合也包含多个文档对象,虽然说一般情况下,同一个集合内的文档对象具有相同的格式定义,但这并不是必须的,即MongoDb的数据模式是自由的(schema-free、模式自由、无模式),collection中可以包含具有不同schema的文档记录,支持嵌入子文档。
redis 官网测试读写能到10万/s左右。
应用场景
+ 业务系统的关联关系用mysql组织
+ 缓存数据用memcached、redis存取
+ 大文本数据放进mongodb存取中

Redis适用场景

Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能。通过tcp直接存取,优势是速度快,并发高,缺点是数据类型有限,查询功能不强,一般用作缓存

Redis特点

  • Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。
  • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。

Redis设计原理

在Redis中,并不是所有的数据都一直存储在内存中的。Redis只会缓存所有的key的信息,如果Redis发现内存的使用量超过了某一个阀值,将触发swap的操作。Redis根据“swappability = age*log(size_in_memory)”计算出哪些key对应的value需要swap到磁盘。然后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis可以 保持超过其机器本身内存大小的数据。当然,机器本身的内存必须要能够保持所有的key,毕竟这些数据是不会进行swap操作的。同时由于Redis将内存 中的数据swap到磁盘中的时候,提供服务的主线程和进行swap操作的子线程会共享这部分内存,所以如果更新需要swap的数据,Redis将阻塞这个 操作,直到子线程完成swap操作后才可以进行修改。当从Redis中读取数据的时候,如果读取的key对应的value不在内存中,那么Redis就需要从swap文件中加载相应数据,然后再返回给请求方。 这里就存在一个I/O线程池的问题。在默认的情况下,Redis会出现阻塞,即完成所有的swap文件加载后才会相应。这种策略在客户端的数量较小,进行 批量操作的时候比较合适。但是如果将Redis应用在一个大型的网站应用程序中,这显然是无法满足大并发的情况的。所以Redis运行我们设置I/O线程 池的大小,对需要从swap文件中加载相应数据的读取请求进行并发操作,减少阻塞的时间。
如果希望在海量数据的环境中使用好Redis,我相信理解Redis的内存设计和阻塞的情况是不可缺少的。

Redis目前提供四种数据类型:string,list,set及zset(sorted set)和hash。

  • string是最简单的类型,。
  • list是一个链表结构,主要功能是push、pop、获取一个范围的所有值等等。操作中key理解为链表的名字。
  • set是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作。操作中key理解为集合的名字。
  • zset是set的一个升级版本,他在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。可以理解了有两列的mysql表,一列存value,一列存顺序。操作中key理解为zset的名字。
  • hash数据类型允许用户用Redis存储对象类型,Hash数据类型的一个重要优点是,当你存储的数据对象只有很少几个key值时,数据存储的内存消耗会很小.更多关于Hash数据类型

Redis处理的个人经验

  • 批量处理:
    redis在处理数据时,最好是要进行批量处理,将一次处理1条数据改为多条,性能可以成倍提高。测试的目的就是要弄清楚批量和非批量处理之间的差别,从测试结果来看,性能差异非常大,所以在开发过程中尽量使用批量处理,即每次发送多条数据,以抵消网络速度影响。
  • 网络:
    redis在处理时受网络影响非常大,所以,部署最好能在本机部署,如果本机部署redis,能获取10到20倍的性能。集群情况下,网络硬件、网速要求一定要高。
  • 内存:
    由于我在测试环境遇到过redis读取超时,排查原因定位在Linux交互分区上。如果没有足够内存,linux可能将reids一部分数据放到交换分区,导致读取速度非常慢导致超时。所以一定要预留足够多的内存供redis使用。

Redis数据类型

    ```
    String key = "";
    ///字符串操作//  
    //查
    String value = jedis.get(key);
    //增
    jedis.set(key, value);
    //删
    jedis.del(key);
    //批量删
    String[] keys = new String[2];
    jedis.del(keys);
    //验证是否存在
    jedis.exists(key);

    ///list操作//
    //列表头部添加
    jedis.lpush("key", "A");
    jedis.lpush("key", "B");
    jedis.lpush("key", "C");
    //列表头部批量添加
    keys = new String[]{"A","B"};
    jedis.lpush("key", keys);
    //返回和移除列表第一个元素
    value = jedis.lpop("key");
    //列表尾部添加
    jedis.rpush("key", "A");
    jedis.rpush("key", "B");
    jedis.rpush("key", "C");
    //列表尾部批量添加
    keys = new String[]{"A","B"};
    jedis.rpush("key", keys);
    //返回和移除列表最后一个元素
    value = jedis.rpop("key");
    //返回列表长度
    jedis.llen("key");

    ///Hash操作//
    String field = "";
    //查
    String str = jedis.hget(key, field);
    //增
    jedis.hset(key, field, value);
    //删
    jedis.hdel(key, field);
    //判断是否存在
    jedis.hexists(key, field);
    //元素数量
    long len = jedis.hlen(key);
    //hash 所有key
    Set<String> set = jedis.hkeys(key);
    //hash 所有value
    List<String> list = jedis.hvals(key);
    //返回hash
    Map<String,String> map = jedis.hgetAll(key);
    ```

Redis 发布和订阅

发布订阅(pub/sub)是一种消息通信模式。订阅者可以通过subscribe和psubscribe命令向redis server订阅自己感兴趣的消息类型,redis将消息类型称为通道(channel)。当发布者通过publish命令向redis server发送特定类型的消息时。订阅该消息类型的全部client都会收到此消息。这里消息的传递是多对多的。一个client可以订阅多个 channel,也可以向多个channel发送消息。

//publisher
String channel = ""; //频道
String mess = "";//消息
jedis.publish(channel, mess);

//subscribe
SubscribeListener subscribeListener = new SubscribeListener();
//可以订阅多个频道,订阅得到信息在SubscribeListener的onMessage(...)方法中进行处理
subscribe(subscribeListener , channels)

public class SubscribeListener extends  JedisPubSub{
     @Override
     public void onMessage(String channel, String message) {
       //dosomething
     }
}

redis 事务、管道、分布式

事务

redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。

    Transaction tx = jedis.multi();
    for (int i = 0; i < 100000; i++) {
        tx.set("t" + i, "t" + i);
    }
    List<Object> results = tx.exec();

同步

     for (int i = 0; i < 100000; i++) {
        String result = jedis.set("n" + i, "n" + i);
    }

每次set之后都可以返回结果,标记是否成功。管道(Pipelining)

异步

有时,我们需要采用异步方式,一次发送多个指令,不同步等待其返回结果。这样可以取得非常好的执行效率。

    Pipeline pipeline = jedis.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("p" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();

分布式同步

    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    for (int i = 0; i < 100000; i++) {
        String result = sharding.set("sn" + i, "n" + i);

    }                                                                                                           

分布式异步

    List<JedisShardInfo> shards = Arrays.asList(
            new JedisShardInfo("localhost",6379),
            new JedisShardInfo("localhost",6380));

    ShardedJedis sharding = new ShardedJedis(shards);

    ShardedJedisPipeline pipeline = sharding.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sp" + i, "p" + i);
    }

    List<Object> results = pipeline.syncAndReturnAll();               
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值