Redis应用场景

来源:互联网 发布:经合组织数据库 编辑:程序博客网 时间:2024/06/14 10:01

缓存

Redis的性能优于Memcached,且数据结构更多样化,支持多种过期淘汰策略;更重要的是支持持久化,持久化策略丰富。

计数,生成唯一ID

Redis的命令都是原子性的,可以轻松地利用INCR,DECR命令来构建计数器系统。同理,可以用INCR命令,为游戏玩家生成唯一的ID。

示例:

import java.util.Scanner;import redis.clients.jedis.Jedis;public class Incr {    // 访问一次web,计数一次    public static void accessWeb(Jedis jedis, String url) {        jedis.incr(url);    }    public static void main(String[] args) {        String host = "127.0.0.1";        int port = 10011;        Jedis jedis = new Jedis(host, port);        String url = "www.ucloud.cn";        //获取原始的值        long origin_cnt = Long.parseLong(jedis.get(url));        //接收终端输⼊入        Scanner sc = new Scanner(System.in);        while(true) {            System.out.println("访问 " + url +" ? [y/n]");            String ac = sc.nextLine();            if (ac.equals("y")) {            accessWeb(jedis,url);            }else {                break;            }        }        sc.close();        //获取现在的值        long now_cnt = Long.parseLong(jedis.get(url));        //计算访问www.ucloud.cn的次数。        System.out.println("你总共访问了 "+ url+ " " + Long.toString(now_cnt - o        rigin_cnt)+"次.");        jedis.close();    }}

输出

访问 www.ucloud.cn ? [y/n]y访问 www.ucloud.cn ? [y/n]y访问 www.ucloud.cn ? [y/n]y访问 www.ucloud.cn ? [y/n]y访问 www.ucloud.cn ? [y/n]n你总共访问了 www.ucloud.cn 4次.

排行榜应用,取TOP N操作

游戏服务器中涉及到很多排行信息,取TOP N操作,比如玩家等级排名、金钱排名、战斗力排名等,虽然通过关系数据库也可以实现,但是随着数据量增多,数据库的排序压力就会变大。

这些操作对于Redis来说都很简单,即使你有几百万个用户,每分钟都会有几百万个新的得分。

只需要jedis.zrevrank(key,member);

import java.util.ArrayList;import java.util.List;import java.util.Set;import java.util.concurrent.ThreadLocalRandom;import redis.clients.jedis.Jedis;import redis.clients.jedis.Tuple;public class HelloWorldApp {    static int TOTAL_SIZE = 10000;    //获取长度为8,由小写字母组成的随机名称    public static String randomName(int length) {        StringBuilder builder = new StringBuilder(length);        for (int i = 0; i < length; i++) {            builder.append((char) ThreadLocalRandom.current().nextInt(97,122));//a~z        }        return builder.toString();    }    public static void main(String[] args)    {        //连接信息,从控制台可以获得        String host = "127.0.0.1";        int port = 10011;        Jedis jedis = new Jedis(host, port);        //排行榜应用,取TOP N操作        try {            //Key(键)            String key = "游戏排行榜!";            //清除可能的已有数据            jedis.del(key);            //模拟生成若干个游戏选手            List<String> playerList = new ArrayList<String>();            for (int i = 0; i < TOTAL_SIZE; ++i)            {                //随机生成每个选手的名称                playerList.add(randomName(8));            }            System.out.println("输入全部" + TOTAL_SIZE +" 选手 ");            //记录每个选手的得分            for (int i = 0; i < playerList.size(); i++)            {                //随机生成数字,模拟选手的游戏得分                int score = (int)(Math.random()*5000);                String member = playerList.get(i);                if (i < 10) {                    System.out.println("选手名称:" + member + ", 选手得分: " + score                    );                }                //将选手的名称和得分,都加到对应key的SortedSet中去                jedis.zadd(key, score, member);            }            System.out.println("更多选手得分......");            //从对应key的SortedSet中获取已经排好序的选手列表            Set<Tuple> scoreList = jedis.zrevrangeWithScores(key, 0, -1);            //输出打印Top100选手排⾏行榜            System.out.println();            System.out.println(" "+key);            System.out.println(" Top 100 选手");            scoreList = jedis.zrevrangeWithScores(key, 0, 99);            for (Tuple item : scoreList) {                System.out.println("选手名称:"+item.getElement()+", 选手得分:"+Doubl                e.valueOf(item.getScore()).intValue());            }            //输出某个选手的排名            String player = playerList.get(0);            System.out.println();            System.out.println(" "+key);            System.out.println(" 选手"+player+"的排名: "+ jedis.zrevrank(key,player));        } catch (Exception e) {            e.printStackTrace();        }finally{            jedis.quit();            jedis.close();        }    }}

输出:

输入全部10000 选手选手名称:hegmsrcs, 选手得分: 1191选手名称:ocvhhxke, 选手得分: 653选手名称:ekgdllwj, 选手得分: 694选手名称:kxwsnnjj, 选手得分: 2051选手名称:vjflcktn, 选手得分: 2100选手名称:jtrlmnlk, 选手得分: 4257选手名称:aatbchgk, 选手得分: 2912选手名称:phukvvxy, 选手得分: 2044选手名称:aqqdqnel, 选手得分: 1859选手名称:hyndvsen, 选手得分: 2381更多选手得分......游戏排行榜!Top 100 选手选手名称:kqyhxehe, 选手得分:4999选手名称:datnveli, 选手得分:4998选手名称:ovxfislm, 选手得分:4997选手名称:llqnigun, 选手得分:4997选手名称:ckikmasa, 选手得分:4997选手名称:wlmdrpnx, 选手得分:4996选手名称:trslhgga, 选手得分:4996选手名称:bkbfnutg, 选手得分:4996选手名称:yqesafda, 选手得分:4995选手名称:grtjbjrq, 选手得分:4995更多选手排名......游戏排行榜!选手hegmsrcs的排名: 7618

构建队列系统

通过使用list的lpop及lpush命令进行队列的写入和消费,可以轻松实现消息队列;由于它是独立于游戏服务器的,所以多个游戏服务器可以通过它来交换数据、发送事件,通过使用sorted set,甚至可以构建有优先级的队列系统。

import redis.clients.jedis.Jedis;class ProducerThread extends Thread {    private Jedis jedis;    private int port;    private String host,key;    ProducerThread(String host, int port, String key) {        super(host);        this.key = key;        this.port = port;        jedis = new Jedis(host, port);    }    protected void finalize( ){        jedis.close();    }    public void run() {        //System.out.println("ProducerThread is running...");        for(int i = 0; i < 10; i++) {            jedis.lpush(key, "job"+ Integer.toString(i));            System.out.println("ProducerThread push job"+ Integer.toString(i));        }    }}class ConsumerThread extends Thread {    private Jedis jedis;    private int port;    private String host,key;    ConsumerThread(String host, int port, String key) {        super(host);        this.key = key;        this.port = port;        jedis = new Jedis(host, port);    }    protected void finalize( ) {        jedis.close();    }    public void run() {        //构建队列系统        //System.out.println("ConsumerThread is running...");        for(int i = 0; i < 10; i++) {            System.out.println("ConsumerThread pop "+ jedis.lpop(key));        }    }}public class QueueSystem {    public static void main(String[] args) {        String host = "127.0.0.1";        int port = 10011;        String key = "jobs";        ProducerThread pT = new ProducerThread(host,port,key);        ConsumerThread cT = new ConsumerThread(host,port,key);        pT.start();        cT.start();    }}

输出:

ConsumerThread pop nullProducerThread push job0ConsumerThread pop job0ProducerThread push job1ConsumerThread pop job1ProducerThread push job2ConsumerThread pop job2ProducerThread push job3ConsumerThread pop job3ProducerThread push job4ConsumerThread pop job4ProducerThread push job5ConsumerThread pop job5ProducerThread push job6ConsumerThread pop job6ProducerThread push job7ConsumerThread pop job7ProducerThread push job8ConsumerThread pop job8ProducerThread push job9

取最新N条评论

如果要取网站的最新评论

import java.util.List;import java.util.UUID;import redis.clients.jedis.Jedis;public class LastestN {    static int TOTAL_NUM = 5000;    static String host = "127.0.0.1";    static int port = 10011;    static String key = "comments";    static Jedis jedis;    public static void getLastestComments(int start, int num) {        System.out.println("最新20条评论:");        List<String> lastest_list = jedis.lrange(key, start, start + num - 1);        if (lastest_list.size() < num) {            //get remaining comments from db        }        for (int i = 0; i < lastest_list.size(); i ++) {            System.out.println("CommentID " + Integer.toString(i) + " "+lastest_            list.get(i));        }    }    public static void setComments() {        System.out.println(key);        for (int i = 0; i < TOTAL_NUM; i++) {            String commentID = UUID.randomUUID().toString();            jedis.lpush(key, commentID);            jedis.ltrim(key, 0, 99);//永远最多保存100条评论在redis中。            if (i < 10) {                System.out.println("CommentID: " + commentID);            }        }        System.out.println("更多CommentID......");        System.out.println("");    }    public static void main(String[] args) {        jedis = new Jedis(host, port);        //添加若干条评论;        setComments();        //取最新20条评论        getLastestComments(0,20);        jedis.close();    }}

输出:

commentsCommentID: b93db3f4-ff88-422a-ad49-bcbf7de5a396CommentID: 3bf56f8a-5d90-4fa1-a068-7dd7c3993917CommentID: 83a32ebd-89c4-40a5-bbd8-ace6bf723c57CommentID: 6003d965-f6cd-4e60-8b12-f9494fcb9bc0CommentID: a932c934-5dfd-4a5f-90da-5a40da468e78CommentID: 08ce995b-2ee1-4db9-8e3c-ca5069f87cceCommentID: ce5b57d5-fc02-4c91-90d5-bbe211073e0bCommentID: 5314a796-5574-4282-aab5-d8a8fc6e7adeCommentID: 3018252d-4f9b-40e7-bbbd-e0f3ab8b753dCommentID: 730bc8f5-d5fc-4d29-adf8-23c2fb632c0b更多CommentID......最新20条评论:CommentID 0 d194a83c-005a-411e-ba36-2b513c3565c1CommentID 1 c8104907-8912-463a-9d05-7fe0385d13d9CommentID 2 88b918ac-bf35-4687-a06c-af5e6159a376CommentID 3 324ff8c1-dfa5-46b3-9463-8a2d6aba3d26CommentID 4 6b3b76b0-3ce6-4dd4-9ed9-b40618330a44CommentID 5 7561efe9-96e0-46df-8f7c-e5f6812246c1CommentID 6 937122ca-a203-4ae9-89d6-454dbf616e1eCommentID 7 8e0f24fe-152a-4297-afbd-703c51fee50eCommentID 8 328f4858-6adc-41c7-88c1-a896c5b122a5CommentID 9 50151b7e-1225-4093-a30b-9d370b44ea25CommentID 10 dd1bd655-760e-41af-8929-9986dce9a41bCommentID 11 358fa7d3-4291-4c1b-8b2e-dbee55c60084CommentID 12 7367b111-9144-428b-af32-685004318c97CommentID 13 5e06f20a-a5b0-4e85-98c4-9be4ec613d70CommentID 14 924ac607-8af2-47b7-a08a-37ee851a1693CommentID 15 add23360-f2d9-4049-b935-97a8823176e4CommentID 16 15aca269-e4dd-4f2f-9eaa-cf8dc19cc8f3CommentID 17 45c6f96b-4a8a-4b57-a1f4-f10621911d67CommentID 18 c0a4fcd1-8df5-4f44-9a04-ba23ce8c8168CommentID 19 3e06fc46-766a-4e78-a67b-276840f72f62

存储社交关系

譬如将用戶的好友/粉丝/关注,可以存在一个set中,这样求两个人的共同好友的操作,只需要用sinter交集命令即可;也可以进行并集,差集操作。

import java.util.Set;import redis.clients.jedis.Jedis;public class CommonFriends {    public static void main(String[] args) {        String host = "127.0.0.1";        int port = 10011;        Jedis jedis = new Jedis(host, port);        //my friends        jedis.sadd("myfriends", "John");        jedis.sadd("myfriends", "Emliy");        jedis.sadd("myfriends", "Ben");        jedis.sadd("myfriends", "Steven");        System.out.println("my friends are: ");        Set<String> myList = jedis.smembers("myfriends");        for (String item:myList) {            System.out.print(item+" ");        }        //your friends        jedis.sadd("yourfriends", "Mark");        jedis.sadd("yourfriends", "Tim");        jedis.sadd("yourfriends", "Willim");        jedis.sadd("yourfriends", "Ben");        jedis.sadd("yourfriends", "Steven");        System.out.println("\n");        System.out.println("your friends are: ");        Set<String> yourList = jedis.smembers("yourfriends");        for (String item:yourList) {            System.out.print(item+" ");        }        //our common friends        System.out.println("\n");        System.out.println("our common friends are: ");        Set<String> commonList = jedis.sinter("myfriends","yourfriends");        for (String item:commonList) {            System.out.print(item+" ");        }        jedis.close();    }}

输出:

my friends are:Steven Emliy John Benyour friends are:Steven Mark Tim Ben Willimour common friends are:Steven Ben

构建实时消息系统

Redis的Pub/Sub系统可以构建实时的消息系统,比如很多开发人员用Pub/Sub构建实时聊天系统。

import redis.clients.jedis.*;import java.util.Date;import org.apache.commons.lang3.time.DateFormatUtils;import org.apache.commons.lang3.RandomStringUtils;class PrintListener extends JedisPubSub{    @Override    public void onMessage(String channel, String message) {        String time = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");        System.out.println("message receive:" + message + ",channel:" + channel +        "..." + time);        //此处我们可以取消订阅        if(message.equalsIgnoreCase("quit")){            this.unsubscribe(channel);        }    }}class PubClient {    private Jedis jedis;    public PubClient(String host,int port){        jedis = new Jedis(host,port);    }    public void pub(String channel,String message){        jedis.publish(channel, message);    }    public void close(String channel){        jedis.publish(channel, "quit");        jedis.del(channel);//实时消息系统    }}class SubClient {    private Jedis jedis;//    public SubClient(String host,int port){        jedis = new Jedis(host,port);    }    public void sub(JedisPubSub listener,String channel){        jedis.subscribe(listener, channel);        //此处将会阻塞,在client代码级别为JedisPubSub在处理消息时,将会“独占”链接        //并且采取了while循环的⽅方式,侦听订阅的消息    }}public class PubSubTest {    /**    * @param args    */    static String host = "127.0.0.1";    static int port = 10011;    public static void main(String[] args) throws Exception{    PubClient pubClient = new PubClient(host,port);    final String channel = "pubsub-channel";    pubClient.pub(channel, "before1");    pubClient.pub(channel, "before2");    Thread.sleep(2000);    //消息订阅者⾮非常特殊,需要独占链接,因此我们需要为它创建新的链接;    //此外,jedis客户端的实现也保证了“链接独占”的特性,sub⽅方法将⼀一直阻塞,    //直到调⽤用listener.unsubscribe⽅方法    Thread subThread = new Thread(new Runnable() {        @Override        public void run() {            try{                SubClient subClient = new SubClient(host,port);                System.out.println("----------subscribe operation begin-------");                JedisPubSub listener = new PrintListener();                //在API级别,此处为轮询操作,直到unsubscribe调⽤用,才会返回                subClient.sub(listener, channel);                System.out.println("----------subscribe operation end-------")                ;            }catch(Exception e){                e.printStackTrace();            }        }    });    subThread.start();    int i=0;    while(i < 10){        String message = RandomStringUtils.random(6, true, true);//apache-commons        pubClient.pub(channel, message);        i++;        Thread.sleep(1000);    }    //被动关闭指示,如果通道中,消息发布者确定通道需要关闭,那么就发送一个“quit”    //那么在listener.onMessage()中接收到“quit”时,其他订阅client将执行“unsubscribe”操作。    pubClient.close(channel);    //此外,你还可以这样取消订阅    //listener.unsubscribe(channel);    }}

输出:

----------subscribe operation begin-------message receive:erRIEe,channel:pubsub-channel...2016-03-15 15:53:52message receive:Ovcwiw,channel:pubsub-channel...2016-03-15 15:53:53message receive:STPWfV,channel:pubsub-channel...2016-03-15 15:53:54message receive:SR4iIk,channel:pubsub-channel...2016-03-15 15:53:55message receive:GI3Ege,channel:pubsub-channel...2016-03-15 15:53:56message receive:0V1JUt,channel:pubsub-channel...2016-03-15 15:53:57message receive:3iU8BV,channel:pubsub-channel...2016-03-15 15:53:58message receive:BqeI2x,channel:pubsub-channel...2016-03-15 15:53:59message receive:D53cHF,channel:pubsub-channel...2016-03-15 15:54:00message receive:quit,channel:pubsub-channel...2016-03-15 15:54:01----------subscribe operation end-------

事务处理

用户可以使用MULTI,EXEC,DISCARD,WATCH,UNWATCH指令用来执行原子性的事务操作。

import redis.clients.jedis.Jedis;import redis.clients.jedis.Transaction;import java.util.List;public class JTransaction {    public static void main(String[] args) {        String host = "127.0.0.1";        int port = 10011;        Jedis jedis1 = new Jedis(host, port);        Jedis jedis2 = new Jedis(host, port);        String key = "transaction-key";        jedis1.set(key, "20");        //jedis1 watch key        jedis1.watch(key);//如果在执⾏行事务之前,其他的客户端改变了key,则事务执⾏行失败。        Transaction tx = jedis1.multi();//开始事务        tx.get(key);        tx.get(key);        tx.get(key);        //jedis2.incr(key);//如果jedis2改变key,那么jedis1的事务就会失败        List<Object> result = tx.exec();//执⾏行事务        if(result == null || result.isEmpty()){            System.out.println("Transaction error...");            return;        }        for(Object rt : result){            System.out.println(rt.toString());        }    }}

输出:

202020

基数统计功能

Redis HyperLogLog 实现了基数统计功能,方便统计一组不同元素且数量很大的数据集,且只耗费很小的空间。如统计网站每天访问的独立IP数量;使用PFADD和PFCOUNT,可以轻松实现。

import redis.clients.jedis.Jedis;import java.util.Random;public class HyperLog {    public static void main(String[] args) {        String host = "127.0.0.1";        int port = 10011;        Jedis jedis = new Jedis(host, port);        String key = "src_ip";        jedis.del(key);        //随机生成10000个 ip,代表访问"www.ucloud.cn"的源ip.        for (int i = 0; i < 10000; i++) {            int section1 = new Random().nextInt(255);            int section2 = new Random().nextInt(253);            String ip = "10.10." + Integer.toString(section1) + "." + Integer.toSt            ring(section2);            //System.out.println(ip);            jedis.pfadd(key, ip);127.0.0.1        }    System.out.println("今天访问www.ucloud.cn的独立ip数为:"+jedis.pfcount(key));    jedis.close();    }}

输出:

今天访问www.ucloud.cn的独立ip数为:9218

参考
        https://docs.ucloud.cn/database/uredis/situation
http://www.runoob.com/redis/redis-pub-sub.html 
0 0