reids面试题

news2024/11/29 3:46:05

image.png

1 redis是单线程吗?

image.png

Redis是单线程
主要是指Redis的网络10和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取(socket 读)、解析、执行、内容返回(socket 写) 等都由一个顺序串行的主线程处理,
但Redis的其他功能,比如持久化RDB、AOF、异步删除、集群数据同步等等,其实是由额外的线程执行的。Redis命令工作线程是单线程的,但是,整个Redis来说,是多线程的;

2 IO多路复用听说过吗?

什么叫IO?
input/output,针对文件的输入和输出。
Linux下的文件类型:
b(block块设备)
c(character字符设备)
d(directory目录)
-(普通文件)
l(line链接文件)
s(socket套接字文件)
p(pipe管道文件)
image.png

image.png

BIO:BIO(blocking I/O):同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销
BIO方式使用于连接数目比较小且固定的架构,这种服务方式对服务器资源要求比价高,并且局限于应用中,
image.png

package com.redis.redis01;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @version 1.0
 * @Author zhaozhiqiang
 * @Date 2023/11/10 9:08
 * @Param
 * @Description //TODO Socket(BIO,同步阻塞):BIO全称是Blocking IO,同步阻塞式IO,是JDK1.4之前的传统IO模型。
 */
public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            Socket socket = serverSocket.accept(); // 阻塞等待客户端连接
            new Thread(() -> {
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String message = reader.readLine(); // 阻塞等待客户端数据
                    System.out.println("Received: " + message);
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start(); // 为每个客户端连接创建一个新线程处理,可能导致线程资源耗尽。
        }
    }

}

NIO:NIO全称 java non-blocking IO。从JDK 1.4开始,java提供了一些列改进的输入/输出(I/O)的新特性,被称为NIO,是同步非阻塞的
NIO三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)
image.png

package com.redis.redis01;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @version 1.0
 * @Author zhaozhiqiang
 * @Date 2023/11/10 9:15
 * @Param
 * @Description //TODO NIO(同步非阻塞): Non-blocking,不单纯是 New,是解决高并发、I/O高性能的有效方式。
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        //使SocketChannel工作在非阻塞模式
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(new InetSocketAddress(8080));

        Selector selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select(); // 阻塞等待就绪Channel
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();

                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int bytesRead = client.read(buffer);
                    if (bytesRead > 0) {
                        buffer.flip();
                        System.out.println("Received: " + new String(buffer.array(), 0, bytesRead));
                        client.close();
                    }
                }
            }
        }
    }

}

3 redis为啥那么快?

3.1 基于内存操作
所有Redis的数据都存在内存中,因此所有的运算都是内存级别的,所以他的性能高
3.2 数据结构简单
Redis的数据结构是专门设计的,这些简单的数据结构的查找和操作时间大部分复杂度都是O(1),性能高
3.3 多路复用和非阻塞IO
Redis使用I/O多路复用功能来监听多个socket连接客户端,这样可以使用一个线程来处理多个请求,减少线程切换带来额开销,同时也避免了I/O阻塞操作
3.4 避免上下文切换
因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生

4 redis读写能力咋样?

官网介绍
大数据量高性能(Redis一秒可以写8万次,读11万次,NoSQL的缓存记录级,是一种细粒度的缓存,性能会比较高)

WINDOWNS局域网本地测试

image.png

已用内存80%情况测试

package com.redis.redis01;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.util.UUID;

@SpringBootTest
public class TestWR {
    //注入模板 序列化
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    volatile boolean stop = false;

    /**
     * redis写测试能力;简单字符平均大概在7000左右
     * @throws InterruptedException
     */
    @Test
    void testWrite() throws InterruptedException {
        Runnable runnable = new Runnable() {
            public void run() {
                int i=0;
                while (!stop) {
                    //1 key和value都是UUID.randomUUID()+System.currentTimeMillis():每10秒683283个  每秒6833
                    //2 key和value都是UUID.randomUUID():每10秒67559个  每秒6755
                    //3 key和value都是从数字0开始递增:每10秒72562个  每秒72562
                    redisTemplate.opsForValue().set("" + i , "" + i);
                    i++;
                }
            }
        };
        new Thread(runnable).start();
        Thread.sleep(10000);
        new Thread(() -> {
            stop = true;//调用shtdown方法stop为true
        }).start();
    }

    /**
     * redis读测试能力;简单字符平均大概在8000左右,比写快点
     * @throws InterruptedException
     */
    @Test
    void testRead() throws InterruptedException {
        Runnable runnable = new Runnable() {
            public void run() {
                int i=0;
                while (!stop) {
                   
                    redisTemplate.opsForValue().get("" + i );
                    i++;
                }
                System.out.println("读取到:"+i);//读取到:81374 大概每秒8134
            }
        };
        new Thread(runnable).start();
        Thread.sleep(10000);
        new Thread(() -> {
            stop = true;//调用shtdown方法stop为true
        }).start();
    }
}

结论:读能力大概81374/s,写能力大概72562/s,当前是redis3.2本地测试,是局域网,网络i/o影响不大,主要是内存当前没测试之前我的内存已经80%了;

内存剩余50%情况下测试

写7475/s,读8828/s

linux局域网测试

单机版本16G

内存已占用60

image.png

写1025/s,读1080/s

内存已经占用16

image.png

写1230/s,读1214

集群版本(一台16台机器装3主3从,和上面单机共用)

写1222/s,1312/s

redis7配置多线程后测试

image.png

写1270/s,读1029

Jedis驱动测试

  /**
     * redis每秒读操作:
     *      1 windows本地测试       13085/s
     *      2 连接linux测试          1438/s
     *
     */
    @Test
    public void redisTester2() throws InterruptedException {
        // 1 connection 连接,通过指定ip和端口号
        Jedis jedis = new Jedis("172.16.204.51", 6379);
        // 2 指定访问服务器密码
        jedis.auth("123456");
        Runnable runnable = new Runnable() {
            public void run() {
                int i = 0;
                try {
                    while (!stop) {
                        i++;
                        jedis.set("test" + i, i + "");
                    }
                    // 打印1秒内对Redis的操作次数
                    System.out.println("redis每秒操作:" + i + "次");
                } finally {// 关闭连接
                    jedis.close();
                }
            }
        };
        new Thread(runnable).start();
        Thread.sleep(1000);
        new Thread(() -> {
            stop = true;//调用shtdown方法stop为true
        }).start();

    }

1 jedis比lettuce快2倍左右,达到13085/s,(相同环境测试)
2 受网络带宽影响很大,连接linux测试慢了10倍
3 目前spingboot2.0之后集成lettuce连接redis,实际情况也就是5000左右,不会向jedis上万的

结论

1 上述16G配置在一般中小型公司算是比较高的配置了,当前测试都是局域网,带宽没限制比外网好太多,所以主要影响的就是内存了,redis官方理论写8万,读11万,应该是内存和网络io没限制的情况下最理想的情况下,当然内存2个T的肯定比16g测试出来的高太多,没条件测试
2 同一个机器下集群确实比单机redis读写能力更好,现在微服务大多数服务器配置2G,4G,8G,16G,32G的因该比较少,这种情况下redis读写能力在5000/s左右,集群的话可能达到1万左右,已经够用了,当前这是大概的说话,实际还要看情况
3 Jedis连接比lettuce确实快了很多将尽2倍数,RedisTemplate底层是lettuce线程安全的

5 redis7默认是否开启多线程?

image.png

在单机模式下,可以开启多线程,但是在其他模式,最好不开启,Redis实例的 CPU开销不大但吞吐量却没有提升,可以考虑使用Redis7的多线程机制,加速网络处理,进而提升实例的吞吐量

6 redis是否支持多线程?

redis4之后才慢慢支持多线程,直到redis6/7稳定

7 redis是单线程的,如何利用多个cpu/内核?

