1.集群工作原理
1.1 集群宕机条件
宕机条件: 如果节点主机数量缺失,则集群崩溃.
案例1: 1主1从.现在→ 3台主机/3台从机 共6台redis. 问至少宕机几台 集群崩溃??? 2台
案例2: 1主2从.现在→ 3台主机/6台从机 共9台redis. 问至少宕机几台 集群崩溃??? 5台
1.2 Redis集群入门案例
/**
* Redis集群测试
*
*/
@Test
public void testRedisCluster(){
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.126.129", 7000));
nodes.add(new HostAndPort("192.168.126.129", 7001));
nodes.add(new HostAndPort("192.168.126.129", 7002));
nodes.add(new HostAndPort("192.168.126.129", 7003));
nodes.add(new HostAndPort("192.168.126.129", 7004));
nodes.add(new HostAndPort("192.168.126.129", 7005));
JedisCluster jedisCluster = new JedisCluster(nodes);
jedisCluster.set("aa", "redis集群测试");
System.out.println("获取数据:"+jedisCluster.get("aa"));
}
1.3 hash槽算法
1.3.1 算法介绍
说明: RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]%16384)映射到0-16383槽内,共16384个槽位(2^14次方),每个节点维护部分槽及槽所映射的键值数据.根据主节点的个数,均衡划分区间.
算法:哈希函数: Hash()=CRC16[key]%16384
当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到管理该槽的节点中.
1.3.2 面试题说明
-
如果分区对不同的key hash(key1)= 3000 hash(key2)=3000 问? 算法是否有误? 是否影响数据的存取?
A 不影响
执行过程:
存:key1/key2 都归第一个主机node进行管理. redis.set(key1,value1), redis.set(key2,value2);
取: key1 hash(key1)=3000 找到node 进行取值操作 redis.get(key1) 结果一定正确 -
redis集群中最多存储16384个数据!!! :错!!
16384只是hash槽位的个数,与存储数量没有必然的联系. 能存储多少 完全由redis内存决定. -
redis集群中主机的数量有没有要求??? A : 3-16384台
1.4 SpringBoot整合Redis集群
1.4.1 编辑配置文件
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005
1.4.2 编辑Redis集群配置类
@Configuration //标识为一个配置类, 一般整合第三方
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
@Value("${redis.nodes}")
private String nodes; //node,node,node
@Bean
public JedisCluster jedisCluster(){
Set<HostAndPort> nodeSet = new HashSet<>();
String[] nodeArray = nodes.split(",");
for (String node : nodeArray){
String host = node.split(":")[0];
int port = Integer.parseInt(node.split(":")[1]);
HostAndPort hostAndPort = new HostAndPort(host,port);
nodeSet.add(hostAndPort);
}
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMinIdle(10);
jedisPoolConfig.setMaxIdle(40);
jedisPoolConfig.setMaxTotal(1000);
return new JedisCluster(nodeSet,jedisPoolConfig);
}
}
1.4.3 编辑Redis AOP
2. 京淘项目前台搭建
2.1 京淘前后端调用
2.2 京淘前台搭建
2.2.1 创建JT-WEB
2.2.2 添加继承/依赖/插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--添加继承-->
<parent>
<artifactId>jt</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jt_web</artifactId>
<!--打包方式 html jar|jsp war -->
<packaging>war</packaging>
<!--添加依赖-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--添加插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2.3 导入静态资源文件
2.2.4 配置京淘启动项
如果报错404 则需要重新配置工作目录即可.
2.2.5 配置域名代理
要求: http://www.jt.com 的方式访问localhost:8092的服务器.
修改hosts文件:
# 京淘前台管理系统
server {
listen 80;
server_name www.jt.com;
location / {
proxy_pass http://localhost:8092;
}
}
修改nginx配置文件之后,重启nginx服务器
2.2.6 关于https访问报错说明
个别的浏览器 可能将请求路径 自动的转化为https.
解决方案:
- 去京淘问题集中 查找答案
- 自己百度 https禁用
2.3 拦截静态资源.html
2.3.1 业务分析
通常情况下,需要获取商品信息时,一般采用都是restFul风格, {itemId}.html 要求后端服务器应该拦截.html为结尾的请求即可.
2.3.2 以.html结尾的优势
如果网站页面 以.html为结尾的请求,则该页面更加容易被搜索引擎记录. 通过搜索引擎提高网站的曝光率.
搜索引擎工作原理:
2.3.3 后台服务器拦截策略
- 默认条件下后台服务器只拦截前缀型请求.
- 如果在浏览器中写入index.html 则后台服务器认为,请求的是一个具体的静态页面.
- 如果需要后台服务器拦截静态页面,之后通过服务器进行中转,则需要额外的配置
package com.jt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
//开启匹配后缀型配置 .html请求时 springMVC才会拦截.
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
}
2.3.4 伪静态
伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页面,但是有的朋友为了实时的显示一些信息。或者还想运用动态脚本解决一些问题。不能用静态的方式来展示网站内容。但是这就损失了对搜索引擎的友好面。怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。
总结: 以.html结尾的"动态"页面技术
2.4 用户登录/注册跳转
2.4.1 业务需求说明
- 当用户网址 http://www.jt.com/user/login.html 要求跳转到登录页面中 login.jsp
- 注册页面 http://www.jt.com/user/register.html 要求跳转到登录页面中 register.jsp
要求用一个方法实现通用的页面跳转
2.4.2 利用RestFul实现页面跳转
说明:编辑UserController 利用restFul的方式,实现页面通用跳转.
package com.jt.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 实现通用的页面跳转
* 1). 当用户网址 http://www.jt.com/user/login.html 要求跳转到登录页面中 login.jsp
* 2). 注册页面 http://www.jt.com/user/register.html 要求跳转到登录页面中 register.jsp
*/
@RequestMapping("/{modleName}")
public String module(@PathVariable String modleName){
return modleName;
}
}
3 关于跨域问题说明
3.1 跨域测试
3.1.1 测试demo1
- 访问页面的网址 http://manage.jt.com:80/test.html
- Ajax访问数据的地址: http://manage.jt.com:80/test.json
分析: 协议://域名:端口 完全一致.
测试是否正常: 测试正常
结论: 如果协议://域名:端口号 都相同时 请求可以正常的进行.
3.1.2 测试demo2
- 访问页面的网址 http://www.jt.com:80/test.html
- Ajax访问数据的地址: http://manage.jt.com:80/test.json
分析: 协议://域名:端口 域名不同.
测试结果: ajax调用无法正常执行.
3.1.3 关于浏览器同源策略的说明
说明: 浏览器规定 当浏览器解析页面时,当遇到ajax请求时 如果请求与当前页面的 协议://域名:端口号都相同时,则满足同源策略 称之为同域请求.浏览器可以正确解析返回值 请求正常.
如果三者中有一项不同,则把请求称之为叫做跨域请求. 浏览器出于安全性的考虑 则不予解析返回值.
远程请求的流程:
3.2 JSONP
3.2.1 关于JSONP介绍
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的
3.2.2 JSONP原理说明
- 利用javaScript标签 动态获取远程数据
<script type="text/javascript" src="http://manage.jt.com/test.json"></script>
- 自定义回调函数
<script type="text/javascript">
/*JS是解释执行的语言 */
/*定义回调函数 */
function hello(data){
alert(data.name);
}
</script>
- 将返回值结果 进行特殊格式封装
hello({"id":"1","name":"tom"})
问题: JSONP能否发起POST请求啊?
不能 原因: javaScript中的src属性只能发起get请求,不可以用POST.
3.2.3 jQuery中的JSONP
3.2.3.1 编辑页面JS
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
alert("测试访问开始!!!!!")
$.ajax({
url:"http://manage.jt.com/web/testJSONP",
type:"get", //jsonp只能支持get请求
dataType:"jsonp", //dataType表示返回值类型 必须添加
jsonp: "callback", //指定参数名称 一般固定写死!!!
jsonpCallback: "hello", //指定回调函数名称
success:function (data){ //data经过jQuery封装返回就是json串
alert(data.id);
alert(data.name);
//转化为字符串使用
//var obj = eval("("+data+")");
//alert(obj.name);
}
});
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
3.2.3.2 京淘后台业务实现
package com.jt.web;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.pojo.ItemDesc;
import com.jt.util.ObjectMapperUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JSONPController {
@RequestMapping("/web/testJSONP")
public JSONPObject testJSONP(String callback){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("详情信息2222");
return new JSONPObject(callback, itemDesc);
}
/**
* JSONP请求 返回值要求: callback(JSON)
* 1.请求网址: http://manage.jt.com/web/testJSONP?callback=xxxx
* 2. 页面取值 itemDesc属性
*/
/* @RequestMapping("/web/testJSONP")
public String testJSONP(String callback){
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("详情信息");
String json = ObjectMapperUtil.toJSON(itemDesc);
//jsonp步骤3 封装指定的格式
return callback + "(" + json + ")";
}*/
}
3.3 CORS
3.3.1 CORS介绍
跨源资源共享 (CORS) (或通俗地译为跨域资源共享)是一种基于HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的**“预检”**请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。
补充: 现阶段几乎所有的浏览器都默认支持CORS(IE除外)
3.3.2 CORS跨域测试
- 修改ajax请求路径
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$.get("http://manage.jt.com/testCors",function(data){
alert(data.itemDesc);
})
})
</script>
</head>
<body>
<h1>JSON跨域请求测试</h1>
</body>
</html>
- 跨域报错
3.3.3 CORS跨域原理
说明: CORS 在响应头中标识哪些网址可以访问服务器.CORS的配置是服务器端的配置和浏览器没关系.
3.3.4 编辑后台Controller
package com.jt.web;
import com.jt.pojo.ItemDesc;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(value = "http://www.jt.com") //标识当前Controller中的方法 允许被其他服务器访问
//预检: 在规定时间内同源策略不会再次拦截 提高效率
public class CorsController {
/**
* http://manage.jt.com/testCors
* @return
*/
@RequestMapping("testCors")
public ItemDesc cors(){
return new ItemDesc().setItemDesc("CORS测试");
}
}
响应头信息: