diff --git a/Interview.md b/Interview.md
deleted file mode 100644
index cd3de2b..0000000
--- a/Interview.md
+++ /dev/null
@@ -1,72 +0,0 @@
-
Interview
-
-Introduction:收纳面试知识总结!
-
-[TOC]
-
-# JAVA
-
-**问题:JDK 和 JRE 有什么区别?**
-
-- JDK:Java Development Kit 的简称,Java 开发工具包,提供了 Java 的开发环境和运行环境
-- JRE:Java Runtime Environment 的简称,Java 运行环境,为 Java 的运行提供了所需环境
-
-具体来说 JDK 其实包含了 JRE,同时还包含了编译 Java 源码的编译器 Javac,还包含了很多 Java 程序调试和分析的工具。简单来说:如果你需要运行 Java 程序,只需安装 JRE 就可以了,如果你需要编写 Java 程序,需要安装 JDK。
-
-
-
-**问题:== 和 equals 的区别是什么?**
-
-`==` 对于`基本类型`来说是`值比较`,对于`引用类型`来说是`比较引用地址`。而 `equals` 默认情况下是`引用比较`(Object中`public boolean equals(Object obj) {return (this == obj);}`),只是很多类重新了 equals 方法,比如 `String`、`Integer` 等把它变成了值比较,所以一般情况下 `equals` 是`比较值是否相等`。
-
-
-
-**问题:两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?**
-
-不对,两个对象的 hashCode() 相同,equals() 不一定 true。
-
-
-
-**问题:String 属于基础的数据类型吗?**
-
-String不属于基础类型,基础类型有8种:byte、boolean、char、short、int、float、long、double,而String属于对象。
-
-
-
-**问题:String、StringBuffer、StringBuilder的区别?**
-
-String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的;但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
-
-
-
-**问题:String str="ABC"与 String str=new String("ABC")一样吗?**
-
-不一样,因为内存的分配方式不一样。String str="ABC"的方式Java 虚拟机会将其分配到常量池中;而 String str=new String("ABC") 则会被分到堆内存中。
-
-
-
-**问题:如何将字符串反转?**
-
-使用 `StringBuilder` 或者 `StringBuffer` 的 `reverse()` 方法。
-
-
-
-**问题:String 类的常用方法都有那些?**
-
-- indexOf():返回指定字符的索引
-- charAt():返回指定索引处的字符
-- replace():字符串替换
-- trim():去除字符串两端空白
-- split():分割字符串,返回一个分割后的字符串数组
-- getBytes():返回字符串的 byte 类型数组
-- length():返回字符串长度
-- toLowerCase():将字符串转成小写字母
-- toUpperCase():将字符串转成大写字符
-- substring():截取字符串
-- equals():字符串比较
-
-
-
-**问题:Java 中 IO 流分为几种?**
-
-按功能来分:输入流(input)、输出流(output)。按类型来分:字节流和字符流。字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。
diff --git a/JAVA.md b/JAVA.md
index 2d62ca8..a29dfb6 100644
--- a/JAVA.md
+++ b/JAVA.md
@@ -3888,7 +3888,7 @@ Error 类是指 java 运行时系统的内部错误和资源耗尽错误。应
-# JAVA Others
+# Others
## Annotation
diff --git a/JVM.md b/JVM.md
index 6a95697..264256b 100644
--- a/JVM.md
+++ b/JVM.md
@@ -2166,9 +2166,14 @@ java -Xmx4048m -Xms4048m -Xmn2024m -XX:SurvivorRatio=7 -Xss256k -XX:MetaspaceSi
### GC
-#### Serial垃圾收集器(新生代)开启
+#### Serial垃圾收集器(新生代)
+
+开启
+
+- -XX:+UseSerialGC
+
+关闭:
-- -XX:+UseSerialGC 关闭:
- -XX:-UseSerialGC //新生代使用Serial 老年代则使用SerialOld
diff --git a/Middleware.md b/Middleware.md
index 97ffeb2..c985913 100644
--- a/Middleware.md
+++ b/Middleware.md
@@ -95,6 +95,28 @@ org.springframework.boot.env.YamlPropertySourceLoader
# Redis
+**Java类型所占字节数(或bit数)**
+
+| 类型 | 存储(byte) | bit数(bit) | 取值范围 |
+| ------- | ---------- | ---------- | ------------------------------------------------------------ |
+| int | 4字节 | 4×8位 | 即 (-2)的31次方 ~ (2的31次方) - 1 |
+| short | 2字节 | 2×8位 | 即 (-2)的15次方 ~ (2的15次方) - 1 |
+| long | 8字节 | 8×8位 | 即 (-2)的63次方 ~ (2的63次方) - 1 |
+| byte | 1字节 | 1×8位 | 即 (-2)的7次方 ~ (2的7次方) - 1,-128~127 |
+| float | 4字节 | 4×8位 | float 类型的数值有一个后缀 F(例如:3.14F) |
+| double | 8字节 | 8×8位 | 没有后缀 F 的浮点数值(例如:3.14)默认为 double |
+| boolean | 1字节 | 1×8位 | true、false |
+| char | 2字节 | 2×8位 | Java中,只要是字符,不管是数字还是英文还是汉字,都占两个字节 |
+
+**注意**:
+
+- 英文的数字、字母或符号:1个字符 = 1个字节数
+- 中文的数字、字母或符号:1个字符 = 2个字节数
+- 计算机的基本单位:bit 。一个bit代表一个0或1,1个字节是8个bit
+- 1TB=1024GB,1GB=1024MB,1MB=1024KB,1KB=1024B(字节,byte),1B=8b(bit,位)
+
+
+
## 数据类型
在 Redis 中,常用的 5 种数据类型和应用场景如下:
@@ -121,7 +143,7 @@ String 数据结构是简单的 key-value 类型,value 不仅可以是 String
- 存储、读取、修改用户属性
-实战场景:
+**实战场景**
- 缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力
- 计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源
@@ -185,9 +207,9 @@ Set 就是一个集合,集合的概念就是一堆不重复值的组合。利
## 特殊数据结构
-### HyperLogLog
+### HyperLogLog(基数统计)
-hyperloglog可用极小空间完成独立数统计。命令如下:
+HyperLogLog 主要的应用场景就是进行基数统计。实际上不会存储每个元素的值,它使用的是概率算法,通过存储元素的hash值的第一个1的位置,来计算元素数量。HyperLogLog 可用极小空间完成独立数统计。命令如下:
| 命令 | 作用 |
| ----------------------------- | ----------------------- |
@@ -197,22 +219,64 @@ hyperloglog可用极小空间完成独立数统计。命令如下:
-### Geo
+**应用案例**
+
+如何统计 Google 主页面每天被多少个不同的账户访问过?
-geo是地理空间位置。redis支持将geo信息存储到有序集合中,再通过geohash算法进行填充。命令如下:
+对于 Google 这种访问量巨大的网页而言,其实统计出有十亿的访问量或十亿零十万的访问量其实是没有太多的区别的,因此,在这种业务场景下,为了节省成本,其实可以只计算出一个大概的值,而没有必要计算出精准的值。
-| 命令 | 作用 |
-| ------------------------------------ | ------------------------------------- |
-| geoadd key latitude longitude member | 添加成员位置(纬度、经度、名称)到key中 |
-| geopos key member ... | 获取成员geo坐标 |
-| geodist key member1 member2 | 计算成员位置间距离 |
-| georadius | 基于经纬度坐标范围查询 |
-| georadiusbymember | 基于成员位置范围查询 |
-| geohash | 计算经纬度hash |
+对于上面的场景,可以使用`HashMap`、`BitMap`和`HyperLogLog`来解决。对于这三种解决方案,这边做下对比:
+- `HashMap`:算法简单,统计精度高,对于少量数据建议使用,但是对于大量的数据会占用很大内存空间
+- `BitMap`:位图算法,具体内容可以参考我的这篇,统计精度高,虽然内存占用要比`HashMap`少,但是对于大量数据还是会占用较大内存
+- `HyperLogLog`:存在一定误差,占用内存少,稳定占用 12k 左右内存,可以统计 2^64 个元素,对于上面举例的应用场景,建议使用
-### Pub/Sub
+
+### Geo(地理空间信息)
+
+Geo主要用于存储地理位置信息,并对存储的信息进行操作(添加、获取、计算两位置之间距离、获取指定范围内位置集合、获取某地点指定范围内集合)。Redis支持将Geo信息存储到有序集合(zset)中,再通过Geohash算法进行填充。命令如下:
+
+| 命令 | 作用 |
+| ------------------------------------ | ------------------------------------------------------------ |
+| geoadd key latitude longitude member | 添加成员位置(纬度、经度、名称)到key中 |
+| geopos key member ... | 获取成员geo坐标 |
+| geodist key member1 member2 [unit] | 计算成员位置间距离。若两个位置之间的其中一个不存在, 那返回空值 |
+| georadius | 基于经纬度坐标范围查询 |
+| georadiusbymember | 基于成员位置范围查询 |
+| geohash | 计算经纬度hash |
+
+
+
+**GEORADIUS**
+
+```properties
+GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
+```
+
+以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。范围可以使用以下其中一个单位:
+
+- **m** 表示单位为米
+- **km** 表示单位为千米
+- **mi** 表示单位为英里
+- **ft** 表示单位为英尺
+
+在给定以下可选项时, 命令会返回额外的信息:
+
+- `WITHDIST`: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离单位和范围单位保持一致
+- `WITHCOORD`: 将位置元素的经度和维度也一并返回
+- `WITHHASH`: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
+
+命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:
+
+- `ASC`: 根据中心的位置, 按照从近到远的方式返回位置元素
+- `DESC`: 根据中心的位置, 按照从远到近的方式返回位置元素
+
+在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 **COUNT ``** 选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 `COUNT` 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 `COUNT` 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。
+
+
+
+### Pub/Sub(发布订阅)
发布订阅类似于广播功能。redis发布订阅包括 发布者、订阅者、Channel。常用命令如下:
@@ -227,9 +291,9 @@ geo是地理空间位置。redis支持将geo信息存储到有序集合中,再
-### bitmap
+### Bitmap(位图)
-bitmap是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND, OR, XOR以及其它位操作。常用命令如下:
+Bitmap就是位图,其实也就是字节数组(byte array),用一串连续的2进制数字(0或1)表示,每一位所在的位置为偏移(offset),位图就是用每一个二进制位来存放或者标记某个元素对应的值。通常是用来判断某个数据存不存在的,因为是用bit为单位来存储所以Bitmap本身会极大的节省储存空间。常用命令如下:
| 命令 | 作用 | 时间复杂度 |
| --------------------------- | --------------------------------------------------- | ---------- |
@@ -240,19 +304,132 @@ bitmap是一串连续的2进制数字(0或1),每一位所在的位置为
-### Redis Module
+**应用案例**
+
+有1亿用户,5千万登陆用户,那么统计每日用户的登录数。每一位标识一个用户ID,当某个用户访问我们的网站就在Bitmap中把标识此用户的位设置为1。使用set集合和Bitmap存储的对比:
+
+| 数据类型 | 每个 userid 占用空间 | 需要存储的用户量 | 全部占用内存量 |
+| -------- | ------------------------------------------------------------ | ---------------- | ---------------------------- |
+| set | 32位也就是4个字节(假设userid用的是整型,实际很多网站用的是长整型) | 50,000,000 | 32位 * 50,000,000 = 200 MB |
+| Bitmap | 1 位(bit) | 100,000,000 | 1 位 * 100,000,000 = 12.5 MB |
-#### BloomFilter
+**应用场景**
-#### RedisSearch
+- 用户在线状态
+- 用户签到状态
+- 统计独立用户
-#### Redis-ML
+### BloomFilter(布隆过滤)
+![Redis-BloomFilter](images/Middleware/Redis-BloomFilter.jpg)
+当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点(使用多个哈希函数对**元素key (bloom中不存value)** 进行哈希,算出一个整数索引值,然后对位数组长度进行取模运算得到一个位置,每个无偏哈希函数都会得到一个不同的位置),把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:
+
+- 如果这些点有任何一个为0,则被检元素一定不在
+- 如果都是1,并不能完全说明这个元素就一定存在其中,有可能这些位置为1是因为其他元素的存在,这就是布隆过滤器会出现误判的原因
+
+
+
+**应用场景**
+
+- **解决缓存穿透**:事先把存在的key都放到redis的**Bloom Filter** 中,他的用途就是存在性检测,如果 BloomFilter 中不存在,那么数据一定不存在;如果 BloomFilter 中存在,实际数据也有可能会不存
+- **黑名单校验**:假设黑名单的数量是数以亿计的,存放起来就是非常耗费存储空间的,布隆过滤器则是一个较好的解决方案。把所有黑名单都放在布隆过滤器中,再收到邮件时,判断邮件地址是否在布隆过滤器中即可
+- **Web拦截器**:用户第一次请求,将请求参数放入布隆过滤器中,当第二次请求时,先判断请求参数是否被布隆过滤器命中,从而提高缓存命中率
+
+
+
+#### 基于Bitmap数据结构
+
+```java
+import com.google.common.base.Preconditions;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class RedisService {
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ /**
+ * 根据给定的布隆过滤器添加值
+ */
+ public void addByBloomFilter(BloomFilterHelper bloomFilterHelper, String key, T value) {
+ Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
+ int[] offset = bloomFilterHelper.murmurHashOffset(value);
+ for (int i : offset) {
+ redisTemplate.opsForValue().setBit(key, i, true);
+ }
+ }
+
+ /**
+ * 根据给定的布隆过滤器判断值是否存在
+ */
+ public boolean includeByBloomFilter(BloomFilterHelper bloomFilterHelper, String key, T value) {
+ Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
+ int[] offset = bloomFilterHelper.murmurHashOffset(value);
+ for (int i : offset) {
+ if (!redisTemplate.opsForValue().getBit(key, i)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+```
+
+
+
+#### 基于RedisBloom模块
+
+RedisBloom模块提供了四种数据类型:
+
+- **Bloom Filter (布隆过滤器)**
+- **Cuckoo Filter(布谷鸟过滤器)**
+- **Count-Mins-Sketch**
+- **Top-K**
+
+`Bloom Filter` 和 `Cuckoo` 用于确定(以给定的确定性)集合中是否存在某项。使用 `Count-Min Sketch` 来估算子线性空间中的项目数,使用 `Top-K` 维护K个最频繁项目的列表。
+
+```shell
+# 1.git 下载
+[root@test ~]# git clone https://github.com/RedisBloom/RedisBloom.git
+[root@test ~]# cd redisbloom
+[root@test ~]# make
+
+# 2.wget 下载
+[root@test ~]# wget https://github.com/RedisBloom/RedisBloom/archive/v2.0.3.tar.gz
+[root@test ~]# tar -zxvf RedisBloom-2.0.3.tar.gz
+[root@test ~]# cd RedisBloom-2.0.3/
+[root@test ~]# make
+
+# 3.修改Redis Conf
+[root@test ~]#vim /etc/redis.conf
+# 在文件中添加下行
+loadmodule /root/RedisBloom-2.0.3/redisbloom.so
+
+# 4.启动Redis server
+[root@test ~]# /redis-server /etc/redis.conf
+# 或者启动服务时加载os文件
+[root@test ~]# /redis-server /etc/redis.conf --loadmodule /root/RedisBloom/redisbloom.so
+
+# 5.测试RedisBloom
+[root@test ~]# redis-cli
+127.0.0.1:6379> bf.add bloomFilter foo
+127.0.0.1:6379> bf.exists bloomFilter foo
+127.0.0.1:6379> cf.add cuckooFilter foo
+127.0.0.1:6379> cf.exists cuckooFilter foo
+```
diff --git a/OS.md b/OS.md
index 5839840..56e06cb 100644
--- a/OS.md
+++ b/OS.md
@@ -2400,3 +2400,4 @@ ulimit -s 1024000
### 线程
+
diff --git a/images/Middleware/BloomFilter-图解.png b/images/Middleware/BloomFilter-图解.png
new file mode 100644
index 0000000..3c1e8b1
Binary files /dev/null and b/images/Middleware/BloomFilter-图解.png differ
diff --git a/images/Middleware/Redis-BloomFilter.jpg b/images/Middleware/Redis-BloomFilter.jpg
new file mode 100644
index 0000000..cf396cd
Binary files /dev/null and b/images/Middleware/Redis-BloomFilter.jpg differ
diff --git a/images/Middleware/1289934-20190621232209365-1000366002.png b/images/Middleware/Redis-Hash.png
similarity index 100%
rename from images/Middleware/1289934-20190621232209365-1000366002.png
rename to images/Middleware/Redis-Hash.png
diff --git a/images/Middleware/1289934-20190621233618769-504231907.png b/images/Middleware/Redis-List.png
similarity index 100%
rename from images/Middleware/1289934-20190621233618769-504231907.png
rename to images/Middleware/Redis-List.png
diff --git a/images/Middleware/1289934-20190622001013515-677922001.png b/images/Middleware/Redis-Set.png
similarity index 100%
rename from images/Middleware/1289934-20190622001013515-677922001.png
rename to images/Middleware/Redis-Set.png
diff --git a/images/Middleware/1289934-20190622000959260-539243592.png b/images/Middleware/Redis-SortedSet.png
similarity index 100%
rename from images/Middleware/1289934-20190622000959260-539243592.png
rename to images/Middleware/Redis-SortedSet.png
diff --git a/images/Middleware/1289934-20190621163930814-1395015700.png b/images/Middleware/Redis-基本数据类型.png
similarity index 100%
rename from images/Middleware/1289934-20190621163930814-1395015700.png
rename to images/Middleware/Redis-基本数据类型.png