<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[mango_love的专栏]]></title><description><![CDATA[习而简之，简而精之]]></description><link>https://blog.youkuaiyun.com/mango_love</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; mango_love]]></copyright><item><title><![CDATA[Redis分布式基础主从同步]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/107203226</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/107203226</guid><author>mango_love</author><pubDate>Wed, 08 Jul 2020 12:49:23 +0800</pubDate><description><![CDATA[​在使用Redis的时候首先开始是从单台Redis服务器开始，随着业务和用户量的增长，单机会暴漏一些问题，比如单台服务器的响应达到了上限、Redis服务器宕机所有请求全部越过缓存等等一系列问题。



那么我们最简单的就是有一个备用的Redis服务器，当主服务器挂了从服务器就顶替主服务器继续服务，提高可用性。

我们拥有了主从两台Redis服务器之后，当主服务器挂掉之后从服务器就替换上去继续为我们服务，原来的主服务器恢复正常后我们两台服务器的数据又不一样了，那么我们如何保证这两台服务器的数据一致性问题呢呢？]]></description><category></category></item><item><title><![CDATA[Redis解读持久化RDB和AOF原理]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/107128441</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/107128441</guid><author>mango_love</author><pubDate>Sat, 04 Jul 2020 18:44:24 +0800</pubDate><description><![CDATA[我们知道关系型数据库比如MySQL支持全备、差备、增备。为了保证Redis故障重启后仍然可用我们的Redis支持全备（RDB快照备份）和增备（AOF日志连续增量备份），下面我们就来解读Redis持久化的原理。

RDB基础知识



RDB文件存在是以一个压缩后的二进制文件，这个RDB文件一般是保存在Redis安装目录下，通过启动Redis服务器执行rdbLoad函数加载RDB文件，执行rdbSave函数保存RDB文件。

RDB保存

rdbSave函数负责将内存中的数据库数据以RDB格式保存到磁盘中，如]]></description><category></category></item><item><title><![CDATA[Redis数据库实现原理（划重点）]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/107011631</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/107011631</guid><author>mango_love</author><pubDate>Mon, 29 Jun 2020 01:32:26 +0800</pubDate><description><![CDATA[Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中，db数组的每一项都是一个redis.h/redisDb结构，每个redisDb结构代表一个数据库，服务器设置dbnum属性为初始数据库的个数，这个属性一般由数据库服务器配置conf文件中的database节点来配置，默认情况下这个初始值是16。




struct redisServer{//数据库redisDb*db;//服务器数量intdbnum;};

数据库切换...]]></description><category></category></item><item><title><![CDATA[Redis实现消息队列之发布订阅模式]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106822078</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106822078</guid><author>mango_love</author><pubDate>Thu, 18 Jun 2020 01:06:09 +0800</pubDate><description><![CDATA[发布订阅(pub/sub)是一种消息通信模式：发送者(pub)在某一频道发送消息，订阅者(sub)接收消息。发布订阅模式类似与微博关注，比如说博主mango被张三、李四、王五关注，那么mango发一篇微博的时候张李王三人都会从关注里看到这条微博。

那么发布订阅和生产消费有何异同之处呢？生产消费主要是生成一个消息只能被一个客户端消费，而发布订阅可以理解为发布一条消息，在该频道中的所有客户端都会收到，所以有时候我们这个发布订阅类似广播。

注意pubsub是一个数据结构。



Pub/Sub（发布订阅）

]]></description><category></category></item><item><title><![CDATA[Redis实现消息队列之生产消费模式]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106758754</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106758754</guid><author>mango_love</author><pubDate>Mon, 15 Jun 2020 11:22:05 +0800</pubDate><description><![CDATA[简单的介绍下消息队列，使用消息队列首先我们得有一个队列，那么这个队列之前讲过就是先进先出的一个数据结构；那么有了队列以后我们还需要有人在队列里面放东西，那么这个放东西的人我们称之为生产者；有了生产者对应的需要一个消费者，没有消费者这个队列满了就会溢出。

简单队列实现



那么我们Redis刚好有一个数据类型符合这个就是List。list可以实现队列（先进先出）和栈（先进后出），那么这个list又有两种插入数据的方式：头插法和尾插法。所以我们今天使用的结构是队列，使用尾插法，关键的命令有rpush（尾插）]]></description><category></category></item><item><title><![CDATA[Redis缓存穿透、击穿、雪崩来解释个明白]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106617228</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106617228</guid><author>mango_love</author><pubDate>Mon, 08 Jun 2020 13:44:57 +0800</pubDate><description><![CDATA[随着用户的增长，用户的请求也越来越频繁，为了保证服务器在高并发的情况能正常提供服务，我们首先引入了缓存Redis，减少数据库的压力和数据的安全性同时提高了接口反应效率，解决了用户的请求直接与数据库建立连接。

但是在使用Redis的时候，随之而来的问题也会越来越多，有些请求甚至会直接越过Redis直接请求数据库，今天我们来了解Redis数据库经常会谈及的问题缓存雪崩、缓存击穿、缓存穿透。

缓存雪崩

在某一时刻，大量的key失效，用户大量请求直接请求数据库，导致数据库宕机。此时的Redis形同虚设，用户.]]></description><category></category></item><item><title><![CDATA[Redis管道（Pipeline）详解]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106578082</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106578082</guid><author>mango_love</author><pubDate>Fri, 05 Jun 2020 20:53:31 +0800</pubDate><description><![CDATA[在讲解管道前，我们首先来了解一下redis的交互，redis的一次交互是由客户端发起，由服务端接收，那么我们连续操作一些指令，如下图所示：



客户端请求一个指令到服务器到服务器返回数据这个过程非常复杂，既要保证数据能够快速传到也要保证不丢包，那么每次请求响应这个过程中数据传输和客户端接收数据的网络消耗非常大，那么我们怎么来提升这个性能呢？

上面说了，我们来回几次消耗大，那么可以一次性请求，一次性接收吗？当然是可以的，redis可以利用管道来提高性能。



Redis客户端与服务器之间使用TCP协议进]]></description><category></category></item><item><title><![CDATA[Redis通讯协议RESP详解]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106557576</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106557576</guid><author>mango_love</author><pubDate>Thu, 04 Jun 2020 20:37:34 +0800</pubDate><description><![CDATA[Redis的作者认为数据库系统的瓶颈一般不在于网络流量，而是数据库自身内部逻辑处理上。所以即使Redis使用了浪费流量的文本协议，依然可以取得极高的访问性能。Redis将所有数据都放在内存，用一个单线程对外提供服务，单个节点在跑满一个CPU核心的情况下可以达到了10w/s的超高QPS。

RESP(RedisSerializationProtocol)

RESP是Redis序列化协议的简写。它是一种直观的文本协议，优势在于实现异常简单，解析性能极好。Redis协议将传输的结构数据分为5种最小单元类型，..]]></description><category></category></item><item><title><![CDATA[Redis线程IO模型的秘密知多少]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106535860</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106535860</guid><author>mango_love</author><pubDate>Wed, 03 Jun 2020 23:55:50 +0800</pubDate><description><![CDATA[​在前面事务里面讲过Redis是一个单线程应用程序，当然我们比较有代表性的单线程还有Node.js、Nginx等。

那么既然是单线程的为什么还这么快呢？

Redis的数据都在内存里面，所有的运算都是内存级别，处理数据是非常快速的，所以这里得注意一些复杂度为O(n)的指令，可能会导致服务器卡顿。

那么Redis是一个单线程是如何处理并发客户端的连接呢？

这就是接下来要讲的非阻塞IO、多路复用和事件轮询API。

非阻塞IO

那什么是阻塞IO模型？即在读写数据过程中会发生阻塞现象。

当用户线程发出I]]></description><category></category></item><item><title><![CDATA[Redis单线程模型事务的实现原理]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106485528</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106485528</guid><author>mango_love</author><pubDate>Tue, 02 Jun 2020 00:31:00 +0800</pubDate><description><![CDATA[在使用关系型数据库的时候，为了保证数据的ACID（Atomicity：原子性，Consistency：一致性，Isolation：隔离性，Durability：持久性）我们经常会使用事务，要么全部提交成功，要么失败全部失败，不会存在中间状态。那么我们Redis也会有事务，只不过它不能保证原子性，Redis已经在系统内部进行功能简化，这样可以确保更快的运行速度，因为Redis不需要事务回滚的能力。

redis为我们的事务提供了四个指令：multi（开启事务），discard（丢弃），exec（执行），wat]]></description><category></category></item><item><title><![CDATA[Redis分布式锁如何提高可用性]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106470018</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106470018</guid><author>mango_love</author><pubDate>Mon, 01 Jun 2020 12:22:45 +0800</pubDate><description><![CDATA[在编程中我们时常考虑高并发带来的数据访问不安全问题，那么我们在redis中是否也要考虑呢？答案是肯定的，有人会问：redis不是单线程的吗？对它是单线程，但是在某些情况他会出现信息更新，用户没有拿到最新数据，然后导致操作有误，看下图



我们可以看到张三和李四同时请求这个number，但是李四执行set后张三拿到的数据是没有更新的，而后执行了set命令，这样这个number应该是30才对。

Redis分布式锁简介

redis给我们提供了分布式锁，开启锁的指令是setnx（set if not exis]]></description><category></category></item><item><title><![CDATA[Redis高并发限流策略之漏斗限流算法]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106443098</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106443098</guid><author>mango_love</author><pubDate>Sat, 30 May 2020 16:24:33 +0800</pubDate><description><![CDATA[在双11活动当天凌晨，打折活动开始前多少名客户下单可以半折甚至是免单优惠，客户当然不会放过这个一年一次的机会，疯狂开始。这时候我们程序员小哥哥就苦了，稍一个不注意，服务器驾崩了，次日头条见。那么为了防止在当天凌晨压死服务器的并发，我们想到了一个很好的策略，一分钟搞不定的事情，我们可以两分钟搞定，至少保证我们的服务器不会瘫痪，就是说，假如我们的服务器并发量是1w左右，那么我们可以限制在9000的并发量，超过这个预警我们就严格限制请求访问量不能做越过这个警戒线，做到削峰或者说是平滑这个爆发点。

很快我们程序员]]></description><category></category></item><item><title><![CDATA[Redis如何实现刷抖音不重复-布隆过滤器（Bloom Filter）]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106416042</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106416042</guid><author>mango_love</author><pubDate>Thu, 28 May 2020 23:48:52 +0800</pubDate><description><![CDATA[刷抖音的时候是否曾想过，我们刷过的视频很难在重复刷到那么它到底是如何实现的呢？

如果说我们每刷一个视频并且把视频id和用户的id组合成一条数据保存到数据库中每次推荐视频的时候都去数据检测是否已经刷过了，嗯，这样可以实现这个功能，但是存在多个问题，频繁操作数据表对数据库造成很大的负担，每次推荐视频时都得保存数据，人流量一多，数据库很快就扛不住。

那么我们可否使用缓存redis中的set来实现呢？当然是可以的，redis4.0版本给我们提供了更加快捷更加节省空间的数据结构--布隆过滤器（Bloom Filt]]></description><category></category></item><item><title><![CDATA[Redis站点流量统计HyperLogLog]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106394667</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106394667</guid><author>mango_love</author><pubDate>Thu, 28 May 2020 00:43:48 +0800</pubDate><description><![CDATA[在我们做站点流量统计的时候一般会统计页面UV(独立访客:unique visitor)和PV(即页面浏览量：page view)，那么我们最常见的处理方式就是用户点击一次就插入一条数据到数据库，统计的时候通过查询表来达到统计流量的效果。

那么我们如果是通过redis来处理，我们可以使用string类型然后自增计数即可达到统计PV，统计UV可以使用set，每个用户id是唯一的可以放到这个集合里，统计的时候只需要执行scard获取集合大小即可。

这两种方式都是可以实现站点的流量统计，但是如果说当站点流量非常]]></description><category></category></item><item><title><![CDATA[Redis快速扫描Scan]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106367890</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106367890</guid><author>mango_love</author><pubDate>Tue, 26 May 2020 23:23:19 +0800</pubDate><description><![CDATA[在平时我们维护线上Redis的时候需要从n个key里面找到某些特定规则的key，可能查看某些key可能清理某些不需要的key，可能我们第一印象就是keys这个指令，我们可以使用这个指令匹配我们想要的key，下面我们来试试。

keys指令基本用法


&gt;msetname1aname2ana1meana2meaOK&gt; keys name*1) "name"2) "name2"3) "name1"&gt; keys na*me1) "name"2) "na1me"3)"na2me...]]></description><category></category></item><item><title><![CDATA[Redis之GeoHash]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106346073</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106346073</guid><author>mango_love</author><pubDate>Tue, 26 May 2020 00:29:11 +0800</pubDate><description><![CDATA[在生活中我们有时候需要点外卖、骑共享单车等等，我们打开软件找到附近餐厅、离我最近的单车，那么他们是怎么快速定位到的呢？我们把地图看作一个二维平面，我们在某个点上然后找到附近10km内的所有餐厅，这时候我们知道求两点直接的距离是需要一个公式，且需要知道两点的x，y轴坐标才能计算出距离，通过计算出距离然后进行排列，那么我们就能过找到离我最近的一个餐厅了。

那么这里我们考虑几个问题，我每次搜索的时候需要计算我离餐厅的距离，那么我们能不能把这个距离保存起来呢？如果我保存了，我下次在另一个地方那是不是还得重新计..]]></description><category></category></item><item><title><![CDATA[Redis位图]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106318320</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106318320</guid><author>mango_love</author><pubDate>Sun, 24 May 2020 17:52:58 +0800</pubDate><description><![CDATA[上课签到时间到了，张三老师开始点名了，每点一名同学就新增加一条记录，我们数据库会把这条记录写到学生考勤表里，到学期末考核的时候汇总根据学生迟到次数计算总学分。假设一个班级50个学生，一天4课时，一个星期就要记录1000条记录，那么如果说我们根据学生的学号顺序记录学生签到信息，通过“0”和“1”来表示，“1”就代表学生签到，“0”代表学生迟到，那么我们一个星期只要保存20条数据即可。

Redis也有这样的结构名叫位图，位图最小的单位是bit，每个bit是由0或1构成，我们的字符串就是由很多个bit数组组成的]]></description><category></category></item><item><title><![CDATA[十大经典排序算法(动态演示+代码)]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106295789</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106295789</guid><author>mango_love</author><pubDate>Sat, 23 May 2020 09:51:22 +0800</pubDate><description><![CDATA[时间复杂度是指程序执行函数或方法的效率常用大写的O表示，比如执行一个循环我们记做O(n)，执行一个加法运算或者执行一个if操作我们记为O(1)​。

​

时间、空间复杂度比较



1 冒泡排序

算法思想：


	比较相邻的元素。如果第一个比第二个大，就交换他们两个。
	
	
	对每一对相邻元素作同样的工作，从开始第一对到结尾的最后一对。这步做完后，最后的元素会是最大的数。
	
	
	针对所有的元素重复以上的步骤，除了最后一个。
	
	
	持续每次对越来越少的元素重复上面的步骤，直到没有任何一对数字需要]]></description><category></category></item><item><title><![CDATA[Redis-集合（Set）基础]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106289755</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106289755</guid><author>mango_love</author><pubDate>Fri, 22 May 2020 19:37:25 +0800</pubDate><description><![CDATA[Redis集合包括Set（无序集合）和ZSet（有序集合），这里的Set实现相当于Java中的HashSet，它内部实现了一个特殊的字典，字典中所有的value都是一个值NULL。下面我们来熟悉下set的常用的命令

Set


&gt;saddname hello(integer)1&gt;saddnamehello#重复，不能插入(integer)0&gt;saddnamei am ok(integer)3&gt;smembers name"hello""i""am""ok"&gt;s...]]></description><category></category></item><item><title><![CDATA[Redis-字典（hash）基础]]></title><link>https://blog.youkuaiyun.com/mango_love/article/details/106247815</link><guid>https://blog.youkuaiyun.com/mango_love/article/details/106247815</guid><author>mango_love</author><pubDate>Thu, 21 May 2020 00:33:32 +0800</pubDate><description><![CDATA[Redis的字典数据结构跟Java的HashMap一样，也是数组+链表结构，数组是hash的位置，hash碰撞的值保存到链表种。但是跟HashMap不同的是Redis字典存储的值都是字符串类型的，而HashMap存储的值是所有数据类型



常见操作


&gt;hset user name mango
(ingeter)1
&gt;hmset user age 18 gender "男"
 OK
&gt;hlen user
 (ingeter)3
 &gt;hget user name
 "mango"
]]></description><category></category></item></channel></rss>