菜鸟看Redis(一)

一、 Redis简介

Redis是用C语言编写的开源软件,可以运行在Linux上,目前不支持Windows。Redis通常会被用于缓存、数据持久化、消息队列,Redis避免了服务器挂掉后,内存数据丢失的问题。Redis支持5种数据结构: strings, hashes, lists, sets, sorted sets,而且对于这些数据结构上的操作都是原子性的,这意味着操作这些集合是线程安全的;Redis首先是把数据集放在内存上的,可以设置每隔一段儿时间持久化数据到硬盘,如果工程中仅仅需要Redis做缓存,持久化也是可以被禁止的;Redis支持像Mysql一样的主从同步,主服务器上的数据可以同步到N个从服务器上,可以读写分离。

大多数编程语言都能使用Redis,C、C++、Java、C#、Python都能通过相应的API绑定Redis服务端的IP和端口使用Redis服务。在下面的章节中主要以Java为例介绍Redis数据结构上的简单操作。

二、Redis支持的数据结构以及简单操作

1. String

  在String类数据结构上,Redis和Memcached一致,都支持Key-Value的数据存储(一个Key对应一个Value,相当于Java中的HashMap),支持给一个Key设定一个value,支持在特定Key下的Value后添加字符串、删除特定Key等操作、对相应Key的数字value进行原子的加减操作。

public class RedisClient {
    private static final String HOST="192.168.146.129";
    private static final int PORT=6379;

    private  final Jedis jedis=new Jedis(HOST,PORT);

    /**
     * 测试 Redis做Key-Value存取
     */
    @Test
    public void testKeyValue(){
        jedis.set("name", "boruoyihao");
        System.out.println("Get name from redis:"+jedis.get("name"));
        System.out.println("Is exist in redis:"+jedis.exists("name"));
        jedis.append("name", ",Hello"); //相同Key下添加
        System.out.println("Get name from redis:"+jedis.get("name"));

        jedis.del("name");  //delete the Key
        System.out.println("Get name from redis:"+jedis.get("name"));

        //相当于jedis.set("name","boreyihao");
        //jedis.set("age",26);
        jedis.mset("name","boreyihao","age","26");
        System.out.println(jedis.get("name")+"=="+jedis.get("age")); 

        //设置name有效时间为2S
        jedis.setex("name", 2, "boruo");
        System.out.println("Get name from redis:"+jedis.get("name"));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //name时间超时,取出数据为null
        System.out.println("Get name from redis:"+jedis.get("name"));

        //原子递增操作
        jedis.set("age", "26");
        jedis.incr("age");
        System.out.println("Get age from redis:"+jedis.get("age"));
        jedis.decrBy("age", 3);
        System.out.println("Get age from redis:"+jedis.get("age"));
    }

}

2. hashes

Redis的Hash可以以一个键值存入一个Map对象,可以获取整个Map对象,也可以获取Map对象的key集合或者Value集合,也可以获取指定Field的Value,也可以对指定Field的整数值执行加减操作。Redis可以存对象的属性以及属性值,但是memcached存对象 只能转化为字符串,如果要修改对象的值,只能把字符串取出来转化为对象,然后修改对象,再转化为字符串存回memcached,开销还是很大的,这是Redis的优势所在。

    @Test
    public void testHash(){
        //test hashmap
        Map<String,String>m=new HashMap<String,String>();
        m.put("name", "Tom");
        m.put("major", "Software");
        m.put("age", "43");
        jedis.hmset("m", m);
        List<String> name=jedis.hmget("m", "name"); // m为key,name为m的key,返回的是List
        System.out.println(name);
        System.out.println("Get Hash Values="+jedis.hvals("m"));

        Iterator<String> it=jedis.hkeys("m").iterator();
        while(it.hasNext()){
            String key=it.next();
            System.out.println(key+":"+jedis.hmget("m", key));
        }
        System.out.println("Get keys from redis:"+jedis.hkeys("m"));
        System.out.println("Get Values from redis:"+jedis.hvals("m"));

        Map<String,String>map=jedis.hgetAll("m");
        System.out.println("Get map from Redis:"+map);

        //Test hashset
        System.out.println("---test hash set");
        jedis.hset("s", "name", "Jack");
        jedis.hset("s", "age", "25");
        System.out.println(jedis.hexists("s", "name"));
        System.out.println(jedis.hget("s", "name"));
        System.out.println(jedis.hgetAll("s"));
        Map<String,String>smap=jedis.hgetAll("s");
        System.out.println(smap);

        System.out.println(jedis.hdel("s", "name"));  //清除name属性
        System.out.println(jedis.hincrBy("s", "age", 3));
        System.out.println("after incr:"+jedis.hgetAll("s"));
    }

3. lists

