Fastjson 和 Spring 进行集成
在 Spring MVC 中集成 Fastjson如果你使用 Spring MVC 来构建 Web 应用并对性能有较高的要求的话,可以使用 Fastjson 提供的FastJsonHttpMessageConverter 来替换 Spring MVC 默认的 HttpMessageConverter 以提高 @RestController @ResponseBody @RequestBody 注解的 JSON序列化速度。下面是配置方式,非常简单。XML式如果是使用 XML 的方式配置 Spring MVC 的话,只需在 Spring MVC 的 XML 配置文件中加入下面配置即可。<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>通常默认配置已经可以满足大部分使用场景,如果你想对它进行自定义配置的话,你可以添加 FastJsonConfig Bean。<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="fastJsonConfig" ref="fastJsonConfig"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
<!-- 自定义配置... -->
</bean>编程式如果是使用编程的方式(通常是基于 Spring Boot 项目)配置 Spring MVC 的话只需继承 WebMvcConfigurerAdapter 覆写 configureMessageConverters 方法即可,就像下面这样。@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
//自定义配置...
//FastJsonConfig config = new FastJsonConfig();
//config.set ...
//converter.setFastJsonConfig(config);
converters.add(converter);
}
}在 Spring Data Redis 中集成 Fastjson编程式如果是使用编程的方式(通常是基于 Spring Boot 项目)配置 RedisTemplate 的话只需在你的配置类(被@Configuration注解修饰的类)中显式创建 RedisTemplate Bean,设置 Serializer 即可。@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
redisTemplate.setDefaultSerializer(fastJsonRedisSerializer);//设置默认的Serialize,包含 keySerializer & valueSerializer
//redisTemplate.setKeySerializer(fastJsonRedisSerializer);//单独设置keySerializer
//redisTemplate.setValueSerializer(fastJsonRedisSerializer);//单独设置valueSerializer
return redisTemplate;
}通常使用 GenericFastJsonRedisSerializer 即可满足大部分场景,如果你想定义特定类型专用的 RedisTemplate 可以使用 FastJsonRedisSerializer 来代替 GenericFastJsonRedisSerializer ,配置是类似的。参考阿里FastJson的使用_json_qq_30920821的博客-CSDN博客https://blog.csdn.net/qq_30920821/article/details/78417690
Redis --- redis事务和分布式事务锁
redis事务基本实现Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。> MULTI
OK
> SET USER "Guide哥"
QUEUED
> GET USER
QUEUED
> EXEC
1) OK
2) "Guide哥"使用 MULTI命令后可以输入多个命令。Redis 不会立即执行这些命令,而是将它们放到队列,当调用了EXEC命令将执行所有命令。过程如下:开始事务(MULTI)。命令入队(批量操作 Redis 的命令,先进先出(FIFO)的顺序执行)。执行事务(EXEC)。你也可以通过 DISCARD 命令取消一个事务,它会清空事务队列中保存的所有命令。> MULTI
OK
> SET USER "Guide哥"
QUEUED
> GET USER
QUEUED
> DISCARD
OKWATCH 命令用于监听指定的键,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的键被修改的话,整个事务都不会执行,直接返回失败。> WATCH USER
OK
> MULTI
> SET USER "Guide哥"
OK
> GET USER
Guide哥
> EXEC
ERR EXEC without MULTIRedis 官网相关介绍 https://redis.io/topics/transactions 如下:但是,Redis 的事务和我们平时理解的关系型数据库的事务不同。我们知道事务具有四大特性: 1. 原子性,2. 隔离性,3. 持久性,4. 一致性。原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;隔离性(Isolation): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。一致性(Consistency): 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;关于 redis 没有事务回滚?首先原子性的定义:事务中的命令要么全部被执行,要么全部都不执行。然后再看官方文档关键段:Redis commands can fail during a transaction, but still Redis will execute the rest of the transaction instead of rolling back
Redis 在事务失败时不进行回滚,而是继续执行余下的命令我根据Redis文档理解,认为事务过程中失败有两种可能:Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令中用在了错误类型的键上面,所以如果在生产环境中你使用的正常命令,那么在 Redis 事务中,是不会出现错误而导致回滚的。来自文档:Redis commands can fail only if called with a wrong syntax...事务执行一半,Redis宕机。如果 Redis 服务器因为某些原因被管理员杀死,或者遇上某种硬件故障,那么可能只有部分事务命令会被成功写入到磁盘中。如果 Redis 在重新启动时发现 AOF 文件出了这样的问题,那么它会退出,并汇报一个错误。使用redis-check-aof程序可以修复这一问题:它会移除 AOF 文件中不完整事务的信息,确保服务器可以顺利启动注意:若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。Redis 官网也解释了自己为啥不支持回滚。简单来说就是 Redis 开发者们觉得没必要支持回滚,这样更简单便捷并且性能更好(回滚还需要解决回滚事务覆盖的问题)。Redis 开发者觉得即使命令执行错误也应该在开发过程中就被发现而不是生产过程中。你可以将 Redis 中的事务就理解为 :Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。分布式事务锁基础知识:分布式:简单来说就是将业务进行拆分,部署到不同的机器来协调处理,保证高性能。比如用户在网上买东西,大致分为:订单系统、库存系统、支付系统、、、、这些系统共同来完成用户买东西这个业务操作。集群:同一个业务,通过部署多个实例来完成,保证应用的高可用。如果其中某个实例挂了,业务仍然可以正常进行,通常集群和分布式配合使用。来保证系统的高可用、高性能。分布式事务:按照传统的系统架构,下单、扣库存等等,都是在单机系统中, 这一系列的操作都是一个数据库中完成的,也就是说保证了事务的ACID特性。如果在分布式应用中就会涉及到跨应用、跨库。这样就涉及到了分布式事务,就要考虑怎么保证这一系列的操作要么都成功要么都失败。保证数据的一致性。分布式锁:因为资源有限,要通过互斥来保持一致性,比如下订单的数据库操作和支付的数据库操作就是一个保证互斥性, 不能同时去执行, 不然那就会出现一旦支付出现失败, 那么下订单也得重新下订单, 这就不合理了, 所以引入分布式事务锁。分布式事务锁:分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。简单来说就是好几个节点访问一个资源, 那我就是使用额外的锁机制互斥的只让其中一个能进行访问核心思想:在被保护的redis节点加一把锁, 让这把锁和被保护的redis节建立直接映射在访问这个redis之前都去看看这把锁在不在如果不存在锁,说明没有客户端使用,可以执行任务,执行完毕,解锁,删除锁 (并且要保证判断有无锁和加锁是原子操作)如果存在锁,则认为有其他客户端在使用,等待锁消失基本操作:Redis中可以使用SETNX命令实现分布式锁,SETNX——SET if Not exists(如果不存在,则设置)setnx key value如果需要解锁,使用 del key 命令就能释放锁分布式锁存在的问题,解决方案Q1:当一个客户端上锁之后服务宕机,由于锁是他上的只有他可以进行redis访问的,别人无法访问,所以导致锁无法被删除.A1:给锁设置一个过期时间,可以通过两种方法实现:通过命令 “setnx 键名 过期时间 “;或者通过设置锁的expire(失效)时间,让Redis去删除锁。Q2:当一个客户端设置了锁的失效时间, 但是这个客户端并没有宕机, 只是真的需要那么多时间来进行操作,也就是任务执行过长,超过过期时间。A2:实际是通过客户端的一个守护线程,大概时间快到的时间给线程续命。Q3:任务执行造成死循环,会造成无限续命A3:设置最大续命时间, 或者设置最大续命次数
MySQL --- SQL基础知识
内连接与左(右)外连接的区别内连接关键字:inner join on
语句:select * from a_table a inner join b_table b on a.a_id = b.b_id;
# 组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交集(阴影)部分。
左(外)连接关键字:left join on / left outer join on
语句:SELECT * FROM a_table a left join b_table b ON a.a_id = b.b_id;
# left join 是left outer join的简写,它的全称是左外连接,是外连接中的一种。 左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符合搜索条件的记录。右表记录不足的地方均为NULL。
右(外)连接关键字:right join on / right outer join on
语句:SELECT * FROM a_table a right outer join b_table b on a.a_id = b.b_id;
#right join是right outer join的简写,它的全称是右外连接,是外连接中的一种。与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为NULL。
# 注意:书写sql语句时连接join关键字的左右两边是将要连接的表,on后边跟着关联条件。总结:内连接:查询左右表都有的数据,不要左/右中NULL的那一部分左连接:即以左表为基准,到右表找匹配的数据,找不到匹配的用NULL补齐。左右连接可以相互转换:A left join B ---> B right join A 是同样的。 #A 站在 B的左边 ---> B 站在 A的右边具体见:https://blog.csdn.net/zjt980452483/article/details/82945663where、having、group by、order by、limit的区别和使用顺序where:通过在SELECT语句的WHERE子句中指定条件进行查询,WHERE子句必须紧跟在FROM子句之后。如:从员工表里查询员工id为h0001的员工的工资select 工资 from 工资表 where id='h0001';having:一般与group by组合来使用,表示在得到分类汇总记录的基础之上,进一步筛选记录。如:从部门表里查部门内员工薪水总和大于100000的部门的编号。select 部门编号,sum(薪水) from 部门表 group by 部门编号 having sum(薪水)>100000;ps:相同点:where和having都可以加条件区别:1.where在分组之前加条件,having在分组之后加条件. 2.where的效率要远远高于having. 分组本身消耗资源非常大.GROUP BY:当需要分组查询时需要使用GROUP BY子句,例如查询每个部门的工资和,这说明要使用部门来分组。select 部门编号,sum(薪水) from 部门表 group by 部门编号;ORDER BY:order by 用来指定数据的排序方式。有升序和降序两种。desc表示降序,asc为升序,默认为升序,asc可省略。ps:order by 要写在where之后,limit之前。select * from stu_info order by id asc;// 按照id升序排序,其中asc可省略。
select * from stu_info order by id desc; //按照id降序LIMITE:LIMIT用来限定查询结果的起始行,以及总行数。如:查询10行记录,起始行从3开始select * from emp limit 3,10;综合运用时的使用顺序:从employee表中查询salary列的值>0且prize字段值>0的记录,结果以id字段分组且降序排列,起始行从0开始,显示5行:select * from emploee where salary>0 group by id having prize>0 order by id desc limit 0, 5;结果:查询到的记录条数小于5行,所以只能显示查询到的总行数。总结顺序: where(条件) - group by(分组) - having(条件) - order by(排序) - limit(限定查询结果)增删改查命令#练习: 创建db4数据库,判断是否存在,并制定字符集为gbk
create database if not exists db4 character set gbk
#查询所有数据库的名称:
show databases;
#修改数据库的字符集
alter database 数据库名称 character set 字符集名称;
#判断数据库存在,存在再删除
drop database if exists 数据库名称;
#查询当前正在使用的数据库名称
select database();
#使用数据库
use 数据库名称;
#复制表,注意位置
create table 表名 like 被复制的表名;
#查询表结构
desc 表名;
#删除表中指定列
alter table 表名 drop 列名;
#操作表,列名 + 数据类型,最后一行没有逗号
create table student(
id int,
name varchar(32),
age int ,
score double(4,1),
birthday date,
insert_time timestamp
);mysql常见函数与数据类型常用函数:字符函数 (自动进行数字和字符串的转化)数值计算函数比较运算符函数日期时间函数具体见:https://www.cnblogs.com/duhuo/p/5650876.html数据类型:MySQL中定义数据字段的类型对你数据库的优化是非常重要的。MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。count(1),count(*),count(列)区别是啥?主要是当数据量达到一定级别,考察基本调优思路。在Mysql中的不同的存储引擎对count函数有不同的实现方式。MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count()的时候会直接返回这个数,效率很高(没有where查询条件,如果有 where 条件,那么即使是 MyISAM 也必须累积计数的。InnoDB引擎并没有直接将总数存在磁盘上,在执行count()函数的时候需要一行一行的将数据读出,然来后累计总数。注:下面的讨论和结论是基于 InnoDB 引擎的。count 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回累计值。所以,count( * )、count(1)和count(主键 id) 都表示返回满足条件的结果集的总行数;而 count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。count(可空字段):扫描全表,读到server层,判断字段可空,拿出该字段所有值,判断每一个值是否为空,不为空则累加(ps:字段非主键的情况最好不要出现,因为不走索引)count(非空字段)与count(主键 id):扫描全表,读到server层,判断字段不可空,按行累加。count(1):扫描全表,但不取值,server层收到的每一行都是1,判断不可能是null,按值累加。注意:count(1)执行速度比count(主键 id)快的原因:从引擎返回 id 会涉及到解析数据行,以及拷贝字段值的操作,ps:两者都只扫描主键。count( * ):MySQL 执行count( * )在优化器做了专门优化。因为count( * )返回的行一定不是空。扫描全表,但是不取值,按行累加。ps:InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。因此,普通索引树比主键索引树小很多。对于 count ( * ) 来说,遍历哪个索引树得到的结果逻辑上都是一样的。MySQL 优化器会找到最小的那棵树来遍历。在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。性能对比:count(可空字段) < count(非空字段) = count(主键 id) < (count(1) ≈ count(*),都扫描全表,不取值,按行累加)至于分析性能差别的时候,记住这么几个原则:server 层要什么就给什么;InnoDB 只给必要的值;现在的优化器只优化了 count(*) 的语义为“取行数”,其他“显而易见”的优化并没有做。ps:Redis 存储计数会出现的问题,把计数值也放在 MySQL 中,利用事务的原子性和隔离性,就可以解决一致性的问题。数据量不大,我们尽量用 count ( * ) 实现计数;数据量很大的情况考虑新建 MySQL 表存储计数,用事务的原子性和隔离性解决。mysql常用命令Structured Query Language:结构化查询语言。其实就是定义了操作所有关系型数据库的规则。每一种数据库操作的方式存在不一样的地方,称为“方言”。通用写法:SQL 语句可以单行或多行书写,以分号结尾。可使用空格和缩进来增强语句的可读性。MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写。111什么是sql注入,如何防止sql注入?所谓SQL注入,黑客对数据库进行攻击的常用手段之一。一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,注入者可以在表单中输入一段数据库查询代码并提交,程序将提交的信息拼凑生成一个完整sql语句,服务器被欺骗而执行该条恶意的SQL命令。注入者根据程序返回的结果,成功获取一些敏感数据,甚至控制整个服务器,这就是SQL注入。SQL注入攻击的总体思路:(1)寻找到SQL注入的位置(2)判断服务器类型和后台数据库类型(3)针对不同的服务器和数据库特点进行SQL注入攻击如何防御SQL注入?加强用户输入内容的验证严格区分权限(普通用户和管理用户)使用参数化语句(?代表此处为一个参数,需要后期通过set设置)使用专业软件对SQL漏洞进行扫描数据库设计的三个范式?第一范式(1NF):强调的是列的原子性(属性不可分割,即每个字段都不可能拆分),即列不能够再分成其他几列,比如字段name,中国名符合,外国名不符合。第二范式(2NF):一是表必须有一个主键;二是其他字段必须完全依赖于主键,理解为主键约束就好了,而不能只依赖于主键的一部分,比如学生表中的学号,其他字段都可以通过学号获取信息。第三范式(3NF):每一列数据都和主键直接相关,而不能间接相关。表中不能有其他表中存在的、存储相同信息的字段,通常实现是在通过外键去建立关联,因此第三范式只要记住外键约束就好了。比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。
数据结构与算法必知--- Bitmap位图与布隆过滤器
写在前bitmap和布隆过滤器主要解决大数据去重的问题。用于对大量整型数据做去重和查询。其实如果并非如此大量的数据,有很多排重方案可以使用,典型的就是哈希表。实际上,哈希表为每一个可能出现的数字提供了一个一一映射的关系,每个元素都相当于有了自己的独享的一份空间,这个映射由散列函数来提供(这里我们先不考虑碰撞)。实际上哈希表甚至还能记录每个元素出现的次数,这样的数据结构完成这个任务有点“大材小用”了。如果用HashSet或HashMap存储,每一个用户ID都要存成int,占4字节即32bit。而一个用户在Bitmap中只占一个bit,内存节省了32倍!所以散列表最大的问题是所占用的空间非常大!!!Bitmap位图算法为什么用位图?我们先来看一个问题,假设我们有1千万个(不重复、未排序)的整数需要存储,每个整数的大小范围是1到1亿。然后,给定任意一个整数X,我们需要快速判断X是否在刚才的1千万个整数内。这个问题该如何处理呢?常规的做法肯定就是先考虑如何存储这1千万个整数,在Java中,int类型是4个字节,可以表示的范围区间是-2147483648~2147483647,所以每个整数都用int来表示是可行的。那么1千万个整数需要占用多少内存空间呢?两者相乘就是了,应该是4000万字节,也就是40MB。而且如果我们存放的整数是是一亿个(甚至更大),每个整数大小范围是1到100亿怎么办?占用的内存空间将会是非常巨大的,是普通的计算机或者手机不能接受的(放不下)。ps:多台机器存储的话,资源占用量太大;另外可以不用内存,但是I/O效率低;所以我们需要使用位图这种数据结构来大大节省内存的使用量。什么是位图?我们知道Byte表示字节,一个字节等于8bit,这里的bit就和位图有关系。在上面的例子中,我们不是要存放1千万个整数嘛,那就申请一个具有1千万个bit的数组,用每个bit(二进制位)来表示一个整数,当前bit为0表示不存在这个整数,为1表示该整数就存在。虽然数量是1千万个,但是每个数的范围是1到1亿,所以我们需要1亿个bit,换算下来,就是12.5MB,和刚才的40MB相比,节省的不是一点点。位图是指内存中连续的二进制位,用于对大量的整型数据做去重和查询。Bit-map就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。对于位图的底层存储结构实际为数组结构,目的是为了存储大量的数据,为了表示存储的数据是否存在,可以使用0/1代表true/false。存储的数据流程为根据自定义的hash计算公式得到对应的数组下标并将数据进行相应的位运算得到的结果存储到数组中;当需要查询数据时将当前要查询的数据转换为对应的数组索引根据索引定位数组中的数据并执行存储时位运算的相反操作判断数据是否存在可以看出位图基于数组下标查询效率非常高效,且相对而言,位运算使用cpu计算也比较高效;由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。位图也存在一些缺点,对于随着数据量的增加,要申请数组的空间也越来越大。bitmap应用1)可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下。2)去重数据而达到压缩数据比如 Java 中的 BitSet 类就是一个位图,Redis 也提供了 BitMap 位图类布隆过滤器为什么用布隆过滤器?位图存在两个问题处理数字很方便,但是处理字符就稍微有点困难了(关键)位图在数据量过大情况下导致了内存浪费布隆过滤器为了解决内存占用的问题,由于位图实际是利用一个index来定位一个数据,如果在数据密集度相对稀疏的情况下,会导致数组空间浪费(存在大量空洞插槽); 布隆过滤器利用多个插槽位置来定义一个元素,尽最大的可能性来提高空间利用率; 对于一个数据对应多个插槽,实际就是利用多个hash函数生成多个索引位置。什么是布隆过滤器?布隆过滤器实际是基于位图来实现的一种数据存储结构,用来判断某个元素(key)是否在某个集合中。和一般的位图不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。布隆过滤器最大的特点,就是对一个对象使用多个哈希函数。如果我们使用了 k 个哈希函数,就会得到 k 个哈希值,也就是 k 个下标,我们会把数组中对应下标位置的值都置为 1。布隆过滤器和位图最大的区别就在于,我们不再使用一位来表示一个对象,而是使用 k 位来表示一个对象。这样两个对象的 k 位都相同的概率就会大大降低,不仅能够解决单哈希容易造成冲突的问题,还能有效减少内存空间的使用。但要注意的是,布隆过滤器 主要是为了解决空间浪费问题,并不能完全解决hash冲突;由于hash冲突的存在会导致一些误判的发生(无中生有),虽然使用多个hash函数可以降低冲突的概率,但还是会存在一些极端的情况出现hash冲突,导致不存在的数据被布隆过滤器判定为存在;但是对于布隆过滤器判定为不存在的数据,是肯定不存在的。虽然布隆过滤器对于空间利用率较高,但随着数组剩余空间越来越小,会导致hash冲突的概率越来越大,因此需要设置一个阈值,当剩余空间达到一定阈值后,就需要执行扩容,降低hash冲突概率。优缺点:优点:不需要存储key,节省空间缺点:算法判断key在集合中时,有一定的概率key其实不在集合中,已经映射的数据无法删除应用场景redis 缓存穿透 就可以利用 布隆过滤器来降低缓存穿透发生概率;redis 缓存穿透的理解 , 对于 redis中和数据库中都不存在的数据,当从redis中获取不到数据时,请求就会请求到服务端执行db查询操作(绕过缓存),当存在大量缓存穿透的情况就会导致redis和服务以及数据库的压力剧增;当redis 使用 布隆过滤器后,首先能通过布隆过滤器的判定,对于不存在的数据,redis和db中肯定都不存在;但对于布隆过滤器判断为存在的数据,即使经过redis查询发生数据不存在,从而查找db也发现数据不存在 的情况, 但对于这种情况毕竟几率较低,即使出现了对整个redis以及服务的压力也不会非常大其他:比如网络爬虫抓取时url去重,邮件提供商反垃圾黑名单Email地址去重,之所以需要k个比特位是因为我们大多数情况下处理的是字符串,那么不同的字符串就有可能映射到同一个位置,产生冲突(尽可能的降低hash冲突)。总结BitMap:把数值转化为数组的下标,下标对应的值只存放一个bit 0或1 ,0不存在 1存在。判断时 根据数值当做下标找到对应的 bit 值,1存在,0不存在BloomFilter:把内容通过多个hash算法,转换成多个数组下标,下标对应的值只存放一个bit 0或1 ,0不存在 1存在。判断过滤时 多个下标对应的值都为1,则可能存在,只要有一个值为0,则一定不存在
如何顺利通过计算机专业毕业答辩
临近毕业,很多同学项目和论文都准备的差不多了,只剩下最后一个环节,那就是决定你能否顺利毕业的毕业答辩。最后很多小伙伴咨询关于答辩的问题,也了解到了大家比较焦虑的心理,毕竟对我们来讲,努力了四年或者三年,最主要的目的还是为了这一纸毕业证,它将是我们走向社会,通向成功的第一把钥匙,今天就来给大家聊聊毕业答辩的一些问题。??????其实如果你前期的准备工作充分,比如你的毕业设计项目自己很熟悉,你的毕业设计论文自己很清楚,那么毕业答辩是水到渠成的事儿,但是我们发现很多同学在得到项目和论文后,几乎是没怎么看过,估计是比较忙吧,或许也可能是胸有成竹,不管怎样,你今天看到了这篇文章,让我们指南针的包哥来给大家聊聊毕业答辩的那些事儿,希望对大家所有帮助。? ? ? 毕业设计答辩的过程对每个人来讲都不会太长,相信你的导师,一般每个人不会超过20分钟,有例外者暂且不表,大部分10分钟左右。所以一般情况下你按10分钟左右去准备怎么比较清楚的阐述你的项目以及导师有可能问到的问题即可。????? 一,如何准备呢?????? 1、项目准备:包哥觉得首先你要对你的项目有一个差不多的了解,怎么着也得自己把程序跑两遍过一下核心功能吧?你总得能说清楚你的系统出于什么的目的,为什么样的客户服务,完成什么样的功能吧?如果不清楚,看看论文,上面一般会有描述。????? 2、论文观看:这个论文其实一般的格式就是将你项目开发的背景、目的、需求、设计、实现、测试、总结几大块全写上了,所以你认真看一遍论文,也会让你对整个软件系统的整体或局部都有一个相对清晰的认知。????? 3、技术查看:这个可能对大部分XDJM来说是最难的,看不懂,束手无措…..能看懂,自梳理清楚当然是最好了,如果实在是基础差,搞不明白,我觉得你可以先查一下看系统用到的相关技术是做什么用的,比如论文可能会有你项目所涉及技术的描述,Springboot框架,SSM框架,Shiro 框架等等,可能还有前端的什么EasyUI,Bootstrap,Vue,Layui等等,还有我们新爱的MYSQL数据库,先有个大概的了解。答辩不是面试,所以一般不会问你具体的技术,但一般会考察你系统的实现。???? 4、核心模块:这是我们准备的重点,你必须要将项目中的二三个你认为是亮点的地方,或者值得一提的地方能说个大概。比如可能你项目中大部分都有这个登陆功能,但它是不是核心功能呢?我觉得值得商榷,因为它基本是每个系统都有的,能有什么亮点?但你说这么一个普通的功能,如果老师问了,你答不上来,尴尬不?所以我觉得你可以看一看,通过个登陆把整个系统的交互流程搞明白了。然后就是准备核心业务模块和系统的核心技术应用。对大部分系统来讲,其实大多的功能还是基本的增删改查,这个你熟悉一个模块即可。但像其它的,比如系统中所拥有的图形报表功能、数据导入导出功能,这些是不是值得一说?我觉得是可以的。当然这要看每个系统的具体情况,比如你的是基于XXX的推荐系统,那就主要准备介绍一下你这个推荐的算法,业务流程的实现;比如你的是基于XXX的大数据分析,那你可能就主要放在你这个大数据是如何分析的业务模块和流程上了。???? 5、答辩PPT:这是一个最终的总结性步骤,你前面的所有的努力,其实都可以汇总到这个PPT上,它是你展示项目和进行答辩的一个思路凝聚,也是你答辩时因为不熟练而忘记时给你救场的救星。一般来讲,一个答辩PPT的制作无法这么几个环节,项目介绍,技术说明,功能实现,主要亮点,项目展示,最后总结。你准备的越充分,胜率也就越大,但是你的导师不可能让你把整个论文都粘贴上去的,所以它就是一个答辩的思路的梳理,你可以把核心的一些东西放上去给自己做提醒。二、如何答辩?? 1、首先人是感情动物,导师会对你有平时的印像分和现场感受分,它是一个综合体,这时候一方面是考验你平时和导师的互动关系,一方面是考验你多年积赞的实力。所以在答辩时我觉得最重要的是要学会控制自己的情绪,言谈举卡给导师和答辩组一个良好的印像,千万不要逞一时之勇,和答辩组老师刚起来了----流泪。? ?2、答辩不是要拿满分,及格就行。所以在答辩时如果有答不上来的,千万不要有心理压力,你想,如果你都答上来了,老师多没面子?哈哈,所以放松。但放松不等于放弃,如果碰到一个自己答不上来的,可以引导老师提问你比较熟悉的功能或知识。比如老师问你在项目中使用到的MVC设计模式,是如果实现的,让你讲讲他的流程,如果你此时答不上来,可以说我在使用MVC的时候也同时使用了三层架构,我来介绍一下三层架构吧。我觉得也是可以的。?? 3、答辩时主要求稳。当然,如果你很优秀,那其实不需要包哥挂念。稳的意思是最好按你前期准备的PPT来按部就班的去介绍和讲解,不要突然心血来潮,去讲解或演示前期没有准备的一些知识点和功能。从小概率事件来讲,如果这样做,几乎都会出问题,从而造成自己的信心一落千仗,对后面的答辩不利。?? 4、最后的总结很重要。可能前面答辩进行的有点糟糕,但最后的总结如果你能好好总结原因,真诚的打动答辩组,让他们觉得你是一个可造之才,还是有挽回的余地的。真的,相信我,有用的。三、常见答辩点1、请说明一下你项目中所说的C/S和B/S架构有什么区别呢?2、请说明一下你项目设计的整体架构什么结构的?3、你系统中用到了什么算法,请说一下?4、你系统中用到的R edis数据库主要是在哪个地方用的,为什么要用它?5、你的系统的安全性是如何保障的?6、你在开发时遇到什么技术难题,是如何解决的?7、请您介绍一下XX模块的基本业务流程,讲解一下相关代码。8、你说说你项目是如何实现前后端分离开发的。9、你的小程序端开发和运行需要什么样的条件?10、你这个商城中的购物车功能是如何进行实现的?11、你这个系统中有没有用到什么设计模式?请说明一下。12、你的这个图形统计报表是如何进行实现的?13、你介绍一下你项目中所用到的各个表以及他们之间的业务关联。14、你能否介绍一下你用的这个SSM框架中三个框架各自的职责是什么?15、你觉得你的这个系统有什么比较新颖的地方?技术或功能点都可以。四,总结? ? ?对于毕业答辩来讲,七分准备,三分讲解,还是要做足准备,其实并不复杂。主要基于项目本身和论文即可参系统有一个熟悉的过程。再掌握一些常见答辩问题,相信各位老铁能都顺利通过答辩。
Laravel 7发行说明( 二)
路由模型绑定优化路由模型绑定优化由 Taylor Otwell 开发贡献 。自定义键名有时你可能希望使用 id 以外的字段来解析 Eloquent 模型。 为此, Laravel 7 允许你在路由参数中指定某个字段:Route::get('api/posts/{post:slug}', function (App\Post $post) {
return $post;
});隐式绑定约束有时,当在路由中隐式绑定多个 Eloquent 模型时,可能希望对第二个 Eloquent 模型进行约束,使其必须是第一个 Eloquent 模型的子类。例如,考虑这种情况,该情况是通过 Slug 为特定用户查找博客文章的:use App\Post;
use App\User;
Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});当使用自定义键隐式绑定作为嵌套的路由参数时,Laravel 7 将自动确定查询范围,以使用约定猜测其父级上的关系名称,以其父级检索嵌套模型。在这种情况下,将假定 User 模型关联了名为 posts(路由参数名称的复数) 的关系,该关系可用于检索 Post 模型。有关路由模型绑定的更多信息,请查阅路由文档。多邮件驱动程序多邮件驱动程序支持由 Taylor Otwell 贡献。Laravel 7 允许为单个应用配置多个邮件驱动。在 mail 配置文件中的每个邮件驱动都拥有它们自己的配置以及自己独特的 「transport」,这允许你的应用使用不同的邮件服务来发送某些邮件。例如,你的应用可以使用 Postmark 发送批量邮件,使用 Amazon SES 发送公务邮件。默认情况下,Laravel 将使用 mail 配置文件中的 default 选项指定的邮件驱动作为邮件驱动。然而,你可以通过 mailer 方法来使用特定的邮件驱动来发送邮件。Mail::mailer('postmark')
->to($request->user())
->send(new OrderShipped($order));路由缓存速度改进路由缓存速度改进由上游的 Symfony 的贡献者和 Dries Vints 贡献Laravel 7 提供了一种新的方法,用于匹配使用 Artisan 命令 route:cache 缓存的已编译缓存路由。在大型应用程序(例如,具有800条或更多路由的应用程序)上,这些改进可以使简单的「Hello World」基准测试每秒的请求速度 提高2倍 ,而无需更改应用程序。CORS 支持CORS 支持由 Barry vd. Heuvel 贡献Laravel 7 通过集成由 Barry vd. Heuvel 编写的受欢迎的 Laravel CORS 软件包,为配置跨域资源共享(CORS) OPTIONS 请求响应提供了官方支持, 默认的 Laravel 应用程序框架 中包含一个新的 cors 配置。有关 Laravel 7.x 中的 CORS 支持的更多信息,请查阅CORS文档。查询时类型转换查询时类型转换由 Matt Barlow 开发贡献.有时候需要在查询执行过程中对特定属性进行类型转换,例如需要从数据库表中获取数据的时候。举个例子,请参考以下查询:use App\Post;
use App\User;
$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->get();在该查询获取到的结果集中,last_posted_at 属性将会是一个字符串。假如我们在执行查询时进行 date 类型转换将更方便。你可以通过使用 withCasts 方法来完成上述操作:$users = User::select([
'users.*',
'last_posted_at' => Post::selectRaw('MAX(created_at)')
->whereColumn('user_id', 'users.id')
])->withCasts([
'last_posted_at' => 'date'
])->get();MySQL 8+ 数据库队列改进MySQL 数据库队列改进由 Mohamed Said 开发贡献.在先前版本的 Laravel 中, database 队列的健壮性被认为无法满足生产环境的需求。但是,Laravel 7 针对使用基于 MySQL 8+ 数据库队列的应用进行了改进。通过使用 FOR UPDATE SKIP LOCKED 语句进行 SQL 的优化,database 队列驱动可以安全地用于生产环境。Artisan test 命令test 命令由 Nuno Maduro 贡献除了 phpunit命令之外,现在可以使用 test Artisan 命令来运行测试。 Artisan 测试运行器提供了漂亮的控制台,以及有关当前正在运行的测试的更多信息。 此外,运行器将在第一次测试失败时自动停止:php artisan test可以传递给 phpunit 命令的任何参数也可以传递给 Artisan test 命令:php artisan test --group=featureMarkdown 邮件模板改进Markdown 邮件模板改进由 Taylor Otwell 贡献默认的Markdown邮件模板已基于Tailwind CSS调色板做出全新、更现代的设计。 当然,可以根据您的应用程序的需求来发布和定制此模板:有关 Markdown 邮件的更多信息,请查看邮件发送.自定义桩代码自定义桩代码由 Taylor Otwell贡献Artisan 控制台的 make 命令用于创建各种类,例如控制器,任务,迁移和测试。 这些类是根据输入填充值使用「桩代码」生成文件的。 但是,有时可能希望对 Artisan 生成的文件进行小的更改。 为此,Laravel 7提供了 stub:publish 命令来发布最常见的自定义桩代码:php artisan stub:publish发布的桩代码将位于应用程序根目录中的 stubs 目录中。 当使用 Artisan 的 make 命令生成它们的相应类时,对这些桩代码所做的任何更改都会反映出来。队列maxExceptions配置maxExceptions属性由Mohamed Said提交贡献.有时可能希望指定可以尝试多次的任务,但是如果重试是由给定数量的异常触发的,则该任务将失败。在Laravel7中,可以在任务类上定义 maxExceptions 属性:<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* 任务可以被重试的次数。
*
* @var int
*/
public $tries = 25;
/**
* 失败之前允许抛出异常的最大次数。
*
* @var int
*/
public $maxExceptions = 3;
/**
* 执行任务。
*
* @return void
*/
public function handle()
{
Redis::throttle('key')->allow(10)->every(60)->then(function () {
// 获取锁,处理博客进程...
}, function () {
// 无法获取锁...
return $this->release(10);
});
}
}在此示例中,如果应用程序无法获得 Redis 锁,则该任务将释放十秒钟,并将继续重试 25 次。但是,如果任务抛出三个未处理的异常,则该任务将失败。
Redis哨兵原理,我忍你很久了!(4)
选出新的主节点后就要对所有的节点发送指令了。四、总结关于哨兵的所有知识点就已经说完了,本文最重要的就是哨兵的工作原理了。我们在简单的梳理一下其工作原理。首先进行监控,并且所有的哨兵同步信息哨兵向订阅里边发布信息故障转移哨兵发现主节点下线哨兵开启投票竞选负责人由负责人推选新的主节点新的主节点断开原主节点,并且其他的从节点连接新的主节点,原主节点上线后作为从节点连接。以上就是咔咔对哨兵的理解,如果错误可以提出,咔咔及时改正。
Redis哨兵原理,我忍你很久了!(3)
三、哨兵工作原理配置完哨兵后,就需要对其工作原理进行解析了,只有知道其工作流程,才能对哨兵有更好的理解。本文讲解原理没有那么干巴!让你可以把一篇技术文章当故事去看。进入正题,哨兵作用是监控、通知、故障转移。那么工作原理也是围绕这三点来讲的。1. 监控工作流程哨兵发送info指令,并且保存所有哨兵状态,主节点和从节点的信息主节点会记录redis实例的信息,主节点记录的信息跟哨兵记录的信息看起来是一样的,实际上还是有点区别哈。哨兵会根据在主节点拿到的从节点信息,给对应的从节点也发送info指令接着哨兵2来了,同样的也会改主节点发送info指令,并且建立cmd连接这个时候哨兵2也会保存跟哨兵1一样的信息,只不过是保存的哨兵信息是2个。这个时候为了每个哨兵的信息都一致它们之间建立了一个发布订阅。为了哨兵之间的信息长期对称它们之间也会互发ping命令。当再来一个哨兵3时,也会做同样的事情,给主节点和从节点发送info。并且跟哨兵1和哨兵2建立连接。2. 通知工作流程Sentinel会给主从的所有节点发送命令获取其状态,并且会把信息发布到哨兵的订阅里。3. 故障转移原理(本文重点)哨兵会一直给主节点发送publish sentinel :hello,直到哨兵报出sdown,这个词这会是有不是有点熟悉了。没错就是我们上文中把主节点断开后哨兵服务端报出的信息。哨兵报出主节点sdown后还没有完,哨兵还会往内网里发布消息说明这个主节点挂了。发送的指令是sentinel is-master-down-by-address-port其余的哨兵接收到指令后,主节点挂了吗?让我去看看到底挂没挂。发送的信息也是hello。其余的哨兵也会发送他们收到的信息并且发送指令sentinel is-master-down-by-address-port到自己的内网,确认一下第一个发送sentinel is-master-down-by-address-port的哨兵说你说的对,这个家伙确实挂了。当所有人都认为主节点挂了后就会修改其状态为odown。当一个哨兵认为主节点挂了标记的是sdown,当半数哨兵都认为挂了其标记的状态是odown。这也就是配置哨兵为什么配置单数的原因。对于一个哨兵认为主节点挂了称之为主观下线,半数哨兵认为主节点挂了称之为客官下线。一旦被认为主节点客官下线后,哨兵就会进行下一步操作这时哨兵已经检测到问题所在了,那么到底是那个哨兵去负责推选新的主节点呢!不能是张三也去,李四也去,王五也去,这样就乱套了、于是就需要在所有的哨兵里选出领头的,那么是如何选的呢!请看下图。这个时候呢!五个sentinel就在一起开会了,所有的哨兵都在一个内网中,然后他们会做一件事情就是五个sentinel会同时发送指令sentinel is-master-down-by-address-port并且携带上自己竞选次数和runid。每个sentinel既是参选者也是投票者,每个sentinel都有一票,信封就代表自己的投票权。当sentinel1和sentinel4同时把指令发送到群里准备竞选时,sentinel2这个时候就说我先接到谁的指令就把票投给谁。假如sentinel1发的早,那么sentinel2的票就会投给sentinel1。按照这样的规则一直发起投票直到有一个sentinel的票数为总sentinel数量的一半之多。假设说是sentinel1的票数满足总哨兵数量的一半之多后,sentinel1就会当选。这个时候就进行到了下一个阶段。在上边哨兵已经选出了sentinel1为代表去所有的从节点找出一个作为主节点。这个挑选主节点不是随便拿一个是有一定的规则的。先把不在线的干掉响应慢的干掉,sentinel会给所有的redis发送信息,响应速度慢的就会被干掉与原主节点断开时间最久的干掉,这里由于演示不够用了,所有新增了一个slave5,没有任何意义哈!以上三个点都判断结束后还有salve4和slave5,就会根据优先原则来进行筛选。首先会根据优先级,如果优先级一样在进行其他判断判断offset偏移量,判断数据同步性,假如说slave4的offset为90 slave5偏移量为100 那么哨兵就会认为slave4的网络是不是有问题啊!于是就会选slave5为新的主节点。那如果说是slave4和slave5的offset相同呢!还有最后一个判断最后一步就是判断runid了,也就是职场中的论资排辈了,也就说根据runid的创建时间来判断,时间早的上位。选出新的主节点后就要对所有的节点发送指令了。
Redis哨兵原理,我忍你很久了!(2)
启动一个哨兵redis-sentinel 26379-sentinel.conf连接26379哨兵,主要是最后一行,监控的主节点名为mymaster,状态正常,从节点有俩个,哨兵数量为1个在来查看一下26379的哨兵配置信息,这个时候已经改动了在启动一个26380的哨兵,redis-sentinel 26380-sentinel.conf,这里注意一下最后一行多了一条信息,这个id就是我们26379配置文件新增的id然后我们来到哨兵26379的客户端,同样也是新增的26380哨兵的id这个时候我们在查看一下26379哨兵的配置文件,第一次查看配置文件是没有配置26380哨兵的,第二次查看时配置了26380哨兵后添加的信息。最后我们需要把哨兵客户端3启动起来,端口号为26381。启动起来之后,我们的配置信息和服务端的信息也会改动,添加哨兵26380有的信息,哨兵26381也会有。直到这里我们对哨兵的配置就结束了,接下来我们把主节点master给宕掉等待30秒后我们来到26379哨兵的客户端,这里新增了一些信息,那么这些信息都做了什么呢!让我们细细道来。这里边的信息我们先需要知道几个+sdown :这个信息后是指三个哨兵里边有一个认为主节点宕机了+odown:这个信息是指其他俩个哨兵去连接了一下主节点,发现确实是主节点宕机了然后发起了一轮投票,这里咔咔使用的是redis4.0,版本之间这块信息有点差异+switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380:直到这里是哨兵发起投票的结果,推选端口为6380的redis为主节点+slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380:这里就把端口为6381与6379和新的主节点6380做了一个连接+sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380:最后一句是端口为6379的还是没有上线,于是给踢下线当我们在重新把6379的redis服务器上线后,就可以看到哨兵服务端响应了俩句。一句是去除6379的下线。最后一句就是重连6379到新的主节点上。这个时候主节点就是6380了,在6380的redis客户端设置值,检测主从复制是否正常工作。在新的主节点6380添加list类型在6379和6381获取这个值,至此呢!我们的哨兵模式就配置完成了。
Redis哨兵原理,我忍你很久了!(1)
本文主要围绕如下几个方面介绍哨兵哨兵介绍哨兵配置哨兵工作原理本文实现环境centos7.3 redis4.0redis工作目录 /usr/local/redis在虚拟机进行模拟操作Redis哨兵搭建以及工作流程本文主要围绕如下几个方面介绍哨兵本文实现环境一、什么是哨兵二、哨兵的作用二、如何配置哨兵1. 准备工作2. sentinel.conf配置解读3. 开始配置三、哨兵工作原理1. 监控工作流程2. 通知工作流程3. 故障转移原理(本文重点)四、总结一、什么是哨兵先简单说几句我们在配置主从复制时有一种情况就是主节点宕机了,谁来提供服务呢!当主节点宕机后主从复制就没有存在的意义了,数据为王的时代没有了数据何谈什么高可用。这个时候就横空出世了一位老大哥名叫哨兵,老大哥说这个问题我来帮你们处理。既然主节点master作为老大不领你们玩了。我就从你们四个中间再挑选出来一位老大,然后你们跟着他玩。等不带你们玩的那个老大回来后他的身份就失效了,就不在是你们的老大了。他只能跟着我挑选出来的老大玩。上边这段对话过程就是我们配置哨兵的意义到底在哪,跟谁玩就是谁给谁数据,知道了哨兵的作用我们就在继续。最后我们用专业术语来解释一下什么是哨兵。哨兵,英文名sentinel,是一个分布式系统,用于对主从结构中的每一台服务器进行监控,当主节点出现故障后通过投票机制来挑选新的主节点,并且将所有的从节点连接到新的主节点上。二、哨兵的作用上文中我们谈到的对话过程就是哨兵的作用之一自动故障转移。谈到作用肯定就是这个哨兵到底在工作中到底干了什么事情。我们先用比较干巴的概念描述一下,然后在下文的工作原理会一一谈到。哨兵的三个作用监控、通知、自动转移故障监控监控谁?支持主从结构的工作一个是主节点一个是从节点,那肯定就是监控这俩个了。监控主节点和从节点是否正常运行检测主节点是否存活,主节点和从节点运行情况通知哨兵检测的服务器出现问题时,会向其他的哨兵发送通知,哨兵之间就相当于一个微信群,每个哨兵发现的问题都会发在这个群里。自动故障转移当检测到主节点宕机后,断开与宕机主节点连接的所有从节点,在从节点中选取一个作为主节点,然后将其他的从节点连接到这个最新主节点的上。并且告知客户端最新的服务器地址。这里有一个注意点,哨兵也是一台redis服务器,只是不对外提供任何服务。配置哨兵时配置为单数。那么为什么配置哨兵服务器的数量为单数呢?带着这个疑问你会在下文看到你想要的答案。二、如何配置哨兵1. 准备工作这一章我们就开始配置哨兵,前期工作准备。下图就是咔咔的准备工作。开启8个客户端,三个哨兵、一个主节点、俩个从节点、一个主节点客户端、一个从节点客户端。2. sentinel.conf配置解读哨兵使用的配置文件是sentinel.conf我们来对sentinel.conf配置信息进行解读但是大多数都是注释,这里咔咔给大家提供一个命令来过滤这些无用信息 cat sentinel.conf | grep -v '#' | grep -v '^$'port 26379 :对外服务端口号dir /tmp:存储哨兵的工作信息sentinel monitor mymaster 127.0.0.1 6379 2:监控的是谁,名字可以自定义,后边的2代表的是,如果有俩个哨兵判断这个主节点挂了那这个主节点就挂了,通常设置为哨兵个数一半加一。sentinel down-after-milliseconds mymaster 30000:哨兵连接主节点多长时间没有响应就代表挂了。后边30000是毫秒,也就是30秒。sentinel parallel-syncs mymaster 1:这个配置项是指在故障转移时,最多有多少个从节点对新的主节点进行同步。这个值越小完成故障转移的时间就越长,这个值越大就意味着越 多的从节点因为同步数据而不可用。sentinel failover-timeout mymaster 180000:在进行同步的过程中,多长时间完成算有效,系统默认值是3分钟。3. 开始配置使用命令cat sentinel.conf | grep -v '#' | grep -v '^$' > ./data/sentinel-26379.conf把sentinel.conf过滤后的信息移到/usr/local/redis/conf下然后打开sentinel-26379.conf修改信息存放目录然后快速的复制俩个哨兵配置文件,端口为26380和26381。sed 's/26379/26381/g' sentinel-26379.conf > sentinel-26381.conf测试主从复制处于正常工作状态,启动三台redis服务器,端口分别为6379、6380、6381查看主节点信息,是有俩台从节点在连接着,端口分别为6380、6381。这里有一个小小的点就是lag怎么一个是1一个是0呢!lag是延迟时间,我这里是本地测试所以会出现0的情况,使用云服务器是很少出现的。lag的值为0和1都属于正常。测试主节点添加一个hash值,hset kaka name kaka分别从slave1和slave2获取kaka的值,检测主从复制是否正常运行。经过测试我们的主从结构是正常运行的。