Redis

1.Redis简介

Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库

2.Redis的数据结构

  • string
set mykey somevalue

get mykey

set mykey somevalue nx

set mykey somevalue xx

set mykey hello ex 10 nx

set mykey hello xx 10 nx

del mykey

// 判断key的数据类型
type key

set counter 100

incr counter

incrby counter 10

decr counter

decrby counter 100

exists count  
  • Lists
rpush mylist A

rpush mylist B

lpush mylist first

rpush mylist A B C D

lrange mylist 0 -1

rpop mylist

lpop mylist

ltrim mylist 0 2

// 和rpop基本一样,但是如果tasks无数据,那么将会等待5s钟
brpop tasks 5
  • Hashes
hmset user:1000 username antirez birthyear 1977 verified 1

// 获取指定的key
hget user:1000 username

// 获取全部的key
hgetall user:1000

// 获取多个key
hmget user:1000 username birthyear

// 对birthyear进行加10操作
hincrby user:1000 birthyear 10
  • Sets
sadd myset 1 2 3

smembers myset

// 判断某个值是否在key里面
sismember myset 3

sadd news:1000:tags 1 2 5 77

smembers news:1000:tags
  • Sorted sets
zadd hackers 1940 "Alan Kay"

zrange hackers 0 -1

zrange hackers 0 -1 withscores

zrangebyscore hackers -inf 1950

zremrangebyscore hackers 1940 1960

zrank hackers "Anita Borg"

3.Redis的使用场景

1、缓存
缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。


redis缓存

2、排行榜
很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。

/**
* 测试商品排行榜
*/
public static void testTop(){
    String rankKey = "product_mobile_phone";

    Jedis jedis = new Jedis("localhost");
    jedis.zadd(rankKey, 100,"iphone_xs");
    jedis.zadd(rankKey, 110,"iphone_xs_max");
    jedis.zadd(rankKey, 90,"xiaomi_9");
    jedis.zadd(rankKey, 120,"huawei_p30");

    Set<String> products = jedis.zrevrange(rankKey, 0, -1);
    System.out.println(products);
}

3、计数器
什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。

4、分布式会话
集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。


分布式session

5、分布式锁
在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。

import java.util.Collections;
import redis.clients.jedis.Jedis;

/**
 * @Description
 * @Author luohong <luohong.lh@alibaba-inc.com>
 * @Date 06/08/19
 */
public class RedisClient {

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    final Jedis jedis = new Jedis("localhost");
                    String lockKey = "hello";
                    String requestId = "world";

                    try{
                        if (tryGetLock(jedis, lockKey, requestId, 10)) {
                            System.out.println("get lock success");
                        } else {
                            System.out.println("get lock failed");
                        }
                    }finally {
                        tryUnlock(jedis, lockKey, requestId);
                    }

                }
            }).start();
        }
    }

    /**
     * 尝试获取分布式锁
     * @param jedis
     * @param lockKey
     * @param requestId
     * @param expireTime
     */
    public static boolean tryGetLock(Jedis jedis, String lockKey, String requestId, int expireTime){
        String result = jedis.set(lockKey, requestId, "NX", "EX", 10);
        return "OK".equals(result);
    }

    /**
     * 释放锁
     * @param jedis
     * @param lockKey
     * @param requestId
     * @return
     */
    public static boolean tryUnlock(Jedis jedis, String lockKey, String requestId){
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        return "OK".equals(result);
    }
}

get lock failed
get lock failed
get lock failed
get lock failed
get lock failed
get lock failed
get lock failed
get lock success
get lock failed
get lock failed

6、 社交网络
点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。

7、最新列表
Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID去到对应的内容页即可。

8、消息系统
消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。

4.Redis高性能的原理

  • 绝大部分请求是纯粹的内存操作(非常快速)
  • 采用单线程,避免了不必要的上下文切换和竞争条件
  • 非阻塞IO - IO多路复用
  • 简单的数据结构,大部分的读/写操作的性能都是O(n)

由于进程的执行过程是线性的,当我们调用低速系统I/O(read,write,accept等等),进程可能阻塞,此时进程就阻塞在这个调用上,不能执行其他操作,阻塞很正常.

接下来考虑这么一个问题:一个服务器进程和一个客户端进程通信,服务器端read(sockfd1,bud,bufsize),此时客户端进程没有发送数据,那么read(阻塞调用)将阻塞,直到客户端调用write(sockfd,but,size)发来数据。在一个客户和服务器通信时这没什么问题;当多个客户与服务器通信时当多个客户与服务器通信时,若服务器阻塞于其中一个客户sockfd1,当另一个客户的数据到达套接字sockfd2时,服务器不能处理,仍然阻塞在read(sockfd1...)上;此时问题就出现了,不能及时处理另一个客户的服务,咋么办?

I/O多路复用来解决!I/O多路复用!继续上面的问题,有多个客户连接,sockfd1、sockfd2、sockfd3...sockfdn。同时监听这n个客户,当其中有一个发来消息时就从select的阻塞中返回,然后就调用read读取收到消息的sockfd,然后又循环回select阻塞;这样就不会因为阻塞在其中一个上而不能处理另一个客户的消息。“I/O多路复用”的英文是“I/O multiplexing”,可以百度一下multiplexing,就能得到这个图:


IO Multiplexing
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343