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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Redis之所以能够实现速的性能,是因为它是一种基于内存的键值存储,它将数据存储在内存中,可以比磁盘I / O更地访问数据。它还支持复杂的数据结构,如列表,集合,有序集合,哈希表等,可以更地执行复杂的操作。 ### 回答2: Redis之所以那么,可以归结为以下几个原因: 1. 内存存储:Redis是基于内存存储的数据库,它的数据存储在内存中,通过避免了硬盘的读写操作,大大提高了读写速度。内存的随机访问速度比硬盘几个数量级。 2. 单线程模型:Redis采用单线程模型,避免了多线程带来的竞争和冲突,简化了问题复杂度,提高了数据处理的效率。虽然是单线程,但通过多路复用技术,可以处理多个连接的请求。 3. 高效的数据结构:Redis支持丰富的数据结构,如字符串、哈希表、列表、集合和有序集合。它们都是直接以二进制方式存储在内存中,没有复杂的键值映射和解析过程,提高了数据的访问效率。 4. 高效的网络通信:Redis使用自己的协议进行网络通信,这个协议是基于TCP的、基于文本的简单协议。相较于其他复杂的协议,这个协议的消息大小较小,传输效率较高。 5. 预分配内存和写时复制:Redis在启动时会提前分配好所需的内存空间,避免了运行过程中频繁的内存分配操作。此外,Redis还实现了写时复制技术,即在进行写操作时,会复制出一个新的副本,使得读操作和写操作可以同时进行,提高了并发性能。 总的来说,Redis之所以速,是通过内存存储、单线程模型、高效的数据结构、高效的网络通信、预分配内存和写时复制等技术手段的综合运用,使得其在各个方面都具备了卓越的性能表现。 ### 回答3: Redis之所以的原因有以下几点: 1. 内存存储:Redis将数据存储在内存中,内存的读写速度远远高于磁盘的读写速度,因此能够实现非常的数据访问。 2. 单线程处理:Redis采用单线程模型,避免了线程切换的开销和线程之间的同步问题。由于单线程不需要考虑并发操作的问题,使得Redis能够更加高效地利用CPU资源。 3. 非阻塞IO:Redis使用了异步的IO模型,在等待IO操作的同时,可以处理其他的请求。这样可以避免由于IO阻塞而导致的系统性能下降。 4. 数据结构简单高效:Redis支持多种数据结构,如字符串、列表、哈希表等,这些数据结构都经过了精心优化,使得其在存储和访问上更加高效。 5. 持久化支持:Redis提供了两种持久化的方式,分别为RDB(照)和AOF(追加日志),可以将数据持久化到磁盘,保证数据的安全性。 6. 网络模型:Redis使用一个单一的TCP连接来处理所有的请求和响应,减少了网络连接的开销,提高了网络性能。 综上所述,Redis之所以速是因为它通过内存存储、单线程处理、非阻塞IO、简单高效的数据结构、持久化支持以及优化的网络模型等多方面的优化措施,使得其能够高效地处理大量的读写请求,从而达到出色的性能表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值