DAY05
知识回顾+遗留问题
2018年1月15日
19:32
前4天的脉络
复习的顺序:将其中的所有非代码技术先复习
把代码敲一遍,分别的引入技术
1 nginx 一个服务器7万/秒 转发 并发 5万 3万
是京淘中提升并发的第一道关卡
20台nginx集群就可以搞定每秒100万并发
2 属性注入
扩展Bean加载数据
后处理bean注入扩展类把数据传递给伪service
后台controller图片上传注入伪service使用属性
3 nginx的匹配规则(与优先级)
· 精确匹配=
· 字符串前缀匹配 ^~
· 按照配置顺序的正则匹配(AB都匹配上了,配置在前的匹配)
· 不带任何修饰的前缀匹配/images/
· 当所有匹配成功时,停止匹配,按照当前匹配规则处理请求
· 前缀匹配,有包含关系时,按最大匹配长度原则匹配
· 最低优先级是通配符 /
location = /images{
return 205;}
location ^~ /images {
return 200;}
location ^~ /images/test.png {
return 201;}
location ~* \.png$ {
return 203;}
location ~ \.(gif|jpg|png|js|css)$ {
return 202;}
location / {
return 204;}
http://localhost/ 返回204
http://localhost/images 205和204?
http://localhost/images/id 200
http://localhost/images/test.png 返回201 前缀最长匹配原则
http://localhost/haha.png 返回203 顺序正则原则
4 nginx负载均衡
轮询:将所有的访问平均分配给服务器库中配置的服务器;
nginx负载均衡
2018年1月16日
10:05
权重:
根据不同机器性能,计算相对的访问负载承受,从而使用权重配置
负载的量
upstream jt1710{
server 192.168.40.170:8081 ;
server 192.168.40.170:8082 ;
server 192.168.40.170:8080 ;
server 192.168.40.170:8081 ;
server 192.168.40.170:8081 ;
server 192.168.40.170:8081 ;
server 192.168.40.170:8081 ;
server 192.168.40.170:8081 ;}
权重的关键字
weight:权重的优先量级;数字越大,访问次数越多
down;宕机状态永不访问;
当服务器宕机不可恢复时,nginx会根据权重或者轮询配置
继续访问,连接超时访问失败,但是不会停止访问,
down一定程度的减少了资源的损耗
session黏着
负载均衡中的session共享问题
解决session共享问题
session黏着
当用户通过ngnix访问某一个tomcat后,使用session黏着,保证后续访问永远
访问者一台
1 ip_hash
利用客户端请求的ip和端口(192.168.40.170:661)获取其字符串的hash值
String str="192.168.40.160:8080";
str.hashCode();(未必是正值,&Integer.max_value)
System.out.println(user1.hashCode()&Integer.MAX_VALUE);
System.out.println(user2.hashCode()&Integer.MAX_VALUE);
System.out.println(user3.hashCode()&Integer.MAX_VALUE);
获取到字符串的整数然后对已有的负载均衡服务器库数量进行取余(三台为例)
哈希整数N%3=[0,1,2]
如果是4台呢?对4取余,依次类推
2 url_hash黏着(依赖第三方插件实现)
访问服务器的url地址字符串做hash取余运算
order.jt.com/*****/***.html
具有某一个固定功能的服务器,固定
springSession(HttpSession+redis)
将虚拟机中的后台系统做完全,还差访问数据库
需要修改war包中的jdbc.properties
需要获取linux系统访问windows系统的ip地址
商品描述
2018年1月16日
10:57
查看电商中的描述信息,需要大字段属性保存图片信息和文本信息
blob/text破坏表的索引,商品描述不能添加到商品列表中
单独创建一个商品描述表格 tb_item_desc
开发过程
pojo,mapper,service,controller
service不用单独编写,直接和ItemService一起保证事务的有效性
级联新增时从表(tb_item_desc),主表(tb_item)
关联的键是itemId
mybatis+mysql底层实现
调用sql
select last_insert_id;
商品描述的修改(包括数据回显和修改过程)
http://manage.jt.com/item/query/item/desc/1474391958
点击编辑按钮弹出item-edit页面,以上一个请求
$.getJSON('/item/query/item/desc/'+data.id,function(_data){
if(_data.status == 200){ itemEditEditor.html(_data.data.itemDesc);
}
});
第一个参数:'/item/query/item/desc/'+data.id
第二个参数:回调函数function(_data) _data就是SysResult 的json字符串
传递给controller的参数是data.id 以restFul形式传参
回显就是查询,在itemController和itemService中添加查询代码
修改部分
修改的前台js代码
$.post("/item/update",$("#itemeEditForm").serialize(), function(data){
if(data.status == 200){
$.messager.alert('提示','修改商品成功!','info',function(){
$("#itemEditWindow").window('close');
$("#itemList").datagrid("reload");
});
}
});
/item/update:请求地址
$("#itemeEditForm").serialize():参数将表单内所有标签封装成一个模拟的get请求参数
字符串传递
function(data):回调函数,data是SysResult的json转化的js对象
商品详情的删除工作
Redis
2018年1月16日
15:09
情景讨论
在后台功能已经完成了,
后台系统的高并发思路:
技术:tomcat集群+nginx
引入20台nginx --100万/s;
考虑一个问题:当100万个用同时增删改查操作时;
系统瓶颈在哪:数据库,尤其是查询
Redis
分布式,nosql,可以持久化,内存,数据库
分布式:数据被划分
nosql:not only sequence query language
不仅仅支持关系型数据--结构化的数据
还支持非关系型数据--非结构化数据
可持久化+内存:启动回复机制
数据库存储;
可以分布式的存储大量海量的数据,存放到内存中,
可以做缓存数据库
京淘中的缓存架构可以如何设计
缓存可以如何添加
数据库缓存
执行的过程包括sql,组织查询结果resultSet
根据sql可以创建缓存,存储已经查过的resultset,节省了
资源的调度重组resultSet
持久层缓存
减少从数据库获取的结果转化成对象的过程,缓存存在直接调用其中
保存的对象结果;
业务层缓存
减少调用层次
控制层缓存
较少调用层次
<问题>可不可以过多使用缓存
缓存是占用内存空间的,过多的缓存插入,容易造成数据的冗余
在内存不够时,清空逻辑会交叉导致数据失效
结论缓存引入的最终目的
1 减少数据库的访问压力
2 减少网络传输
3 减少封装层次
Redis这个技术就可以在京淘中实现提升性能的目的,缓存
介绍缓存
主流的缓存架构
1 ehcache (很多数据库底层缓存使用ehcache)并发量差
2 memoryCache,10年,高并发的100万/s; 缺点:不落地
3 Redis:持久化可以在宕机恢复后迅速解决数据丢失
<问题>:如果在缓存服务器宕机后,无法进行数据恢复/没有解决数据重新加载
的问题,会导致“雪崩”/”缓存击穿“
雪崩/缓存击穿
海量用户访问请求涌入,一旦缓存失效(宕机数据丢失);所有的访问
涌入数据库;数据库无法承受海量数据的查询,导致数据库服务器宕机;
重启数据库,请求查询没消失,数据库--宕机--重启循环,导致系统崩溃
解决雪崩:
1 缓存用不宕机;启动集群,永远让集群中的一部分起作用
2 缓存技术必须可以恢复数据,持久化
安装redis
2018年1月16日
15:47
1 下载安装包解压
使用对象存储的源站地址获取资源
"
创建管理目录
[root@10-9-62-65 ~]# cd /home/
[root@10-9-62-65 home]# mkdir software
[root@10-9-62-65 home]# cd software/
[root@10-9-62-65 software]#
使用wget获取资源
解压
redis使用
make && make install
2 启动redis
启动redis的服务
#redis-server
使用redis需要启动redis客户端
#redis-cli
如果想在同一个操作控制台启动服务和客户端
启动客户端时可以使用后台运行命令
#redis-server &
停止redis服务
1 占用控制台的redis服务直接ctrl+c停止服务
2 在后台运行服务的时候,登陆客户端
shutdown;
3 检查后台运行的redis服务
ps -ef|grep redis;
redis-server 表示redis服务
*:表示能够访问当前redis服务的所有ip地址,都可以
如果列出一系列的ip地址,除这些ip意外的所有访问redis服务的请求
都被拒绝
Redis的基础命令
操作字符串
redis存储数据是以key-value的形式,key-{key,value},key-list
keys:查询当前的存储空中的所有存在key;
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379>
set [key名] [value]
设置 key-value值,value是String字符串
127.0.0.1:6379> set name xiao
OK
127.0.0.1:6379> key *
(error) ERR unknown command 'key'
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379>
get [key名]
获取key对应的value值
127.0.0.1:6379> keys *
1) "gender"
2) "name"
3) "age"
4) "city"
127.0.0.1:6379> get name
"xiao"
127.0.0.1:6379>
select [整数值[0-15]]
redis存在吗默认的0-15标号的数据分裤,默认使用0号;这个功能是早期
版本冗余的功能,现在都使用默认0号数据库;现在java的代码不支持分库
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]>
exists [key名]
判断当前key是否存在;与get的却别
redis存储的key-value结构的字符串数据 512M,当逻辑判断只需要返回是与
否时,get命令获取的大字符串就占用了资源的调用
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists xiao
(integer) 0
127.0.0.1:6379>
del [key名]
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> keys *
1) "gender"
2) "num"
3) "age"
4) "city"
type [key名]
127.0.0.1:6379> set num1 100
OK
127.0.0.1:6379> type num1
string
127.0.0.1:6379>
help type/help [命令名称]
127.0.0.1:6379> help set
SET key value [EX seconds] [PX milliseconds] [NX|XX]
summary: Set the string value of a key
since: 1.0.0
group: string
127.0.0.1:6379>
实际问题可以到官网查询对应的命令细节
flushall 将所有的当前内存数据(0-15号库),flush到持久化文件
127.0.0.1:6379> keys *
1) "num1"
2) "gender"
3) "num"
4) "age"
5) "city"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty list or set)
flushdb flush当前redis某一个标号的库中的内容到持久化文件
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> selet
(error) ERR unknown command 'selet'
127.0.0.1:6379> selet 1
(error) ERR unknown command 'selet'
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> set name xiao
OK
127.0.0.1:6379[1]> keys *
1) "name"
127.0.0.1:6379[1]> flushdb
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379>
===============================================================================
==========================================================================
DAY06
知识回顾
2018年1月17日
8:54
1 nginx负载均衡
权重;weight,down关键字
session黏着,解决session共享的负载均衡计算方式
ip_hash
url_hash,以来第三方插件;
2 商品描述
大字段内容,不破坏商品表的索引,单独使用一张表来记录
单独的desc表数据特别大的时候,分库,分表保存(早期)
现在几乎所有的可见查询功能都使用缓存
完成商品详情的增删改查
改和查一体(回显和修改)
3 Redis介绍
后台的访问并发量已经使用nginx+tomcat可以达到很高
程序性能未必能支持如此大的并发量请求
缓存的引入;
分布式,nosql,可持久化,内存,缓存,数据库
ehcache,
memoryCache
雪崩:缓存由于各种原因数据丢失,大量请求涌入数据库,数据库无法
承受,宕机重启,缓存没数据,请求未消失,数据库继续宕机,恶性循环
解决雪崩:没有持久化的功能,必须保证缓存集群永远保持部分可使用
在缓存技术中添加持久化,在宕机后可以读取持久化文件
恢复数据
4 安装redis+key-value类型数据使用的部分命令
keys*;get,set,exists,flushdb,flushall,type,help,select,del
Redis基础命令
2018年1月17日
9:28
incr decr 自增自减
127.0.0.1:6379> set n1 100
OK
127.0.0.1:6379> type n1
string
127.0.0.1:6379> incr n1
(integer) 101
127.0.0.1:6379> get n1
"101"
127.0.0.1:6379> set school bjdx
OK
127.0.0.1:6379> incr school
(error) ERR value is not an integer or out of range
127.0.0.1:6379>
incrby 数字 decrby 数字
127.0.0.1:6379> incrby n1 5
(integer) 106
127.0.0.1:6379>
append 在value后追加数据
127.0.0.1:6379> set name xiao
OK
127.0.0.1:6379> apend name laoshi
(error) ERR unknown command 'apend'
127.0.0.1:6379> append name laoshi
(integer) 10
127.0.0.1:6379> get name
"xiaolaoshi"
127.0.0.1:6379>
mset mget 获取或者设置一批key-value对
mset k1 v1 k2 v2
mget k1 k2
127.0.0.1:6379> mset n1 100 n2 200 n3 300
OK
127.0.0.1:6379> keys *
1) "name"
2) "n3"
3) "n2"
4) "n1"
127.0.0.1:6379> mget n1 n2 n3
1) "100"
2) "200"
3) "300"
127.0.0.1:6379>
支持的语言API不支持这个命令,这种群体操作k-v对的过程
无法进行分片和集群计算;早期redis版本遗留功能;
expire [key] 时间数字(单位秒)
设置当前key对应的value的过期时间
ttl 查看当前key-value对的存活时间
127.0.0.1:6379> set bomb c4
OK
127.0.0.1:6379> keys *
1) "name"
2) "n1"
3) "n2"
4) "n3"
5) "bomb"
127.0.0.1:6379> expire bomb 100
(integer) 1
127.0.0.1:6379> ttl
(error) ERR wrong number of arguments for 'ttl' command
127.0.0.1:6379> ttl bomb
(integer) 86
127.0.0.1:6379> ttl bomb
(integer) 85
127.0.0.1:6379> ttl bomb
(integer) 84
127.0.0.1:6379>
第二个案例
127.0.0.1:6379> set bread binbao
OK
127.0.0.1:6379> expire bread 5
(integer) 1
127.0.0.1:6379> ttl bread
(integer) 2
127.0.0.1:6379> ttl bread
(integer) 1
127.0.0.1:6379> ttl bread
(integer) 0
127.0.0.1:6379> ttl bread
(integer) -2
127.0.0.1:6379>
127.0.0.1:6379> ttl name
(integer) -1
127.0.0.1:6379>
-2代表过期,-1代表永久
可以使用数据中的过期来做倒计时
还可以秒杀;
pexpire [key] 时间数字(毫秒)
127.0.0.1:6379> pexpire bomb 5000
(integer) 1
127.0.0.1:6379> ttl bomb
(integer) 3
127.0.0.1:6379> ttl bomb
(integer) 2
HASH+LIST
2018年1月17日
9:47
1 HASH结构
key-value字符串类型中的key本身也是key-value对儿
HSET和HGET赋值和取值
HSET key field value
HGET key field
HMSET key field value [field value…]
HMGET key field value [field value…]
HGETALL key
127.0.0.1:6379> hset user username chenchen
(integer) 1
127.0.0.1:6379> hget user username
"chenchen"
127.0.0.1:6379> hset user username chen
(integer) 0
127.0.0.1:6379> keys user
1) "user"
127.0.0.1:6379> hgetall user
1) "username"
2) "chen"
127.0.0.1:6379>
127.0.0.1:6379> hset user age 30
(integer) 1
127.0.0.1:6379> hgetall user
1) "username"
2) "chen"
3) "age"
4) "30"
127.0.0.1:6379>
HSET命令不区分插入和更新操作,当执行插入操作时HSET命令返回1,当执行更新操作时返回0。
HMSET和HMGET设置和获取对象属性
127.0.0.1:6379> hmset person username tony age 18
OK
127.0.0.1:6379> hmget person age username
1) "18"
2) "tony"
127.0.0.1:6379> hgetall person
1) "username"
2) "tony"
3) "age"
4) "18"
127.0.0.1:6379>
注意:上面HMGET字段顺序可以自行定义
HEXISTS属性是否存在
127.0.0.1:6379> hexists killer
(error) ERR wrong number of arguments for 'hexists' command
127.0.0.1:6379> hexists killer a
(integer) 0
127.0.0.1:6379> hexists user username
(integer) 1
127.0.0.1:6379> hexists person age
(integer) 1
127.0.0.1:6379>
HDEL删除对象字段
127.0.0.1:6379> hdel user age
(integer) 1
127.0.0.1:6379> hgetall user
1) "username"
2) "chen"
127.0.0.1:6379> hgetall person
1) "username"
2) "tony"
3) "age"
4) "18"
127.0.0.1:6379>
只获取字段名HKEYS或字段值HVALS
127.0.0.1:6379> hkeys person
1) "username"
2) "age"
127.0.0.1:6379> hvals person
1) "tony"
2) "18"
获取字段数量HLEN
127.0.0.1:6379> hlen user
(integer) 1
127.0.0.1:6379> hlen person
(integer) 2
127.0.0.1:6379>
List
key-value(双向链表,左-上,右-下)
查看list
redis 127.0.0.1:6379> lrange mylist3 0 -1
lrange key start length
LPUSH
在key对应list的头部添加字符串元素
redis 127.0.0.1:6379> lpush mylist "world"
(integer) 1
redis 127.0.0.1:6379> lpush mylist "hello"
(integer) 2
redis 127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379>
RPUSH
在key对应list的尾部添加字符串元素
redis 127.0.0.1:6379> rpush mylist2 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist2 "world"
(integer) 2
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379>
linsert
在key对应list的特定位置之前或之后添加字符串元素
redis 127.0.0.1:6379> rpush mylist3 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist3 "world"
(integer) 2
redis 127.0.0.1:6379> linsert mylist3 before "world" "there"
(integer) 3
redis 127.0.0.1:6379> lrange mylist3 0 -1
1) "hello"
2) "there"
3) "world"
redis 127.0.0.1:6379>
lset
设置list中指定下标的元素值
redis 127.0.0.1:6379> rpush mylist4 "one"
(integer) 1
redis 127.0.0.1:6379> rpush mylist4 "two"
(integer) 2
redis 127.0.0.1:6379> rpush mylist4 "three"
(integer) 3
redis 127.0.0.1:6379> lset mylist4 0 "four"
OK
redis 127.0.0.1:6379> lset mylist4 -2 "five"
OK
redis 127.0.0.1:6379> lrange mylist4 0 -1
1) "four"
2) "five"
3) "three"
redis 127.0.0.1:6379>
大于0是正数
小于0倒数
lrem
从key对应list中删除count个和value相同的元素,count>0时,
按从头到尾的顺序删除
redis 127.0.0.1:6379> rpush mylist5 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist5 "hello"
(integer) 2
redis 127.0.0.1:6379> rpush mylist5 "foo"
(integer) 3
redis 127.0.0.1:6379> rpush mylist5 "hello"
(integer) 4
redis 127.0.0.1:6379> lrem mylist5 2 "hello"
(integer) 2
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) "foo"
2) "hello"
redis 127.0.0.1:6379>
count<0时,按从尾到头的顺序删除
redis 127.0.0.1:6379> rpush mylist6 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist6 "hello"
(integer) 2
redis 127.0.0.1:6379> rpush mylist6 "foo"
(integer) 3
redis 127.0.0.1:6379> rpush mylist6 "hello"
(integer) 4
redis 127.0.0.1:6379> lrem mylist6 -2 "hello"
(integer) 2
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) "hello"
2) "foo"
redis 127.0.0.1:6379>
count=0时,删除全部
redis 127.0.0.1:6379> rpush mylist7 "hello"
(integer) 1
redis 127.0.0.1:6379> rpush mylist7 "hello"
(integer) 2
redis 127.0.0.1:6379> rpush mylist7 "foo"
(integer) 3
redis 127.0.0.1:6379> rpush mylist7 "hello"
(integer) 4
redis 127.0.0.1:6379> lrem mylist7 0 "hello"
(integer) 3
redis 127.0.0.1:6379> lrange mylist7 0 -1
1) "foo"
redis 127.0.0.1:6379>
ltrim
保留指定key 的值范围内的数据
redis 127.0.0.1:6379> rpush mylist8 "one"
(integer) 1
redis 127.0.0.1:6379> rpush mylist8 "two"
(integer) 2
redis 127.0.0.1:6379> rpush mylist8 "three"
(integer) 3
redis 127.0.0.1:6379> rpush mylist8 "four"
(integer) 4
redis 127.0.0.1:6379> ltrim mylist8 1 -1
OK
redis 127.0.0.1:6379> lrange mylist8 0 -1
1) "two"
2) "three"
3) "four"
redis 127.0.0.1:6379>
lpop
从list的头部删除元素,并返回删除元素
redis 127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379> lpop mylist
"hello"
redis 127.0.0.1:6379> lrange mylist 0 -1
1) "world"
redis 127.0.0.1:6379>
rpop
从list的尾部删除元素,并返回删除元素:
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
2) "world"
redis 127.0.0.1:6379> rpop mylist2
"world"
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
redis 127.0.0.1:6379>
rpoplpush
从第一个list的尾部移除元素并添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个list是空或者不存在返回nil:
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) "three"
2) "foo"
3) "hello"
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) "hello"
2) "foo"
redis 127.0.0.1:6379> rpoplpush mylist5 mylist6
"hello"
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) "three"
2) "foo"
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) "hello"
2) "hello"
3) "foo"
redis 127.0.0.1:6379>
lindex
返回名称为key的list中index位置的元素:
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) "three"
2) "foo"
redis 127.0.0.1:6379> lindex mylist5 0
"three"
redis 127.0.0.1:6379> lindex mylist5 1
"foo"
redis 127.0.0.1:6379>
llen
返回key对应list的长度:
redis 127.0.0.1:6379> llen mylist5
(integer) 2
redis 127.0.0.1:6379>
数据的分布存储
2018年1月17日
10:44
要完成数据的分片存储,需要至少多个redis实例
启动多个redis实例
前面的单个redis节点实例的启动时默认配置
端口号6379
配置文件
/redis根目录/redis.conf
配置文件的修改内容
p61 bind 用#注释掉
p80 保护模式不启动
p84 6379是默认端口(要启动其他的redis实例需要修改端口)
p105 当客户端空闲时间一小时,就会自动断开连接,0秒表示
不启用超时配置
p128 daemonize 设置成yes让redis服务器启动有守护进程管理
(后台执行)
p150 对应不同的redis实例,pid的文件名称需要和端口同名
save 900(秒) 1(变动的数据条数)
当900以内,至少有1条数据变动,看是flush保存数据到文件
save 300 10
300秒以内至少10条数据变动,保存文件
save 60 10000
启动第二和第三个redis实例
redis-server redis.conf(指定启动文件)
需要第二个实例的配置文件
需要第三个实例的配置文件
拷贝redis.conf,用redis6380.conf,redis6381.conf
将拷贝的文件中只修改与端口有关内容
port
pid文件
6381的略
启动另外两个节点
#redis-server redis6380.conf
#redis-server redis6381.conf
#ps -ef|grep redis
指定端口登录客户端redis-cli -p [端口号]
#redis-cli -p 6380
#redis-cli -p 6381
6380和6381会共享6379的dump.db文件
所以不同的节点实例在同一个机器上运行时,可以修改dump.db
指定端口文件;
三个节点,怎么分布式保存数据?
数据来源:代码的逻辑执行
如何使用代码来操作redis执行分布式的数据存储过程?
引出了Jedis客户端
Jedis
2018年1月17日
11:36
测试jedis控制redis的命令功能
需要导入jedis包
自定义分片
准备数据:
葵花宝典A,B,C三部分数据
将三部分数据分别存储到redis 6379 6380 6381
哈希取余
利用hash的散列特性,可以处理海量非结构化数据的散列分布的分片计算
代码
jedis分片
没有在分片时使用哈希取余,hash一致性
经过代码发现,一般的自定义分片逻辑计算无法做到散列
不散列无法均衡
jedis池
HASH一致性
2018年1月17日
15:27
作为散列算法
考虑哈西取余的问题
1 容易产生大规模的数据倾斜(散列必定倾斜)
hash一致性一定程度的解决了数据倾斜;
2 哈希取余算法,导致数据迁移量过大
当redis集群数量进行增加减少的时候,哈希取余算法中的n变化了
由于n的变化,数据命中变化量非常大,需要迁移的数据量非常大,
jedis中引入另外一种hash散列算法--hash一致性
1997麻省理工学生发明;引入一个2^32-1(43亿)整数环,
把节点使用ip+端口做哈希散列计算,得到43亿中一个值,投射到环中
将所有的数据key进行哈希散列计算,得到43亿中的一个
node1,2,3个节点启动着redis
数据分别是key1,2,3,4
根据hash散列算法都投射到一个整数上
顺时针寻找最近节点的映射规则,将key值进行存放
key1,2存储在node1
key3存储在node2
key4存储在node3
当增加删除节点时,迁移量有何变化?
增加node4,根据散列得到43亿中一个整数,投射到环上
根据顺时针寻找最近节点存储的原则,只需要迁移key4
而且可以判断,原节点数量越多,迁移量越小
节点删除,将node2删除,迁移key3
解决数据平衡性
单独的使用节点的ip+端口做映射,毕竟节点数量是有限的
有可能在映射时的各自分布位置并不平均,导致数据偏移量非常大
解决数据的平衡性引入虚拟节点
node1的ip是192.168.40.156
node2的ip是192.168.40.157
各自引入2个虚拟节点(虚拟节点的数量是非常大的)
node1-1=hash(192.168.40.156#1)
node1-2=hash(192.168.40.156#2)
node2-1=hash(192.168.40.157#1)
node2-2=hash(192.168.40.157#2)
每一个虚拟节点在哈希环上也会接收顺时针寻找最近节点的key们
通过增加节点数量(虚拟的),完成数据的映射平衡
凡是投影到node1-1,node1-2的key,都会中真实存储在node1中
所以虚拟节点越多平衡性越好
京淘的缓存引入
2018年1月17日
16:24
根据在模拟缓存的逻辑,思考后台什么位置可以做缓存?
商品分类树(缓存版本1)
商品列表(不好做,有分页参数)
商品新增,修改,删除
商品详情新增,修改,删除
补充内容
2018年1月17日
10:19
HASH取余数据分片
原子级操作
一系列操作如果称之为原子级,不可分割,一旦分隔开
系列操作不成功
当天问题
2018年1月17日
16:51
版本1的缓存引入京淘时
商品分类树查询
Name [spring.liveBeansView.mbeanDomain] is not bound in this Context. Unable to find [spring.liveBeansView.mbeanDomain].. Returning null.
原因,从mysql查询的数据没有text,state
返回json需要text和state,ItemCat类中的两个get方法,导致MAPPER转化字符串和对象时的错误
在ItemCat中添加一个注解,让MAPPER转化时忽略这两个属性