CPU并不是您使用Redis的瓶颈,因为通常Redis要么受内存限制,要么受网络限制。例如,使用在平均Linux系统上运行的流水线Redis每秒可以发送一百万个请求,因此,如果您的应用程序主要使用0(N)或O(lg(N) )命令,则几乎不会使用过多的CPU。
但是,为了最大程度地利用CPU,您可以在同一中启动多个Redis实例,并将它们视为不同的服务器。在某个时候,单个盒子可能还不够,因此,如果您要使用多个CPU,则可以开始考虑更早地进行分片的某种方法。

8 Redis单线程为什么加了多线程特性?

8.1 因为单线程有单线程的问题,比如我要删除一个比较大的key,
del bigkey 会一直阻塞,等待删除完成,才能继续操作,会导致Redis主线程卡顿
所以引入了 惰性删除 可以有效避免Redis主线程卡顿
Redis 4.0 中就新增了多线程的模块,当然此版本中的多线程主要是为了解决删除数据效率比较低的问题的。
而lazy free的本质就是把某些cost(主要时间复制度,占用主线程cpu时间片)较高删除操作,从redis主线程剥离让BIO子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题。
虽然引入了多个线程来实现数据的异步惰性删除等功能,但其处理读写请求的仍然只有一个线程,所以仍然算是狭义上的单线程

9 影响redis主要的性能瓶颈是内存/网络带宽/cpu?

image.png

内存和带宽

10 redis大key如何处理?

准备数据阶段

1 造数据
for((i=1;i<=100*10000;i++)); do echo “set k i v i v ivi” >> /tmp/redisTest.txt ;done;
2 pipe管道命令执行
cat /tmp/redisTest.txt | /usr/local/install/redis-6.2.5/src/redis-cli -h localhost -p 6379 -a 123456 --pipe

:::info
linux redis6 100万数据, windows redis3.2 231万数据
:::
image.png

10.1 你如何生产上限制keys*、flushdb、flushall等危险命令以及防止误删误用?

image.png

image.png

  • keys * / flushall / flushdb 严禁 在线上使用
  • keys * / flushall / flushdb 会造成阻塞,会导致Redis其他的读写都被延后甚至是超时报错,可能会引起缓存雪崩甚至数据库宕机

通过配置redis.conf禁用危险命令

rename-command keys ""
rename-command flushdb ""
rename-command flushall ""

重启禁用之后找不到命令
image.png

替代方案 scan类似与mysql limit,避免卡顿

image.png

 @Test
    void tesScan() throws InterruptedException {
        long start = System.currentTimeMillis();
        //需要匹配的key
        String patternKey = "1*";
        ScanOptions options = ScanOptions.scanOptions()
                //这里指定每次扫描key的数量(很多博客瞎说要指定Integer.MAX_VALUE,这样的话跟        keys有什么区别?)
                .count(10000)
                .match(patternKey).build();
        RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
        Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
        List<String> result = new ArrayList<>();
        while(cursor.hasNext()){
            result.add(cursor.next().toString());
        }
        //切记这里一定要关闭,否则会耗尽连接数。报Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a
        cursor.close();
       log.info("scan扫描共耗时:{} ms key数量:{}",System.currentTimeMillis()-start,result.size());

    }

10.2 MEMORY USAGE命令你用过吗?

image.png

10.3 BigKey问题,多大算big?你如何发现?如何删除?如何处理?

多大算big

大的内容不是key本身,二十key对应的value
image.png
image.png

危害

  1. 内存不均,集群迁移困难
  2. 超时删除,大key导致阻塞
  3. 网络流量阻塞
如何产生、发现、删除

产生

  1. 社交类粉丝列表逐步递增
  2. 汇总统计某个报表,经年累月的积累

发现

redis-cli --bigkeys

redis-cli -h 127.0.0.1 -p 6379 -a 111111 --bigkeys
//每隔 100 条 scan 指令就会休眠 0.1s,ops 就不会剧烈抬升,但是扫描的时间会变长
redis-cli -h 127.0.0.1 -p 6379 –-bigkeys -i 0.1
image.png

  • 好处
    • 给出每种数据结构Top 1 bigkey,同时给出每种数据类型的键值个数+平均大小
  • 不足
    • 想查询大于10kb的所有key,–bigkeys参数就无能为力了,需要用到memory usage来计算每个键值的字节数

memory usage
image.png
image.png
删除bigkey

  • String
    • 一般用del,过于庞大 unlink
  • hash
    • 使用hscan每次获取少量field-value,再使用hdel删除每个field
    • 语法 hscan key cursor[match pattern] [count count]

image.png

  • ** list**
    • 使用 ltrim 渐进式逐步删除,直到全部删除
    • 命令 redis localhost:6379> ltrim key_name start stop

image.png
image.png

  • set
    • 使用sscan 每次获取部分元素,再使用 srem 命令删除每个元素
  • image.png

image.png

  • zset
    • 使用zscan每次获取部分元素,再使用ZREMRANGEBYRANK 命令删除每个元素
    • 命令

image.png

10.4 BigKey你做过调优吗?惰性释放lazyfree了解吗?

  • 阻塞和非阻塞删除命令

image.png

10.5 MoreKey问题,生产上redis数据库有1000w记录,你如何遍历?keys*可以吗?

1 scan 命令代替 keys ,避免卡顿

11 双写一致性

11.1 双写一致性,你先动缓存redis还是数据库mysql,why?

4中双写一致性更新策略

先更新数据库,再更新缓存

问题

  • 回写redis失败,读到redis脏数据
  • 多线程下/高并发下,回写redis延迟,redis更新的数据不是最终结果,导致督导redis脏数据,mysql和redis数据不一致

image.png

先更新缓存,再更新数据库

问题

  • 一般把mysql写入作为准则,保证最后的解释,不推荐这样做
  • 多线程高并发下,redis和mysql数据不一致

image.png

先删除缓存,再更新数据库

a线程删除redis,正在更新mysql还没commit,b线程读取mysql回写redis,a线程更新完成mysql发现redis 还是之前旧值

解决方案延时双删

image.png

延迟双删问题
这个删除该休眠多久呢?
  • 统计线程读取和写入缓存的操作时间,自行评估项目中读业务数据耗时逻辑,进行估算,然后写数据的休眠时间再读取业务逻辑耗时的基础上增加百毫秒即可
  • 新启动一个后台监控程序,watchDog监控程序会加时
这种同步淘汰策略,吞吐量降低咋么办?

image.png

先更新数据库,再删除缓存

image.png
如果删除redis中的key不成功,如何解决
消息队列
image.png

总结

先更新数据库,再删除缓存
如果业务层要求必须读取一致性的数据,那么我们就需要在更新数据库时,先在Redis缓存客户端暂停并发读请求,等数据库更新完、缓存值删除后,再读取数据,从而保证数据一致性,这是理论可以达到的效果,但实际,不推荐,因为真实生产环境中,分布式下很难做到实时一致性,一般都是最终一致性。

11.2 延迟双删你做过吗?会有哪些问题?

参照3.1 3.2

11.3 微服务查询redis无mysql有,为保证数据双写一致性回写redis需要注意仕么?

11.4 双加锁策略你了解吗?如何经量避免缓存击穿?

双锁策略定义

  • 多个线程同时去查询数据库的这条数据,就在第一个查询数据的请求上使用一个互斥锁来锁住他。
  • 其他线程获取不到锁就一直等待,等第一个线程查询到了数据,然后做了缓存
  • 后面的线程进来发现已经有了缓存,就直接走缓存

避免缓存击穿

1 设置热点数据永不过期
2 加互斥锁,如下代码

