문자열 유형은 간단하고 편리하며 공간 사전 할당을 지원합니다. 즉, 매번 더 많은 공간이 할당되므로 다음에 문자열이 길어지면 문제가 발생합니다. 물론 남은 공간이 충분하다면 추가 신청은 필요하지 않습니다.
List 유형은 간단한 메시지 대기열을 구현할 수 있지만 ACK 모드를 지원하지 않으므로 메시지 손실이 발생할 수 있습니다.
해시 테이블은 관계형 데이터베이스와 약간 비슷하지만, 해시 테이블이 점점 커지면 hgetall과 같은 문은 사용하지 않도록 주의하세요. 많은 양의 데이터를 요청하면 Redis가 차단되므로 뒤에 있는 형제들이 기다려야 할 것이다.
set set 컬렉션 유형은 일부 통계를 수행하는 데 도움이 될 수 있습니다. 예를 들어 특정 날짜의 활성 사용자 수를 계산하려는 경우 컬렉션에 사용자 ID를 직접 넣을 수 있습니다. , 세트 간의 차이를 얻을 수 있고 sunion. 세트 간의 합집합을 얻을 수 있으며 많은 기능이 있지만 이러한 작업에는 약간의 CPU 및 IO 리소스가 필요하므로 주의해야 합니다. 블로킹이 발생할 수 있으므로 사용 시 주의하세요.
zset은 정렬이 가능하기 때문에 다음과 같은 응용 시나리오가 많습니다. 좋아요를 누른 상위 xx명의 사용자, 지연된 대기열 등
비트맵 비트맵의 장점은 특히 특정 날짜에 로그인한 사용자 수, 특정 사용자가 로그인했는지 여부 등 일부 통계를 수행할 때 공간을 절약한다는 것입니다. 비트맵을 사용하지 않으면 세트 사용을 고려할 수도 있습니다.
SADD day 1234//签到就添加到集合 SISMEMBER day 1234//判断1234是否签到 SCARD day //有多少个签到的
set는 기능적으로는 만족스럽지만 비트맵에 비해 저장공간을 더 많이 차지합니다. set의 맨 아래 레이어는 주로 정수 컬렉션이나 해시 테이블로 구성되어 있으며 일반적으로 데이터 양이 매우 적을 경우에만 사용됩니다. 512개 미만의 요소, 그리고 요소는 모두 정수여야 합니다. 집합의 경우 정수 집합의 데이터는 더 작고 메모리에서 연속적입니다. 쿼리는 이진 검색만 가능하며 시간 복잡도는 O(logN)입니다. 여기서 해시테이블은 값이 null을 가리키고 컬렉션이기 때문에 충돌이 없다는 점을 제외하면 Redis의 5가지 주요 데이터 유형의 해시와 동일합니다. Rehash 관련 문제를 고려해야합니다. 사용자 로그인 문제에 대해서는 좀 거리가 멀군요. 사용자가 많을 때 set은 반드시 해시테이블을 사용하게 됩니다. 실제로 각 요소는 dictEntry 구조입니다
typedef struct dictEntry { // 键 void *key; // 值 union { void *val; uint64_t u64; int64_t s64; } v; // 指向下个哈希表节点,形成链表 struct dictEntry *next; } dictEntry;
구조, 당신은 무엇을 볼 수 있습니까? 우선, 값이 Union(값 없음)과 Next(충돌 없음)가 비어 있지만 구조 자체에는 공간과 키가 필요합니다. 이 점유 공간은 실제이며 비트맵을 사용하면 1비트이면 충분합니다. 숫자를 나타내고 공간을 절약해 줍니다. 비트맵을 설정하고 계산하는 방법을 살펴보겠습니다.
SETBIT day 1234 1//签到 GETBIT day 1234//判断1234是否签到 BITCOUNT day//有多少个签到的
bf redis4.0 이후에 지원되는 Bloom 필터 RedisBloom 인데 해당 모듈을 별도로 로드해야 합니다. 물론 위의 비트맵을 기반으로 자체 Bloom 필터를 구현할 수도 있지만 Redis가 이미 지원하고 있기 때문에, RedisBloom은 개발 시간을 단축할 수 있습니다. 여기서는 Bloom 필터의 기능에 대해 자세히 설명하지 않겠습니다. RedisBloom의 관련 사용법을 살펴보겠습니다.
# 可以通过docker的方式快速拉取镜像来玩耍 docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest docker exec -it redis-redisbloom bash redis-cli # 相关操作 bf.reserve sign 0.001 10000 bf.add sign 99 //99这个用户加入 bf.add exists 99//判断99这个用户是否存在
블룸 필터에는 오판이 있기 때문에 모든 bf는 맞춤 오판 비율을 지원합니다. 0.001은 오판 비율을 나타내고, 10000은 블룸 필터가 저장할 수 있는 요소 수를 나타내며, 실제 저장된 요소 수를 초과하면 false입니다. 긍정적인 비율이 높아질 것입니다.
HyperLogLog는 통계에 사용할 수 있습니다. 저장 공간을 거의 차지하지 않는다는 장점이 있습니다. 2^64개 요소를 계산하는 데 메모리가 12KB만 필요합니다. 실제로는 주로 UV와 같은 카디널리티 통계에 관한 것입니다. 기능적으로 말하면 UV는 세트 또는 해시를 사용하여 저장할 수 있지만 단점은 스토리지를 소비하고 공간을 절약하려는 경우 쉽게 큰 키가 될 수 있다는 것입니다. 12KB도 사용할 수 있습니다. 공간 비트맵은 12*1024*8=98304개의 요소만 계산할 수 있지만 HyperLogLog는 2^64개의 요소를 계산할 수 있습니다. 그러나 이러한 강력한 기술에는 실제로 확률에 따른 오류와 표준 오류가 있습니다. 계산 비율은 0.81%입니다. 대용량 데이터가 계산되고 정확도 요구 사항이 그다지 높지 않은 시나리오에서 HyperLogLog는 여전히 공간 절약에 매우 좋습니다.
PFADD uv 1 2 3 //1 2 3是活跃用户 PFCOUNT uv //统计
GEO 是可以应用在地理位置的业务上,比如微信附近的人或者附近的车辆等等,先来看一下如果没有GEO 这种数据结构,你如何知道你附近的人?首先得上报自己的地理位置信息吧,比如经度 116.397128,纬度 39.916527,此时可以用 string、hash 数据类型存储,但是如果要查找你附近的人,string 和 hash 这种就无能为例了,你不可能每次都要遍历全部的数据来判断,这样太耗时了,当然你也不可能通过 zset 这种数据结构来把经纬度信息当成权重,但是如果我们能把经纬度信息通过某种方式转换成一个数字,然后当成权重好像也可以,这时我们只需通过zrangebyscore key v1 v2也可以找到附近的人。真的需要这么麻烦吗?于是 GEO 出现了,GEO 转换经纬度为数字的方法是“二分区间,区间编码”,这是什么意思呢?以经度为例,它的范围是[-180,180],如果要采用3位编码值,那么就是需要二分3次,二分后落在左边的用0表示,右边的用1表示,以经度是121.48941 来说,第一次是在[0,180]这个区间,因此记1,第二次是在[90,180],因此再记1,第三次是在[90,135],因此记0。纬度也是同样的逻辑,假设此时对应的纬度编码后是010,最后把经纬度合并在一起,需要注意的是经度的每个值在偶数位,纬度的每个值在奇数位。
1 1 0 //经度 0 1 0 //纬度 ------------ 101100 //经纬度对应的数值
原理是这样,我们再来看看 redis 如何使用 GEO:
GEOADD location 112.123456 41.112345 99 //上报用户99的地理位置信息 GEORADIUS location 112.123456 41.112345 1 km ASC COUNT 10 //获取附近1KM的人
生产环境用单实例 redis 的应该比较少,单实例的风险在于:
单点故障即服务故障,没有backup
单实例压力大,又要提供读,又要提供写
于是我们首先想到的就是经典的主从模式,而且往往是一主多从,这是因为大部分应用都是读多写少的情况,我们的主负责更新,从负责提供读,就算我们的主宕机了,我们也可以选择一个从来充当主,这样整个应用依然可以提供服务。
当一个 redis 实例首次成为某个主的从的时候,这时主得把数据发给它,也就是 rdb 文件,这个过程 master 是要 fork 一个子进程来处理的,这个子进程会执行 bgsave 把当前的数据重新保存一下,然后准备发给新来的从,bgsave 的本质是读取当前内存中的数据然后保存到 rdb 文件中,这个过程涉及大量的 IO,如果直接在主进程中来处理的话,大概率会阻塞正常的请求,因此使用个子进程是个明智的选择。
那 fork 的子进程在 bgsave 过程中如果有新的变更请求会怎么办?
严格来说子进程出来的一瞬间,要保存的数据应该就是当时那个点的快照数据,所以是直接把当时的内存再复制一份吗?不复制的话,如果这期间又有变更改怎么办?其实这要说到写实复制(COW)机制,首先从表象上来看内存是一整块空间,其实这不太好维护,因此操作系统会把内存分成一小块一小块的,也就是内存分页管理,一页的大小一般是4K、8K或者16K等等,redis 的数据都是分布在这些页面上的,出于效率问题,fork 出来的子进程是和主进程是共享同一块的内存的,并不会复制内存,如果这期间主进程有数据变更,那么为了区分,这时最快捷的做法就是把对应的数据页重新复制一下,然后主的变更就在这个新的数据页上修改,并不会修改来的数据页,这样就保证了子进程处理的还是当时的快照。
以上说的变更是从快照的角度来考虑的,如果从数据的一致性来说,当快照的 rdb 被从库应用之后,这期间的变更该如何同步给从库?答案是缓冲区,这个缓冲区叫做 replication buffer,主库在收到需要同步的命令之后,会把期间的变更都先保存在这个缓冲区中,这样在把 rdb 发给从库之后,紧接着会再把 replication buffer 的数据也发给从库,最终主从就保持了一致。
replication buffer不是万能的补给剂
我们来看看 replication buffer 持续写入的时间有多长。
我们知道主从同步的时候,主库会执行 fork 来让子进程完成相应地工作,因此子进程从开始执行 bgsave 到执行完毕这期间,变更是要写入 replication buffer 的。
rdb 生成好之后,需要把它发送给从库,这个网络传输是不是也需要耗点时间,这期间也是要写入 replication buffer 的。
从库在收到 rdb 之后需要把 rdb 应用到内存里,这期间从库是阻塞的,无法提供服务,因此这期间也是要写入 replication buffer 的。
복제 버퍼는 버퍼이기 때문에 크기가 제한되어 있습니다. 위의 세 단계 중 하나라도 시간이 오래 걸리면 복제 버퍼가 급격히 커지게 됩니다(정상적인 쓰기가 있는 경우). 제한을 초과하면 마스터 라이브러리와 슬레이브 라이브러리 간의 연결이 끊어지며, 연결이 끊어진 후 슬레이브 라이브러리가 다시 연결되면 복제가 다시 시작되고 동일한 긴 복제 단계가 반복됩니다. 버퍼 크기는 여전히 매우 중요하며 일반적으로 쓰기 속도, 초당 쓰기 양, 네트워크 전송 속도와 같은 요소를 기준으로 판단해야 합니다.
슬레이브 데이터베이스 네트워크가 좋지 않고 마스터 데이터베이스 연결이 끊어지면 어떻게 해야 하나요?
일반적으로 마스터와 슬레이브 간의 연결이 설정되어 있는 한 마스터 데이터베이스에 대한 후속 변경 사항은 슬레이브 데이터베이스에서 직접 재생하기 위해 슬레이브 데이터베이스로 직접 전송될 수 있지만 네트워크 환경이 다음과 같다고 보장할 수는 없습니다. 100% 원활하므로 슬레이브 데이터베이스와 마스터 데이터베이스 간의 연결 끊김 문제도 고려해야 합니다.
redis2.8 이전에는 슬레이브 데이터베이스의 연결이 잠시 끊어졌더라도 나중에 슬레이브 데이터베이스가 다시 연결되면 메인 데이터베이스가 직접적으로 무의식적으로 전체 동기화를 수행해야 했습니다. 2.8 버전 이상에서는 증분 복제를 지원하는데, 변경 기록을 저장하기 위한 버퍼가 있어야 하는데, 여기서 이 버퍼는 논리적으로 링 버퍼이다. 처음부터 덮어쓰게 되므로 크기 제한도 있습니다. 슬레이브 라이브러리가 다시 연결되면 슬레이브 라이브러리는 메인 라이브러리에 "현재 xx 위치에 복사했습니다."라고 알립니다. 메인 라이브러리는 슬레이브 라이브러리로부터 메시지를 받은 후 xx 위치의 데이터가 복사되었는지 확인하기 시작합니다. 아직 repl_backlog_buffer에 있다면 xx 이후의 데이터를 슬레이브 라이브러리로 보내면 됩니다. 그렇지 않으면 할 수 있는 일이 없으며 전체 동기화만 다시 수행할 수 있습니다.
마스터-슬레이브 모드에서는 마스터 데이터베이스에 장애가 발생하면 슬레이브 데이터베이스를 마스터 데이터베이스로 업그레이드할 수 있지만 이 프로세스는 수동이며 사람의 노동에 의존하므로 손실을 최소화할 수 없습니다. 자동 관리 및 선택 메커니즘이 여전히 필요합니다. Sentinel 자체도 서비스이지만 데이터 읽기 및 쓰기를 처리하지는 않습니다. Sentinel은 정기적으로 각 Redis 인스턴스와 통신합니다. Redis 통신(ping 작업)을 통해 각 Redis 인스턴스는 지정된 시간 내에 응답하는 한 자신의 위치를 표현할 수 있습니다. 물론, Sentinel 자체가 다운되었거나 네트워크를 사용할 수 없는 경우도 있으므로 일반적으로 Sentinel도 Sentinel 클러스터를 구축하게 되는데, 3개나 5개 등 홀수 개의 클러스터를 갖는 것이 가장 좋습니다. 홀수의 목적은 다음과 같습니다. 주로 선거를 위해 (소수는 다수에 복종합니다).
Ping을 시작한 후 Sentinel이 제 시간에 Pong을 받지 못하면 Redis 인스턴스는 오프라인으로 표시됩니다. 이때는 여전히 오프라인이 아닙니다. 이때 다른 Sentinel도 현재 Sentinel이 오프라인인지 확인합니다. 실제 오프라인에서는 대부분의 센트리가 Redis가 오프라인이라고 판단하면 클러스터에서 쫓아냅니다. 오프라인인 슬레이브 데이터베이스라면 직접 쫓아내면 됩니다. 그러면 데이터베이스도 선택을 실행해야 합니다. 선택은 새 기본 데이터베이스로 사용하기에 가장 적합한 선택이어야 합니다. 메인 라이브러리로 사용하기에 가장 적합한 라이브러리는 일반적으로 다음 우선순위에 따라 결정됩니다:
가중치 각 슬레이브 라이브러리는 실제로 가중치가 더 높은 슬레이브 라이브러리가 우선순위를 갖습니다.
복사 각 슬레이브 데이터베이스에서 복사 진행 상황이 다를 수 있습니다. 실제로 위의 조건이 충족되면 각 Redis 인스턴스는 고유한 ID를 갖습니다. 동일하면 가장 작은 ID를 가진 라이브러리가 메인 라이브러리로 선택됩니다crc16(key)%16384
客户端将缓存插槽信息,以便在每个键到达时只需计算即可确定该将其发送到哪个实例进行处理。但是客户端缓存的槽信息并不是一成不变的,比如在增加实例的时候,这时候会导致重新分片,那么原来客户端缓存的信息就会不准确,一般这时候会发生两个常见的错误,严格来说也不是错误,更像一种信息,一个叫做MOVED,一个叫做ASK。moved的意思就说,原来是实例A负责的数据,现在被迁移到了实例B,MOVED 代表的是迁移完成的,但是 ASK 代表的是正在迁移过程中,比如原来是实例A负责的部分数据,现在被迁移到了实例B,剩下的还在等待迁移中,当数据迁移完毕之后 ASK 就会变成 MOVED,然后客户端收到 MOVED 信息之后就会再次更新下本地缓存,这样下次就不会出现这两个错误了。
위 내용은 Redis의 이상한 데이터 유형과 클러스터 지식은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!