我们知道,整个Redis的数据结构是key-value形式组成的一个全局字典,还有带过期时间key集合也是一个字典。
struct RedisDb{
dict* dict; //所有key-value
dict* expires //所有key的过期时间
...
}
struct zset{
dict* dict //所有的value-score
zskiplist *zsl //跳表
}
一、字典内部结构
在字典的内部结构中包含两个hashtable,但是只有一个hashtable是存储数据的(我们假设为h[0],另一个hashtable(我们假设h[1])的作用是:当字典需要进行扩容或者缩容的时候,需要分配出新的hashtable,然后进行渐进式的搬迁 ,这个h[0]存储的是旧的数据,h[1]存储的是新的数据,当数据完全迁移到h[1]的时候,h[0]里面的hashtable将会被删除,而被被h[1]取代。
Redis里面hashtable的结构和Java中HashMap的结构以及原理几乎是一样的,都是通过粪桶的方式解决了hash冲突。在结构中一共有两个维度,第一个是数组,在每一个数组元素中又存了一个链表结构。
当插入一个元素的时候,先获取元素的散列值,根据散列值找到结构数组中对应的位置。如果该位置中没有元素,则把插入的新值填充到相应的数组位置。若有元素(元素为一个链表节点),则以哈希值和内容来比较两个元素是否相等,如果不相等取元素的下一个节点,直到取到最后一个节点加入到元素的尾部中。
二、渐进式rehash详解
大字典扩容redis一般采用渐进式rehash操作。
首先我们要先知道两个问题。第一个就是什么叫渐进式,第二个就是为什么需要渐进式。
在我的理解下,渐进式rehash就是把一次rehash操作分成很多步进行操作,这样可以把一次性的耗时分散到其他操作的耗时上,这属于一个分治的思想。如果不采用渐进式rehash,那么一次大字典的扩容操作是需要花费很多时间的,这对于单线程的redis是很难承受这样的过程。所以干脆把一次性的耗时分散到多次、渐进式的完成。虽然这样扩容会慢一些,但是总可以完成扩容操作。
渐进式rehash大致分为四个步骤:
为 ht[1]
分配空间, 让字典同时持有 ht[0]
和 ht[1]
两个哈希表。
在字典中维持一个索引计数器变量 rehashidx
, 并将它的值设置为 0
, 表示 rehash 工作正式开始。
在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0]
哈希表在 rehashidx
索引上的所有键值对 rehash 到 ht[1]
, 当 rehash 工作完成之后, 程序将 rehashidx
属性的值增一。
随着字典操作的不断执行, 最终在某个时间点上, ht[0]
的所有键值对都会被 rehash 至 ht[1]
, 这时程序将 rehashidx
属性的值设为 -1
, 表示 rehash 操作已完成。
渐进式的过程如下图所示:
dict | type | privdata | ht | rehashidx \n -1 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 4 | sizemask \n 3 | used \n 4"]; dictht1 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 0"]; table0 [label = " dictEntry*[4] | <0> 0 | <1> 1 | <2> 2 | <3> 3 "]; table1 [label = " dictEntry*[8] | <0> 0 | <1> 1 | <2> 2 | ... | <7> 7 "]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1:head; table0:0 -> kv2:head -> null0; table0:1 -> kv0:head -> null1; table0:2 -> kv3:head -> null2; table0:3 -> kv1:head -> null3; table1:0 -> null10; table1:1 -> null11; table1:2 -> null12; table1:7 -> null17; }" class="has" src="http://img.e-com-net.com/image/info8/65c6a2e068d545749bdd6d5353d61f2b.jpg" width="0" height="0">
dict | type | privdata | ht | rehashidx \n 0 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 4 | sizemask \n 3 | used \n 3"]; dictht1 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 1"]; table0 [label = " dictEntry*[4] | <0> 0 | <1> 1 | <2> 2 | <3> 3 "]; table1 [label = " dictEntry*[8] | ... | <4> 4 | ... "]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1:head; table0:0 -> null0; table0:1 -> kv0:head -> null1; table0:2 -> kv3:head -> null2; table0:3 -> kv1:head -> null3; table1:4 -> kv2:head -> null14 }" class="has" src="http://img.e-com-net.com/image/info8/3f9d6e65caf44c95959b217b5587aaff.jpg" width="0" height="0">
dict | type | privdata | ht | rehashidx \n 1 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 4 | sizemask \n 3 | used \n 2"]; dictht1 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 2"]; table0 [label = " dictEntry*[4] | <0> 0 | <1> 1 | <2> 2 | <3> 3 "]; table1 [label = " dictEntry*[8] | ... | <4> 4 | <5> 5 | ... "]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1:head; table0:0 -> null0; table0:1 -> null1; table0:2 -> kv3:head -> null2; table0:3 -> kv1:head -> null3; table1:4 -> kv2:head -> null14 table1:5 -> kv0:head -> null15; }" class="has" src="http://img.e-com-net.com/image/info8/2bf31e323ad34fbd8111a4386e35f590.jpg" width="0" height="0">
dict | type | privdata | ht | rehashidx \n 2 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 4 | sizemask \n 3 | used \n 1"]; dictht1 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 3"]; table0 [label = " dictEntry*[4] | <0> 0 | <1> 1 | <2> 2 | <3> 3 "]; table1 [label = " dictEntry*[8] | ... | <1> 1 | ... | <4> 4 | <5> 5 | ... "]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1:head; table0:0 -> null0; table0:1 -> null1; table0:2 -> null2; table0:3 -> kv1:head -> null3; table1:1 -> kv3:head -> null11; table1:4 -> kv2:head -> null14 table1:5 -> kv0:head -> null15; }" class="has" src="http://img.e-com-net.com/image/info8/35097ec231cc466ab6a9b713652e9cc3.jpg" width="0" height="0">
dict | type | privdata | ht | rehashidx \n 3 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 4 | sizemask \n 3 | used \n 0"]; dictht1 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 4"]; table0 [label = " dictEntry*[4] | <0> 0 | <1> 1 | <2> 2 | <3> 3 "]; table1 [label = " dictEntry*[8] | ... | <1> 1 | ... | <4> 4 | <5> 5 | ... | <7> 7 "]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1:head; table0:0 -> null0; table0:1 -> null1; table0:2 -> null2; table0:3 -> null3; table1:1 -> kv3:head -> null11; table1:4 -> kv2:head -> null14 table1:5 -> kv0:head -> null15; table1:7 -> kv1:head -> null17; }" class="has" src="http://img.e-com-net.com/image/info8/329ba5b0f63347fd91252a0d1bef7cf0.jpg" width="0" height="0">
dict | type | privdata | ht | rehashidx \n -1 "]; // 哈希表 dictht0 [label = " dictht | table | size \n 8 | sizemask \n 7 | used \n 4"]; dictht1 [label = " dictht | table | size \n 0 | sizemask \n 0 | used \n 0"]; table0 [label = " dictEntry*[8] | ... | <1> 1 | ... | <4> 4 | <5> 5 | ... | <7> 7 "]; table1 [label = "NULL", shape = plaintext]; // 哈希表节点 kv0 [label = " dictEntry | { k0 | v0 } "]; kv1 [label = " dictEntry | { k1 | v1 } "]; kv2 [label = " dictEntry | { k2 | v2 } "]; kv3 [label = " dictEntry | { k3 | v3 } "]; // node [shape = plaintext, label = "NULL"]; // dict:ht -> dictht0:head [label = "ht[0]"]; dict:ht -> dictht1:head [label = "ht[1]"]; dictht0:table -> table0:head; dictht1:table -> table1; table0:1 -> kv3:head -> null11; table0:4 -> kv2:head -> null14; table0:5 -> kv0:head -> null15; table0:7 -> kv1:head -> null17; }" class="has" src="http://img.e-com-net.com/image/info8/de107f39f8904feb94b0a20c6f3aaefa.jpg" width="0" height="0">
渐进是把hash操作分散到对字典的增加、删除、修改等操作上的。那么如果对于一个正在发生rehash操作的字典,我需要查找到该字典的某一个元素该怎么办?首先我会在h[0]进行查找,如果在h[0]找不到的话则再去h[1]上进行查找。
在增加操作中的增加的元素都一律保存在新表h[1]当中,这将意味着一旦发生扩容操作h[0]的值是不会改变的。
如果在搬迁的过程中并没有对字典进行操作那怎么办?是否就意味着不会进行rehash操作了?当然不是。如果字典后面没有进行操作的话,redis还有一个定时器任务,redis将会在定时器任务中对字典进行搬迁操作
三、hash攻击
hashtable中key的分布的均匀程度影响到redis的性能,但是如果一个hash函数存在偏向性,那么黑客可以利用这个偏向性对服务器进行攻击,使得key的分布堆积在某一个数组当中,这样会使得链表非常的长,导致查找的效率下降,可能查询的时间复杂度退化到O(n)级别,这样服务器很容易崩溃,这就是hash攻击。
四、扩容条件
当hash表中元素的个数等于数组长度的时候将会进行扩容操作,扩容的大小为原来数组的2倍。不过如果redis正在做bgsave操作为了加少过多的内存页分离(COW操作),redis此时尽量不会去扩容。如果hash表中的元素长度为数组长度的5倍以上,将会进行强制扩容。
五、缩容条件
当hash表进行删除操作,元素个数低于数组长度的10%,将会进行缩容操作。缩容操作不会考虑redis是否在进行bgsava操作。
参考:http://redisbook.com/preview/dict/incremental_rehashing.html
你可能感兴趣的:(redis,java)
Long类型前后端数据不一致
igotyback
前端
响应给前端的数据浏览器控制台中response中看到的Long类型的数据是正常的到前端数据不一致前后端数据类型不匹配是一个常见问题,尤其是当后端使用Java的Long类型(64位)与前端JavaScript的Number类型(最大安全整数为2^53-1,即16位)进行数据交互时,很容易出现精度丢失的问题。这是因为JavaScript中的Number类型无法安全地表示超过16位的整数。为了解决这个问
LocalDateTime 转 String
igotyback
java 开发语言
importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassMain{publicstaticvoidmain(String[]args){//获取当前时间LocalDateTimenow=LocalDateTime.now();//定义日期格式化器DateTimeFormatterformat
Linux下QT开发的动态库界面弹出操作(SDL2)
13jjyao
QT类 qt 开发语言 sdl2 linux
需求:操作系统为linux,开发框架为qt,做成需带界面的qt动态库,调用方为java等非qt程序难点:调用方为java等非qt程序,也就是说调用方肯定不带QApplication::exec(),缺少了这个,QTimer等事件和QT创建的窗口将不能弹出(包括opencv也是不能弹出);这与qt调用本身qt库是有本质的区别的思路:1.调用方缺QApplication::exec(),那么我们在接口
DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理
STU学生网页设计
网页设计 期末网页作业 html静态网页 html5期末大作业 网页设计 web大作业
️精彩专栏推荐作者主页:【进入主页—获取更多源码】web前端期末大作业:【HTML5网页期末作业(1000套)】程序员有趣的告白方式:【HTML七夕情人节表白网页制作(110套)】文章目录二、网站介绍三、网站效果▶️1.视频演示2.图片演示四、网站代码HTML结构代码CSS样式代码五、更多源码二、网站介绍网站布局方面:计划采用目前主流的、能兼容各大主流浏览器、显示效果稳定的浮动网页布局结构。网站程
【华为OD机试真题2023B卷 JAVA&JS】We Are A Team
若博豆
java 算法 华为 javascript
华为OD2023(B卷)机试题库全覆盖,刷题指南点这里WeAreATeam时间限制:1秒|内存限制:32768K|语言限制:不限题目描述:总共有n个人在机房,每个人有一个标号(1<=标号<=n),他们分成了多个团队,需要你根据收到的m条消息判定指定的两个人是否在一个团队中,具体的:1、消息构成为:abc,整数a、b分别代
关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript
二挡起步
web前端期末大作业 javascript html css 旅游 风景
⛵源码获取文末联系✈Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业|游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作|HTML期末大学生网页设计作业,Web大学生网页HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScrip
HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动
二挡起步
web前端期末大作业 web设计网页规划与设计 html css javascript dreamweaver 前端
Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作HTML期末大学生网页设计作业HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScript:做与用户的交互行为文章目录前端学习路线
node.js学习
小猿L
node.js node.js 学习 vim
node.js学习实操及笔记温故node.js,node.js学习实操过程及笔记~node.js学习视频node.js官网node.js中文网实操笔记githubcsdn笔记为什么学node.js可以让别人访问我们编写的网页为后续的框架学习打下基础,三大框架vuereactangular离不开node.jsnode.js是什么官网:node.js是一个开源的、跨平台的运行JavaScript的运行
Redis系列:Geo 类型赋能亿级地图位置计算
Ly768768
redis bootstrap 数据库
1前言我们在篇深刻理解高性能Redis的本质的时候就介绍过Redis的几种基本数据结构,它是基于不同业务场景而设计的:动态字符串(REDIS_STRING):整数(REDIS_ENCODING_INT)、字符串(REDIS_ENCODING_RAW)双端列表(REDIS_ENCODING_LINKEDLIST)压缩列表(REDIS_ENCODING_ZIPLIST)跳跃表(REDIS_ENCODI
Java 重写(Override)与重载(Overload)
叨唧唧的
Java重写(Override)与重载(Overload)重写(Override)重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如:父类的一个方法申明了一个检查异常IOExceptio
简单了解 JVM
记得开心一点啊
jvm
目录♫什么是JVM♫JVM的运行流程♫JVM运行时数据区♪虚拟机栈♪本地方法栈♪堆♪程序计数器♪方法区/元数据区♫类加载的过程♫双亲委派模型♫垃圾回收机制♫什么是JVMJVM是JavaVirtualMachine的简称,意为Java虚拟机。虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统(如:JVM、VMwave、VirtualBox)。JVM和其他两个虚拟机
1分钟解决 -bash: mvn: command not found,在Centos 7中安装Maven
Energet!c
开发语言
1分钟解决-bash:mvn:commandnotfound,在Centos7中安装Maven检查Java环境1下载Maven2解压Maven3配置环境变量4验证安装5常见问题与注意事项6总结检查Java环境Maven依赖Java环境,请确保系统已经安装了Java并配置了环境变量。可以通过以下命令检查:java-version如果未安装,请先安装Java。1下载Maven从官网下载:前往Apach
Java企业面试题3
马龙强_
java
1.break和continue的作用(智*图)break:用于完全退出一个循环(如for,while)或一个switch语句。当在循环体内遇到break语句时,程序会立即跳出当前循环体,继续执行循环之后的代码。continue:用于跳过当前循环体中剩余的部分,并开始下一次循环。如果是在for循环中使用continue,则会直接进行条件判断以决定是否执行下一轮循环。2.if分支语句和switch分
JVM、JRE和 JDK:理解Java开发的三大核心组件
Y雨何时停T
Java java
Java是一门跨平台的编程语言,它的成功离不开背后强大的运行环境与开发工具的支持。在Java的生态中,JVM(Java虚拟机)、JRE(Java运行时环境)和JDK(Java开发工具包)是三个至关重要的核心组件。本文将探讨JVM、JDK和JRE的区别,帮助你更好地理解Java的运行机制。1.JVM:Java虚拟机(JavaVirtualMachine)什么是JVM?JVM,即Java虚拟机,是Ja
Java面试题精选:消息队列(二)
芒果不是芒
Java面试题精选 java kafka
一、Kafka的特性1.消息持久化:消息存储在磁盘,所以消息不会丢失2.高吞吐量:可以轻松实现单机百万级别的并发3.扩展性:扩展性强,还是动态扩展4.多客户端支持:支持多种语言(Java、C、C++、GO、)5.KafkaStreams(一个天生的流处理):在双十一或者销售大屏就会用到这种流处理。使用KafkaStreams可以快速的把销售额统计出来6.安全机制:Kafka进行生产或者消费的时候会
白骑士的Java教学基础篇 2.5 控制流语句
白骑士所长
Java 教学 java 开发语言
欢迎继续学习Java编程的基础篇!在前面的章节中,我们了解了Java的变量、数据类型和运算符。接下来,我们将探讨Java中的控制流语句。控制流语句用于控制程序的执行顺序,使我们能够根据特定条件执行不同的代码块,或重复执行某段代码。这是编写复杂程序的基础。通过学习这一节内容,你将掌握如何使用条件语句和循环语句来编写更加灵活和高效的代码。条件语句条件语句用于根据条件的真假来执行不同的代码块。if语句‘
python语法——三目运算符
HappyRocking
python python 三目运算符
在java中,有三目运算符,如:intc=(a>b)?a:b表示c取两者中的较大值。但是在python,不能直接这样使用,估计是因为冒号在python有分行的关键作用。那么在python中,如何实现类似功能呢?可以使用ifelse语句,也是一行可以完成,格式为:aifbelsec表示如果b为True,则表达式等于a,否则等于c。如:c=(aif(a>b)elseb)同样是完成了取最大值的功能。
ArrayList 源码解析
程序猿进阶
Java基础 ArrayList List java 面试 性能优化 架构设计 idea
ArrayList是Java集合框架中的一个动态数组实现,提供了可变大小的数组功能。它继承自AbstractList并实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量capacity,表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添
Java爬虫框架(一)--架构设计
狼图腾-狼之传说
java 框架 java 任务 html解析器 存储 电子商务
一、架构图那里搜网络爬虫框架主要针对电子商务网站进行数据爬取,分析,存储,索引。爬虫:爬虫负责爬取,解析,处理电子商务网站的网页的内容数据库:存储商品信息索引:商品的全文搜索索引Task队列:需要爬取的网页列表Visited表:已经爬取过的网页列表爬虫监控平台:web平台可以启动,停止爬虫,管理爬虫,task队列,visited表。二、爬虫1.流程1)Scheduler启动爬虫器,TaskMast
Java:爬虫框架
dingcho
Java java 爬虫
一、ApacheNutch2【参考地址】Nutch是一个开源Java实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。Nutch致力于让每个人能很容易,同时花费很少就可以配置世界一流的Web搜索引擎.为了完成这一宏伟的目标,Nutch必须能够做到:每个月取几十亿网页为这些网页维护一个索引对索引文件进行每秒上千次的搜索提供高质量的搜索结果简单来说Nutch支持分
python怎么将png转为tif_png转tif
weixin_39977276
发国外的文章要求图片是tif,cmyk色彩空间的。大小尺寸还有要求。比如网上大神多,找到了一段代码,感谢!https://www.jianshu.com/p/ec2af4311f56https://github.com/KevinZc007/image2Tifimportjava.awt.image.BufferedImage;importjava.io.File;importjava.io.Fi
JavaScript 中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)
跳房子的前端
前端面试 javascript 开发语言 ecmascript
在JavaScript中,深拷贝(DeepCopy)和浅拷贝(ShallowCopy)是用于复制对象或数组的两种不同方法。了解它们的区别和应用场景对于避免潜在的bugs和高效地处理数据非常重要。以下是对深拷贝和浅拷贝的详细解释,包括它们的概念、用途、优缺点以及实现方式。1.浅拷贝(ShallowCopy)概念定义:浅拷贝是指创建一个新的对象或数组,其中包含了原对象或数组的基本数据类型的值和对引用数
JAVA·一个简单的登录窗口
MortalTom
java 开发语言 学习
文章目录概要整体架构流程技术名词解释技术细节资源概要JavaSwing是Java基础类库的一部分,主要用于开发图形用户界面(GUI)程序整体架构流程新建项目,导入sql.jar包(链接放在了文末),编译项目并运行技术名词解释一、特点丰富的组件提供了多种可视化组件,如按钮(JButton)、文本框(JTextField)、标签(JLabel)、下拉列表(JComboBox)等,可以满足不同的界面设计
WebMagic:强大的Java爬虫框架解析与实战
Aaron_945
Java java 爬虫 开发语言
文章目录引言官网链接WebMagic原理概述基础使用1.添加依赖2.编写PageProcessor高级使用1.自定义Pipeline2.分布式抓取优点结论引言在大数据时代,网络爬虫作为数据收集的重要工具,扮演着不可或缺的角色。Java作为一门广泛使用的编程语言,在爬虫开发领域也有其独特的优势。WebMagic是一个开源的Java爬虫框架,它提供了简单灵活的API,支持多线程、分布式抓取,以及丰富的
博客网站制作教程
2401_85194651
java maven
首先就是技术框架:后端:Java+SpringBoot数据库:MySQL前端:Vue.js数据库连接:JPA(JavaPersistenceAPI)1.项目结构blog-app/├──backend/│├──src/main/java/com/example/blogapp/││├──BlogApplication.java││├──config/│││└──DatabaseConfig.java
00. 这里整理了最全的爬虫框架(Java + Python)
有一只柴犬
爬虫系列 爬虫 java python
目录1、前言2、什么是网络爬虫3、常见的爬虫框架3.1、java框架3.1.1、WebMagic3.1.2、Jsoup3.1.3、HttpClient3.1.4、Crawler4j3.1.5、HtmlUnit3.1.6、Selenium3.2、Python框架3.2.1、Scrapy3.2.2、BeautifulSoup+Requests3.2.3、Selenium3.2.4、PyQuery3.2
JAVA学习笔记之23种设计模式学习
victorfreedom
Java技术 设计模式 android java 常用设计模式
博主最近买了《设计模式》这本书来学习,无奈这本书是以C++语言为基础进行说明,整个学习流程下来效率不是很高,虽然有的设计模式通俗易懂,但感觉还是没有充分的掌握了所有的设计模式。于是博主百度了一番,发现有大神写过了这方面的问题,于是博主迅速拿来学习。一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种:适配器
JavaScript `Map` 和 `WeakMap`详细解释
跳房子的前端
JavaScript 原生方法 javascript 前端 开发语言
在JavaScript中,Map和WeakMap都是用于存储键值对的数据结构,但它们有一些关键的不同之处。MapMap是一种可以存储任意类型的键值对的集合。它保持了键值对的插入顺序,并且可以通过键快速查找对应的值。Map提供了一些非常有用的方法和属性来操作这些数据对:set(key,value):将一个键值对添加到Map中。如果键已经存在,则更新其对应的值。get(key):获取指定键的值。如果键
华为云分布式缓存服务DCS 8月新特性发布
华为云PaaS服务小智
华为云 分布式 缓存
分布式缓存服务(DistributedCacheService,简称DCS)是华为云提供的一款兼容Redis的高速内存数据处理引擎,为您提供即开即用、安全可靠、弹性扩容、便捷管理的在线分布式缓存能力,满足用户高并发及数据快速访问的业务诉求。此次为大家带来DCS8月的特性更新内容,一起来看看吧!
切换淘宝最新npm镜像源是
hai40587
npm 前端 node.js
切换淘宝最新npm镜像源是一个相对简单的过程,但首先需要明确当前淘宝npm镜像源的状态和最新的镜像地址。由于网络环境和服务更新,镜像源的具体地址可能会发生变化,因此,我将基于当前可获取的信息,提供一个通用的切换步骤,并附上最新的镜像地址(截至回答时)。一、了解npm镜像源npm(NodePackageManager)是JavaScript的包管理器,用于安装、更新和管理项目依赖。由于npm官方仓库
Spring的注解积累
yijiesuifeng
spring 注解
用注解来向Spring容器注册Bean。
需要在applicationContext.xml中注册:
<context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>。
如:在base-package指明一个包
<context:component-sc
传感器
百合不是茶
android 传感器
android传感器的作用主要就是来获取数据,根据得到的数据来触发某种事件
下面就以重力传感器为例;
1,在onCreate中获得传感器服务
private SensorManager sm;// 获得系统的服务
private Sensor sensor;// 创建传感器实例
@Override
protected void
[光磁与探测]金吕玉衣的意义
comsci
这是一个古代人的秘密:现在告诉大家
信不信由你们:
穿上金律玉衣的人,如果处于灵魂出窍的状态,可以飞到宇宙中去看星星
这就是为什么古代
精简的反序打印某个数
沐刃青蛟
打印
以前看到一些让求反序打印某个数的程序。
比如:输入123,输出321。
记得以前是告诉你是几位数的,当时就抓耳挠腮,完全没有思路。
似乎最后是用到%和/方法解决的。
而今突然想到一个简短的方法,就可以实现任意位数的反序打印(但是如果是首位数或者尾位数为0时就没有打印出来了)
代码如下:
long num, num1=0;
PHP:6种方法获取文件的扩展名
IT独行者
PHP 扩展名
PHP:6种方法获取文件的扩展名
1、字符串查找和截取的方法
1
$extension
=
substr
(
strrchr
(
$file
,
'.'
), 1);
2、字符串查找和截取的方法二
1
$extension
=
substr
面试111
文强chu
面试
1事务隔离级别有那些 ,事务特性是什么(问到一次)
2 spring aop 如何管理事务的,如何实现的。动态代理如何实现,jdk怎么实现动态代理的,ioc是怎么实现的,spring是单例还是多例,有那些初始化bean的方式,各有什么区别(经常问)
3 struts默认提供了那些拦截器 (一次)
4 过滤器和拦截器的区别 (频率也挺高)
5 final,finally final
XML的四种解析方式
小桔子
dom jdom dom4j sax
在平时工作中,难免会遇到把 XML 作为数据存储格式。面对目前种类繁多的解决方案,哪个最适合我们呢?在这篇文章中,我对这四种主流方案做一个不完全评测,仅仅针对遍历 XML 这块来测试,因为遍历 XML 是工作中使用最多的(至少我认为)。 预 备 测试环境: AMD 毒龙1.4G OC 1.5G、256M DDR333、Windows2000 Server
wordpress中常见的操作
aichenglong
中文注册 wordpress 移除菜单
1 wordpress中使用中文名注册解决办法
1)使用插件
2)修改wp源代码
进入到wp-include/formatting.php文件中找到
function sanitize_user( $username, $strict = false
小飞飞学管理-1
alafqq
管理
项目管理的下午题,其实就在提出问题(挑刺),分析问题,解决问题。
今天我随意看下10年上半年的第一题。主要就是项目经理的提拨和培养。
结合我自己经历写下心得
对于公司选拔和培养项目经理的制度有什么毛病呢?
1,公司考察,选拔项目经理,只关注技术能力,而很少或没有关注管理方面的经验,能力。
2,公司对项目经理缺乏必要的项目管理知识和技能方面的培训。
3,公司对项目经理的工作缺乏进行指
IO输入输出部分探讨
百合不是茶
IO
//文件处理 在处理文件输入输出时要引入java.IO这个包;
/*
1,运用File类对文件目录和属性进行操作
2,理解流,理解输入输出流的概念
3,使用字节/符流对文件进行读/写操作
4,了解标准的I/O
5,了解对象序列化
*/
//1,运用File类对文件目录和属性进行操作
//在工程中线创建一个text.txt
getElementById的用法
bijian1013
element
getElementById是通过Id来设置/返回HTML标签的属性及调用其事件与方法。用这个方法基本上可以控制页面所有标签,条件很简单,就是给每个标签分配一个ID号。
返回具有指定ID属性值的第一个对象的一个引用。
语法:
&n
励志经典语录
bijian1013
励志 人生
经典语录1:
哈佛有一个著名的理论:人的差别在于业余时间,而一个人的命运决定于晚上8点到10点之间。每晚抽出2个小时的时间用来阅读、进修、思考或参加有意的演讲、讨论,你会发现,你的人生正在发生改变,坚持数年之后,成功会向你招手。不要每天抱着QQ/MSN/游戏/电影/肥皂剧……奋斗到12点都舍不得休息,看就看一些励志的影视或者文章,不要当作消遣;学会思考人生,学会感悟人生
[MongoDB学习笔记三]MongoDB分片
bit1129
mongodb
MongoDB的副本集(Replica Set)一方面解决了数据的备份和数据的可靠性问题,另一方面也提升了数据的读写性能。MongoDB分片(Sharding)则解决了数据的扩容问题,MongoDB作为云计算时代的分布式数据库,大容量数据存储,高效并发的数据存取,自动容错等是MongoDB的关键指标。
本篇介绍MongoDB的切片(Sharding)
1.何时需要分片
&nbs
【Spark八十三】BlockManager在Spark中的使用场景
bit1129
manager
1. Broadcast变量的存储,在HttpBroadcast类中可以知道
2. RDD通过CacheManager存储RDD中的数据,CacheManager也是通过BlockManager进行存储的
3. ShuffleMapTask得到的结果数据,是通过FileShuffleBlockManager进行管理的,而FileShuffleBlockManager最终也是使用BlockMan
yum方式部署zabbix
ronin47
yum方式部署zabbix
安装网络yum库#rpm -ivh http://repo.zabbix.com/zabbix/2.4/rhel/6/x86_64/zabbix-release-2.4-1.el6.noarch.rpm 通过yum装mysql和zabbix调用的插件还有agent代理#yum install zabbix-server-mysql zabbix-web-mysql mysql-
Hibernate4和MySQL5.5自动创建表失败问题解决方法
byalias
J2EE Hibernate4
今天初学Hibernate4,了解了使用Hibernate的过程。大体分为4个步骤:
①创建hibernate.cfg.xml文件
②创建持久化对象
③创建*.hbm.xml映射文件
④编写hibernate相应代码
在第四步中,进行了单元测试,测试预期结果是hibernate自动帮助在数据库中创建数据表,结果JUnit单元测试没有问题,在控制台打印了创建数据表的SQL语句,但在数据库中
Netty源码学习-FrameDecoder
bylijinnan
java netty
Netty 3.x的user guide里FrameDecoder的例子,有几个疑问:
1.文档说:FrameDecoder calls decode method with an internally maintained cumulative buffer whenever new data is received.
为什么每次有新数据到达时,都会调用decode方法?
2.Dec
SQL行列转换方法
chicony
行列转换
create table tb(终端名称 varchar(10) , CEI分值 varchar(10) , 终端数量 int)
insert into tb values('三星' , '0-5' , 74)
insert into tb values('三星' , '10-15' , 83)
insert into tb values('苹果' , '0-5' , 93)
中文编码测试
ctrain
编码
循环打印转换编码
String[] codes = {
"iso-8859-1",
"utf-8",
"gbk",
"unicode"
};
for (int i = 0; i < codes.length; i++) {
for (int j
hive 客户端查询报堆内存溢出解决方法
daizj
hive 堆内存溢出
hive> select * from t_test where ds=20150323 limit 2;
OK
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
问题原因: hive堆内存默认为256M
这个问题的解决方法为:
修改/us
人有多大懒,才有多大闲 (评论『卓有成效的程序员』)
dcj3sjt126com
程序员
卓有成效的程序员给我的震撼很大,程序员作为特殊的群体,有的人可以这么懒, 懒到事情都交给机器去做 ,而有的人又可以那么勤奋,每天都孜孜不倦得做着重复单调的工作。
在看这本书之前,我属于勤奋的人,而看完这本书以后,我要努力变成懒惰的人。
不要在去庞大的开始菜单里面一项一项搜索自己的应用程序,也不要在自己的桌面上放置眼花缭乱的快捷图标
Eclipse简单有用的配置
dcj3sjt126com
eclipse
1、显示行号 Window -- Prefences -- General -- Editors -- Text Editors -- show line numbers
2、代码提示字符 Window ->Perferences,并依次展开 Java -> Editor -> Content Assist,最下面一栏 auto-Activation
在tomcat上面安装solr4.8.0全过程
eksliang
Solr solr4.0后的版本安装 solr4.8.0安装
转载请出自出处:
http://eksliang.iteye.com/blog/2096478
首先solr是一个基于java的web的应用,所以安装solr之前必须先安装JDK和tomcat,我这里就先省略安装tomcat和jdk了
第一步:当然是下载去官网上下载最新的solr版本,下载地址
Android APP通用型拒绝服务、漏洞分析报告
gg163
漏洞 android APP 分析
点评:记得曾经有段时间很多SRC平台被刷了大量APP本地拒绝服务漏洞,移动安全团队爱内测(ineice.com)发现了一个安卓客户端的通用型拒绝服务漏洞,来看看他们的详细分析吧。
0xr0ot和Xbalien交流所有可能导致应用拒绝服务的异常类型时,发现了一处通用的本地拒绝服务漏洞。该通用型本地拒绝服务可以造成大面积的app拒绝服务。
针对序列化对象而出现的拒绝服务主要
HoverTree项目已经实现分层
hvt
编程 .net Web C# ASP.ENT
HoverTree项目已经初步实现分层,源代码已经上传到 http://hovertree.codeplex.com请到SOURCE CODE查看。在本地用SQL Server 2008 数据库测试成功。数据库和表请参考:http://keleyi.com/a/bjae/ue6stb42.htmHoverTree是一个ASP.NET 开源项目,希望对你学习ASP.NET或者C#语言有帮助,如果你对
Google Maps API v3: Remove Markers 移除标记
天梯梦
google maps api
Simply do the following:
I. Declare a global variable:
var markersArray = [];
II. Define a function:
function clearOverlays() {
for (var i = 0; i < markersArray.length; i++ )
jQuery选择器总结
lq38366
jquery 选择器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
基础数据结构和算法六:Quick sort
sunwinner
Algorithm Quicksort
Quick sort is probably used more widely than any other. It is popular because it is not difficult to implement, works well for a variety of different kinds of input data, and is substantially faster t
如何让Flash不遮挡HTML div元素的技巧_HTML/Xhtml_网页制作
刘星宇
html Web
今天在写一个flash广告代码的时候,因为flash自带的链接,容易被当成弹出广告,所以做了一个div层放到flash上面,这样链接都是a触发的不会被拦截,但发现flash一直处于div层上面,原来flash需要加个参数才可以。
让flash置于DIV层之下的方法,让flash不挡住飘浮层或下拉菜单,让Flash不档住浮动对象或层的关键参数:wmode=opaque。
方法如下:
Mybatis实用Mapper SQL汇总示例
wdmcygah
sql mysql mybatis 实用
Mybatis作为一个非常好用的持久层框架,相关资料真的是少得可怜,所幸的是官方文档还算详细。本博文主要列举一些个人感觉比较常用的场景及相应的Mapper SQL写法,希望能够对大家有所帮助。
不少持久层框架对动态SQL的支持不足,在SQL需要动态拼接时非常苦恼,而Mybatis很好地解决了这个问题,算是框架的一大亮点。对于常见的场景,例如:批量插入/更新/删除,模糊查询,多条件查询,联表查询,