/**
     * 压力测试结果
     *  1 id存在
     *   type=0,qps=1000,id存在    吞吐量    979.4/s   平均值  2
     *   type=0,qps=10000,id存在   吞吐量   1550.2/s   平均值  14
     *   type=1,qps=10000,id存在   吞吐量   4207.2/s   平均值  13
     *  2 id不存在(null,失效,攻击能情况)
     *    type=0,qps=1000,id不存在    吞吐量    1541.3/s   平均值  42
     *    type=0,qps=10000,id不存在   吞吐量   1420.2/s   平均值  99
     *    type=1,qps=10000,id不存在   吞吐量   1582.7/s   平均值  89
     *
     * 结论:
     *    1 重量级锁synchronized的吞吐量小于轻量级可重入锁ReentrantLock的吞吐量
     *    2 重量级锁synchronized的平均响应时间大于轻量级锁ReentrantLock
     *    3 双入保护机制能有效的保护系统的健壮性
     *
     * @param id
     * @param type
     * @param qps
     * @return
     */
    @RequestMapping(value = "findUserById")
    public RedisBs findUserById(@RequestParam("id") Integer id, @RequestParam("type") int type, @RequestParam("qps")int qps) {
        com.redis.redis01.bean.RedisBs userById = service.findUserById(id,type,qps);
        return userById;

    }
package com.redis.redis01.service;

import com.redis.redis01.bean.RedisBs;
import com.redis.redis01.mapper.RedisBsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.beans.Transient;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@Service
public class RedisBsService {

    //定义key前缀/命名空间
    public static final String CACHE_KEY_USER = "user:";
    @Autowired
    private RedisBsMapper mapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private static ReentrantLock lock = new ReentrantLock();

    /**
     * 业务逻辑没有写错,对于中小长(qps<=1000)可以使用,但是大厂不行:大长需要采用双检加锁策略
     *
     * @param id
     * @return
     */
    @Transactional
    public RedisBs findUserById(Integer id,int type,int qps) {
        //qps<=1000
        if(qps<=1000){
            return qpsSmall1000(id);
        }
        //qps>1000
        return qpsBig1000(id, type);
    }

    /**
     * 加强补充,避免突然key失效了,或者不存在的key穿透redis打爆mysql,做一下预防,尽量不出现缓存击穿的情况,进行排队等候
     * @param id
     * @param type 0使用synchronized重锁,1ReentrantLock轻量锁
     * @return
     */
    private RedisBs qpsBig1000(Integer id, int type) {
        RedisBs redisBs = null;
        String key = CACHE_KEY_USER + id;
        //1先从redis里面查询,如果有直接返回,没有再去查mysql
        redisBs = (RedisBs) redisTemplate.opsForValue().get(key);
        if (null == redisBs) {
            switch (type) {
                case 0:
                    //加锁,假设请求量很大,缓存过期,大厂用,对于高qps的优化,进行加锁保证一个请求操作,让外面的redis等待一下,避免击穿mysql
                    synchronized (RedisBsService.class) {
                        //第二次查询缓存目的防止加锁之前刚好被其他线程缓存了
                        redisBs = (RedisBs) redisTemplate.opsForValue().get(key);
                        if (null != redisBs) {
                            //查询到数据直接返回
                            return redisBs;
                        } else {
                            //数据缓存
                            //查询mysql,回写到redis中
                            redisBs = mapper.findUserById(id);
                            if (null == redisBs) {
                                // 3 redis+mysql都没有数据,防止多次穿透(redis为防弹衣,mysql为人,穿透直接伤人,就是直接访问mysql),优化:记录这个null值的key,列入黑名单或者记录或者异常
                                return new RedisBs(-1, "当前值已经列入黑名单");
                            }
                            //4 mysql有,回写保证数据一致性
                            //setifabsent
                            redisTemplate.opsForValue().setIfAbsent(key, redisBs,7l, TimeUnit.DAYS);
                        }
                    }
                    break;
                case 1:
                    //加锁,大厂用,对于高qps的优化,进行加锁保证一个请求操作,让外面的redis等待一下,避免击穿mysql
                    lock.lock();
                    try {
                        //第二次查询缓存目的防止加锁之前刚好被其他线程缓存了
                        redisBs = (RedisBs) redisTemplate.opsForValue().get(key);
                        if (null != redisBs) {
                            //查询到数据直接返回
                            return redisBs;
                        } else {
                            //数据缓存
                            //查询mysql,回写到redis中
                            redisBs = mapper.findUserById(id);
                            if (null == redisBs) {
                                // 3 redis+mysql都没有数据,防止多次穿透(redis为防弹衣,mysql为人,穿透直接伤人,就是直接访问mysql),优化:记录这个null值的key,列入黑名单或者记录或者异常
                                return new RedisBs(-1, "当前值已经列入黑名单");
                            }
                            //4 mysql有,回写保证数据一致性
                            redisTemplate.opsForValue().set(key, redisBs);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        //解锁
                        lock.unlock();
                    }
            }
        }
        return redisBs;
    }
    private RedisBs qpsSmall1000(Integer id) {
        RedisBs redisBs = null;
        String key = CACHE_KEY_USER + id;
        //1先从redis里面查询,如果有直接返回,没有再去查mysql
        redisBs = (RedisBs) redisTemplate.opsForValue().get(key);
        if (null == redisBs) {
            //2查询mysql,回写到redis中
            redisBs = mapper.findUserById(id);
            if (null == redisBs) {
                // 3 redis+mysql都没有数据,防止多次穿透(redis为防弹衣,mysql为人,穿透直接伤人,就是直接访问mysql),优化:记录这个null值的key,列入黑名单或者记录或者异常
                return new RedisBs(-1, "当前值已经列入黑名单");
            }
            //4 mysql有,回写保证数据一致性
            redisTemplate.opsForValue().set(key, redisBs);
        }
        return redisBs;
    }

}

11.5 redis和mysql双写100%会处纰漏,做不到强一直性,你如何保证最终一致性?

以mysql写入数据为准,对缓存操作做最大努力即可,也就是说,写入mysql成功,缓存更新失败,那么只要达到过期时间,后面请求自然会从数据库中读取新值然后回填缓存,达到最终一致性

12 mysql有记录改动了,立刻同步反应到redis?该如何做?

canal 监听mysql回写redis
https://github.com/alibaba/canal

image.pngcanal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。
基于日志增量订阅和消费的业务包括

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

13 对于亿级数据的收集、清洗、统计、展现,需要用仕么技术实现?介绍一下pv、uv、pau?仕么是基数统计?

UV: Unique Visitor ,独立访客数,是指在一个统计周期内,访问网站的人数之和。一般理解客户ip,需要去重
PV : Page View,浏览量,是指在一个统计周期内,浏览页面的数之和。不需要去重
DAU: Daily Active User 日活跃用户数量;去重
DNU:Daily New User,日新增用户数
MAU:Monthly New User,月活跃用户;去重
需要使用redis hyperloglog基数统计数据结构来实现
基数统计:数据集中不重复的元素的个数

HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的内存空间总是固定的、并且是很小的。因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身;
HyperLogLog 优势在于只需要花费 12 KB 内存,就可以计算接近 2^64 个元素的基数,和元素越多就越耗费内存的 Set 和 Hash 类型相比,HyperLogLog 就非常节省空间。所以,非常适合统计百万级以计网站的独立访客数场景。
image.png

14 布隆过滤器了解过吗?

由一个初值都为零的bit数组和多个哈希函数构成,用来快速判断集合中是否存在某个元素

目的
减少内存占用
方式
不保存数据信息,只是在内存中做一个是否存在的标记flag
本质
判断具体数据是否村在于一个大的集合中
布隆过滤器是一种类似 set 的数据结构,只是统计结果在巨量数据下有点小瑕疵,不够完美

  • 它实际上是一个很长的二进制数组(00000000)+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中。
  • 通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。
  • 链表、树、哈希表等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,最终达到瓶颈。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为O(n),O(logn),O(1)。这个时候,布隆过滤器(Bloom Filter)就应运而生

能干嘛