List是一个双向链表,原因是Redis支持在这个链表的两端插入和弹出操作,所以Redis的List除了是双向链表外,也可以用于队列,也可以用于栈。

    @Test
    public void testList(){
        System.out.println("test List");
        jedis.del("task");
        jedis.rpush("task", "do homework");//在链表尾部添加
        jedis.rpush("task", "clean housr");
        jedis.lpush("task", "rest");//在链表头部添加
        jedis.lpush("task", "watch tv");
        System.out.println("length:"+jedis.llen("task"));
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1)); //-1表示到最后,表示取出从头到尾的数据
        System.out.println("target Index:"+jedis.lindex("task", 2));
        System.out.println(jedis.lpop("task"));//取出头部数据
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));
        System.out.println(jedis.rpop("task"));//取出尾部数据
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));

    }

4. sets

Redis的Set相当于Java的hashset,元素排列有序,更强的是它可以很方便的求两个集合的并、交、差集。

    @Test
    public void testSet(){
        System.out.println("test Set");
        jedis.del("s1");
        jedis.sadd("s1", "4","1","3","20");  //有序
        System.out.println("Get all s1:"+jedis.smembers("s1")); //有序的
        System.out.println("Get no s1:"+jedis.scard("s1"));

        jedis.sadd("s2", "4","11","13","34","3","20");
        System.out.println("Get all s2:"+jedis.smembers("s2")); //有序的
        System.out.println("Get no s2:"+jedis.scard("s2"));

        System.out.println(jedis.sinter("s1","s2"));//交集
        System.out.println(jedis.sunion("s1","s2")); //并集
        System.out.println(jedis.sdiff("s1","s2"));//差集
    }

5. sorted sets

Redis的Sorted Sets 是对Set补充,可以根据权值进行排序,同样不允许重复。

    @Test
    public void testSortedSet(){
        System.out.println("testSortedset");
        jedis.zadd("ss", 12, "Tom"); //中间为权值,根据权值排序
        jedis.zadd("ss", 1, "Jack");
        jedis.zadd("ss", 20, "David");
        jedis.zadd("ss", 3, "Jim");
        System.out.println("sortedset length:"+jedis.zcard("ss")); //获取元素个数
        System.out.println("sorted set:"+jedis.zrange("ss", 0, -1));  //输出按权值排列

        jedis.zadd("ss1", 1, "Tom"); //中间为权值
        jedis.zadd("ss1", 3, "Jimmy");
        jedis.zadd("ss1", 2, "Alex");
        jedis.zadd("ss1", 5, "Jim");

        System.out.println("sortedset length:"+jedis.zcard("ss1")); //获取元素个数
        System.out.println("sorted set:"+jedis.zrange("ss1", 0, -1));  //输出按权值排列

        System.out.println(jedis.zscore("ss1", "Tom")); //获取Tom的排序权值

    }

、Redis应用

结合以上对Redis数据结构的介绍,Redis在服务端开发技术上,简单来说是可以做缓存,并可以做数据持久化,以下几方面是菜鸟的理解。

1. 消息队列

在本文第二部分介绍了Redis有双向链表List,并且支持双进双出,所以可以用Redis做消息队列,比如通知的消息、任务、邮件等都可以存储在消息队列,然后另一端可以通过Redis能支持的大部分语言消费队列里的数据,这样便于系统模块之间的解耦,降低模块之间的依赖性;并且把同步消息处理方式转化为异步处理,不会造成队列阻塞。微博的用户微博列表应该是用Redis做的缓存。

2. 列出某项列表最新几条数据

这个同样可以用Redis中的List去处理,比如微博某大V的评论数上百万,在页面上显示肯定只能显示最新的几十条评论,如果存在数据库中,用Mysql的SELECT limit 查询数据,会对所有数据进行排序,这样的代价机会非常大,但是如果使用Redis的List就可以使用lrange(“key”,0,100)方法,这样可以取出最近100条评论。

3. 计数器

因为微博有最大的Redis集群,我们还是拿微博举例,某明星发了一个主题“我们”的微博,点赞数量两天内几百万,对于这种情况,就可以使用Redis中的原子加减操作,在java中,我们知道i++或者i--并不是原子性的,也就意味着它并不是线程安全的,但是使用Redis就不会有这个问题,可以使用jedis.hincrBy("weiboid", "likes", 1);这样表示某微博点赞数量加1,在这里是线程安全的。

4. 排行榜,取TOP N数据

结合本文第二部分介绍的Sorted Set,我们可以取出TOP N的数据,比如有100W用户参与比赛,或者100W用户微博,我们想取出比赛成绩最高的100个,或者最热的100条微博,在这里的比赛成绩或者微博热度都可以是权值(score),在缓存中操作,不需要进行排序,就能快速取出。

5. 排重与求并、差、交集

Redis使用Set,在第二部分Java程序中已经介绍,需要排重时,只需要往set集合中插入数据,Redis会自动做好去重操作,并且可以求任意两个缓存中的set集合的并、交、差集合。

6. Pub/Sub