  • 高效地插入和查询,占用空间少,返回地结果是不确定性 + 不完美性
    • 一个元素如果判断结果:存在时,元素不一定存在,不存在时,元素一定不存在
  • 布隆过滤器可以添加元素,但是不能删除元素
    • 涉及到hashcode判断依据,删掉元素会导致误判率增加
    • 为什么不能删掉?
      - 因为他是有多个 hash 函数,对一个值进行多次 hash 运算,将获得的每个值,在对应位置存 1 ,容易导致这个 1 也代表别的值,一旦删除,另一个值也无法通过

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1215969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023.11.16 hivesql高阶函数之json

目录 1.数据准备 2.操作 -- 方式1: 逐个(字段)处理, get_json_object UDF函数 最大弊端是一次只能解析提取一个字段 -- 方式2: 逐条处理. json_tuple 这是一个UDTF函数 可以一次解析提取多个字段 -- 方式3: 在建表时候, 直接处理json, row format SerDe 能处理Json的SerDe类…

React函数组件状态Hook—useState《进阶-对象数组》

React函数组件状态-state 对象 state state 中可以保存任意类型的 JavaScript 值&#xff0c;包括对象。但是&#xff0c;你不应该直接修改存放在 React state 中的对象。相反&#xff0c;当你想要更新⼀个对象时&#xff0c;你需要创建⼀个新的对象&#xff08;或者将其拷⻉⼀…

Ubuntu18.04安装Loam保姆级教程

系统环境&#xff1a;Ubuntu18.04.6 LTS 1.Loam的安装前要求&#xff1a; 1.1 ROS安装&#xff1a;参考我的另一篇博客 Ubuntu18.04安装ROS-melodic保姆级教程_灬杨三岁灬的博客-CSDN博客还是那句话&#xff0c;有时候加了这行也不好使&#xff0c;我是疯狂试了20次&#xf…

基于51单片机步进电机加减速正反转数码管显示( proteus仿真+程序+原理图+设计报告+讲解视频)

基于51单片机步进电机加减速正反转数码管显示( proteus仿真程序原理图设计报告讲解视频&#xff09; &#x1f4d1;1.主要功能&#xff1a;&#x1f4d1;讲解视频&#xff1a;&#x1f4d1;2.仿真&#x1f4d1;3. 程序代码&#x1f4d1;4. 设计报告&#x1f4d1;5. 设计资料内容…

如何快速本地搭建悟空CRM结合内网穿透工具高效远程办公

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 无需公网IP&#xff0c;使用cpolar实现悟空CRM远程访问二. 通过公网来访问公司…

移动机器人路径规划(三)--- 基于采样的路径规划Sample-basedpath finding

目录 1 基于采样的路径规划的优点和一些重要概念 2 概率路图 Probabilistic Road Map 3 快速搜索随机树Rapidly-exploring Random Tree 3.1 RRT 3.2 RRT Connect 4 RRT算法的优化 4.1 RRT* 4.2 Kinodynamic-RRT* 4.3 Anytime-RRT* 5 Advanced Sampling-based Methods…

在混料配料输送系统中使用485modbus转profinet网关案例

485Modbus转Profinet网关是一种在工业自动化控制系统中常用的设备&#xff0c;能够实现不同通信协议之间的转换&#xff0c;对于混料配料输送系统的优化和控制具有重要作用。 通过使用485Modbus转Profinet网关&#xff0c;混料配料输送系统能够实现与不同设备之间的通信和数据交…

linux下安装python3.8(有坑)

1安装包下载 ###直接官网下载linux版本&#xff0c;找到对应的包 https://www.python.org/downloads/source/2安装包解压 tar -zxvf Python-3.8.0.tgz 3编译安装 1&#xff09;设置安装目录&#xff0c;比如在此创建在 /usr/local/python3 &#xff1a; mkdir -p /usr/loca…

clip4clip:an empirical study of clip for end to end video clip retrieval

广告深度学习计算&#xff1a;阿里妈妈智能创意服务优化使用CPU/GPU分离的多进程架构&#xff0c;加速阿里妈妈智能创意服务。https://mp.weixin.qq.com/s/_pjhXrUZVzFRtiwG2LhnkwCLIP4Clip: CLIP 再下一城&#xff0c;利用CLIP实现视频检索 - 知乎前言&#xff1a; OpenAI 的论…

networkx使用draw画图报错:TypeError: ‘_AxesStack‘ object is not callable

一、问题描述 在使用networkx的draw绘图时nx.draw(g,posnx.spring_layout(g))&#xff0c;报错&#xff1a;TypeError: _AxesStack object is not callable 二、原因 可能是当前python环境下的networkx和matplotlib的版本不匹配。我报错时的networkx2.8&#xff0c;matplotl…

DBeaver还原mysql数据库

DBeaver还原mysql数据库 DBEaver还原mysql数据库新建一个要还原的数据库选择工具》恢复数据库 DBEaver还原mysql数据库 新建一个要还原的数据库 选中数据库,右键新建一个数据库&#xff0c;字符集和排序规则默认的即可 选择工具》恢复数据库 选中刚刚创建好的数据库&#x…

2—10岁女童羽绒服,黑色长款也太好看了吧

冬天怎么能没有一件暖呼呼的羽绒服呢&#xff1f; 黑色长款羽绒服也赞了吧 大长款连帽&#xff0c;防风保暖设计 时尚与美观度都兼具呢&#xff01;好穿又耐穿&#xff01;

电路综合-基于简化实频的集总参数电路匹配1

电路综合-基于简化实频的集总参数电路匹配1 对于分布式参数的匹配方法&#xff0c;我们已经深入探讨并给出了解决方案&#xff1a; 10、电路综合-基于简化实频的宽带匹配电路设计方法 {阻抗匹配其实就是S11电路的匹配&#xff0c;给定需要匹配的阻抗数值去设计微带电路&#…

李开复再度回应争议;10 月中国游戏厂商及应用出海收入 30 强出炉丨 RTE 开发者日报 Vol.86

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有…

什么是等保测评?

随着近几年随着网络技术的发展&#xff0c;互联网应用的普及和丰富&#xff0c;互联网安全问题也日益严重&#xff0c;利用信息技术进行的高科技犯罪事件呈现增长态势。从2004年度CNCERT的信息网络安全工作报告中我们看到&#xff0c;信息网络安全事故在逐年上升&#xff0c;20…

2022年09月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 点击绿旗,下面哪个选项可以实际播放放马叫声并在声音全部播放完后,马向右移动? A: B: C: D: 答案:D

Linux 爱好者线下沙龙:成都场圆满结束 下一场西子湖畔相见 | LLUG·第五站

导读&#xff1a;第四站 LLUG成都场已于10 月 29 日在武侯区菁蓉汇成功举办。LLUG 第五站将于11 月 25 日走进美丽的西子湖畔&#xff0c;在这个冬日&#xff0c;LLUG 与你在杭州线下相见。 10 月 29 日&#xff0c;LLUG 成都场成功在武侯区菁蓉汇举办。 LLUG成都站由 Linux 中…

中小企业数字化的“下半场”,与华为的生态伙伴“引力场”

作者 | 曾响铃 文 | 响铃说 中小企业数字化始终是业界关注的重点&#xff0c;也催生了庞大的产业数字化价值空间等待挖掘&#xff0c;在如何推进这件事上&#xff0c;各方都在持续发力。 这其中&#xff0c;针对中小企业迫切需求&#xff0c;来自华为的动作正变得越来越紧凑…

苏宁API:一键搜索,海量商品任你选!

使用苏宁API按关键字搜索商品&#xff0c;可以在API的搜索参数中设置关键字。 例如&#xff0c;在搜索商品时&#xff0c;可以在API的请求参数中设置q关键字。例如&#xff0c;要搜索“鞋子”&#xff0c;可以将q设置为“鞋子”。 另外&#xff0c;还可以设置其他的搜索参数&…

CDR最新CorelDRAWX8安装步骤教程

CorelDRAW Graphics Suite非凡的设计能力广泛地应用于商标设计、标志制作、模型绘制、插图描画、排版及分色输出等等诸多领域。作为一个强大的绘图软件&#xff0c;它被喜爱的程度可用事实说明&#xff1a;用作商业设计和美术设计的PC机几乎都安装了 。CorelDRAW让您轻松应对创…