Redis支持消息发布-订阅模式,非常适合聊天消息推送。

学习资料与参考文献:

http://try.redis.io/  有Redis初学者需要学习的基本命令,提供命令行界面。

http://redis.io/topics/introduction Redis基本介绍

http://www.csdn.net/article/2013-10-07/2817107-three-giant-share-redis-experience/1  Redis在国内外应用

http://www.cnblogs.com/whoamme/p/3532129.html Redis基本操作

http://www.360doc.com/content/15/0510/20/23016082_469494498.shtml Redis应用

时间: 2024-10-19 20:42:46

菜鸟看Redis(一)的相关文章

就publish/subscribe功能看redis集群模式下的队列技术(一)

Redis 简介 Redis 是完全开源免费的,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用. Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储. Redis支持数据的备份,即master-slave模式的数据备份. 性能极高 – Redis能读的速度是110000次/s

菜鸟看spring源码(0)之deubg环境搭建与BeanFactory的注册与依赖绑定

先贴几个基本类: 代码清单1#User类 package test; public class User{ private String name; User(){} User(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 代码清单2#UserDao.java package te

【菜鸟看框架】——MVC+EF实现分页

引言 分页这个名词对于现在的我们来说已经非常的熟悉,因为我知道了为什么我会在显示数 据的时候采用分页的形式,有人说为了显示的美观,有的人说为了在众多的数据中能容 易的找到我们想要的数据等等,这些都是其中的一些原因,但是这些东西我们完全可以 用VS自带的控件来实现,也就是所以的假分页,那么假分页和真分页的本质是什么呢? 假分页是一次性把所要的数据全部在数据库中查询出来,只是在显示的时候分页显示罢 了,这样显然是非常影响性能的,而真分页是每次取每页的数据条数,这样在大数据的 时候就能体现出了它的优势

【菜鸟看框架】——如何给EF实体添加注释

引言 在做图书馆项目的时候我们采用了EF实体架构自动生成实体,但是遇到一个很大的问 题就是在生成的实体中没有注释,我们都知道实体没有注释是非常痛苦的一件事情对于 开发的人来说,因为我们不能很快速的了解到底我们需要对那个属性进行操作,所以我 就在研究应该如何给生成的实体添加注释,下面给大家分享一下我的经验: 第一 手动添加(无效) 当开发人员告诉我让我给实体添加注释的时候,我就什么都没有多想,开始给我生成 的实体手动添加注释,当我们把我的15个实体的每一个字段都添加了以后,发现我的一 个数据库的字

菜鸟看设计模式系列笔记之开篇:设计模式的原则及概论

模式是在某一个背景下的某一个问题的解决方案. 设计模式在很大程度上是为了解决软件的可复用性,而根据大量工程实践总结出来的软件体系结构,隐含包括了软件工程的面向对象思想:封装.继承.多态. 为什么需要设计模式:设计模式(Design Pattern )是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结, 使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码的可靠性. 设计模式一般有如下几个基本要素:模式名称.问题.目的.解决方案.效果.实例代码和相关的设计模式,关键因素包

高性能网站架构利器--redis必杀技

目录 1.redis简介 2.redis主从复制实现 3.sentinel集群管理工具实现redis的高可用性 4.redis cluster 4.1.redis cluster环境搭建 4.2.redis cluster增加节点 4.3.redis cluster删除节点 4.4.redis cluster主从手动切换 5.总结 1.redis简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从201

(5)Redis几个认识误区

前几天微博发生了一起大的系统故障,很多技术的朋友都比较关心,其中的原因不会超出James Hamilton在On Designing and Deploying Internet-Scale Service(1)概括的那几个范围,James第一条经验“Design for failure”是所有互联网架构成功的一个关键.互联网系统的工程理论其实非常简单,James paper中内容几乎称不上理论,而是多条实践经验分享,每个公司对这些经验的理解及执行力决定了架构成败. 题外话说完,最近又研究了Re

Redis 中 5 种数据结构的使用场景介绍

这篇文章主要介绍了Redis中5种数据结构的使用场景介绍,本文对Redis中的5种数据类型String.Hash.List.Set.Sorted Set做了讲解,需要的朋友可以参考下 一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 redis 中一共有5种数据结构,那每种数据结构的使用场景都是什么呢? String——字符串 Hash——字典

基于 Redis 构建数据服务

今天我们来聊聊如何基于redis数据库扩展数据服务,如何实现分片(sharding)以及高可用(high availability). 分布式系统不存在完美的设计,处处都体现了trade off. 因此我们在开始正文前,需要确定后续的讨论原则,仍然以分布式系统设计中的CAP原则为例.由于主角是redis,那性能表现肯定是最高设计目标,之后讨论过程中的所有抉择,都会优先考虑CAP中的AP性质. 两个点按顺序来,先看分片. 何谓分片?简单来说,就是对单机redis做水平扩展. 当然,做游戏的同学可能