Redis高级数据结构原理解析-bitmap,hyperloglog

Redis 位图

  • 开发过程中,我们可能遇到这种场景记录用户的打卡情况,签到情况,这些场景只有两种结果,有或者没有,加入记录的数据量比较大,比如用一年的数据,如果用Redis中普通key/value,每个用户要记录365个,当用户上亿时候,需要的存储就比较多了。Redis为解决这种勤快提供了位图的数据结构,这样一条数据在位图中只需要占用1位,365天就是365位,一个字节8位,你们就是46个字节左右,这样大大节省空间,位图的最小单位是bit,每个bit只能取1或者0.
    在这里插入图片描述
  • 位图在Redis中就是普通字符串,也就是byte数组。可以通过Redis命令get/set直接获取,和设置整个位图的内容,也可以使用getbit/setbit 等将byte看出位数组操作某一个位。
基本用法
  • Redis中提供位图的统计指令bitcount和位图查找指令bitpos, bitcount统计指定范围内1 个数,bitpos查找指定范围内出现的第一个0或者1。
  • 还是签到的案例,我们通过bitcount统计用户一共签到多少天,通过bitpos查找从那一天开始签到的。还可以指定范围参数[start, end],可以统计某个时间范围内用户签到多少天。
  • 注意此处的start,end是字节的索引,也就是说指定的范围必须是8的倍数(1字节=8位),不能任意指定。如下案例
新docker-redis:0>get w
"hello"
新docker-redis:0>bitcount w
"21"
新docker-redis:0>bitcount w 0 0 // 第一个字符中1 的位数
"3"
新docker-redis:0>bitcount w 0 1//前两个字符中1 的位数
"7"
新docker-redis:0>bitpos w 0 //第一个0 位
"0"
新docker-redis:0>bitpos w 1//第一个1 位
"1"
特殊的bitfield
  • Redis中setbit, getbit指定的值都是单个位的,如果要一次操作多个位,就必须使用管道处理。Redis3.2 之后增加了一个强大的指令bitfield,可以一次性处理多个位操作。
  • bitfield 有三个基本指令,get,set, incrby,可以对指定位片段进行读写,但最多只能处理64个连续位,如果超过64个,就得使用多个子指令,bitfield可以一次执行多个指令。如下是h,e两个字符的bit位示意图:
    在这里插入图片描述
新docker-redis:0>set w hello
"OK"
新docker-redis:0>bitfield w get u4 0 //从第一位开始取4个位,结果是无符号数u1)  "6"
新docker-redis:0>bitfield w get u3 2 //从第三个位开始取3个位,结果是无符号数u1)  "5"
新docker-redis:0>bitfield w get i4 0 //从第一位开始取4个位,结果有符号数i (0-正 1-负)1)  "6"
新docker-redis:0>bitfield w get i3 2 //从第三位开始取3个位,结果是有符号i1)  "-3"
  • 如上结果中,有符号以上是第一个是按符号位算,其他的才是值,符号为0-正 1-负,无符号标识非负数,没有符合为,获取到的位全是数值。有符号数最多获取64位,无符号只能获取63位,因为Redis协议中的integer是有符号数,最大64位,符号位占用一位,所以只有63位数据位,如果超出限制,会提示参数错误。一次性执行多个指令:
127.0.0.1:6379> bitfield w get u4 0 get u3 2 get i4 0 get i3 2
1) (integer) 6
2) (integer) 5
3) (integer) 6
4) (integer) -3
  • bitfielt提供单个字节替换的功能,因为1字节=8为,我们可以替换其中的一个8 位bit符来达到操作字节的目的,如下面这个案例我们将hello中的第二个字符替换成hallo:
127.0.0.1:6379> get w
"hello"
127.0.0.1:6379> bitfield w set u8 8 97 // 从第九位开始替换一个8bit的字节,用97替换
1) (integer) 101
127.0.0.1:6379> get w
"hallo"
  • 同样的bitmap中也有自增命令incrby,用来对指定范围的位进行自增操作,因为自增的时候就可能出现数据溢出的风险,Redis中默认是折返处理,比如溢出后将溢出符号为丢弃,如果8位无符号255,加1 溢出变成0 也就是向上近位 1111 1111 变成1 0000 0000但是只有8 位所以第一位1 被舍弃,变成最后的0 。
  • bitfield指令提供溢出的操作行为默认是折返(wrap),还可以失败(fail)就是报错不执行,饱和截断(sat)超过范围停留在最大值比如255 +1 = 255,如下三个案例:
//越界情况
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w incrby u4 2 2 //从第三位开始,对接下来4位无符号数+1
1) (integer) 12
127.0.0.1:6379> bitfield w incrby u4 2 2
1) (integer) 14
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w incrby u4 2 1 // 越界,变为0 
1) (integer) 0//饱和截断情况
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 2
1) (integer) 12
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 2
1) (integer) 14
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 15//失败情况:
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 3
1) (integer) 13
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 2
1) (integer) 15
127.0.0.1:6379> bitfield w overflow fail incrby u4 2 1
1) (nil)

Redis HyperLogLog

-Java web开发过程中经常需要统计网页的UV,这个我们怎么实现,之前我们统计PV只需要给每个网页分配一个Redis计数器就可以,将key后缀加上日期,每天一个,每次请求incrby就行。但是UV需要区分不同的用户,最笨的办法是每个也没分配一个set集合,用来存储访问的用户ID,但是这个方式是非常消耗内存的,当有热点也没达到百万兵法时候,当有N个热点也没时候,那内存消耗将会是一个非常大的数量,Redis中HyperLogLog引入来一个新的解决方案,提供来不精确的去重计数方案,虽然不精确但是标准误差也就0.81%而已,对于统计UV的这种业务场景是完全能够接受的。

HyperLogLog使用方式
127.0.0.1:6379> pfadd code userq
(integer) 1
127.0.0.1:6379> pfadd code user1
(integer) 1
127.0.0.1:6379> pfcount code
(integer) 2
  • 如上,Redis中HyperLogLog提供pfadd,pfcount,一个增加,一个统计,我们试了一把,统计没有误差,我们执行100000 次add操作来测试他的误差以及性能
public class HypLogLogDemo {public static final String key = "code";public static void main(String[] args) {Jedis jedis = JedisUtils.getJedis();for (int i = 0; i < 100000; i++) {jedis.pfadd(key, "user" + i);}long total = jedis.pfcount(key);System.out.println(total);}
}
//输出:99715
  • 如上结果相差285个按照0.285%的误差,对于UV的统计需求误差可以忽略,我们可以多次重复执行,其实还是得到近似的结果,说明他有去重的功能。
pfmerge
  • HypLogLog除了提供上面的两个命令还有一个merge功能,用于将多个计数器累加成一个新的pf值
  • 比如多个内容相似的网页,运营需要合并统计,就可以用这个来统计。
  • HyperLogLog这个数据结构占用内存异常的小,只需要占用12KB内存,如果统计的计数有亿级别,那么对空间的节省是非常令人惊讶的
存储原理
  • HypLogLog有以下几个特点:

    • 实现比较困难
    • 能够用极少的内存来统计巨量的数据,在Redis中实现的HyperLogLog,只需要12k内存就能统计2^64个数据
    • 计数存在一定的误差0.81%
    • 误差可以被设置辅助计算因子进行降低
  • 12K是一个什么概念,1byte=8bit,long类型是8字节64bit,对应2^63-1 个数,那假设有这么多个数,从0 ~ 2 ^ 63-1,按照long以及1k=1026字节内存总数应该是((2 ^ 63-1) * 8.1024)K,这个远远超过来12k。

伯努力试验
  • HyperLogLog用极少内存完成巨量数据计算,我们先需要了解他的数学原理:伯努利试验(概率论)
  • 抛硬币一次得到正反概率都是50%,假设一直抛硬币,一直到得到一次正面,记这位一次完整试验,期间记录抛硬币的次数,这个试验就是伯努利试验;
  • 对于多次伯努利试验,假设多次为n次,每次试验抛次数为K(抛K次得到正面),因此第一次k1, 依次类推,第n次kn
  • 期间必然在n次试验中有一个最大抛次数k,我们称为k_max。
  • 伯努利试验容易得出如下结论
    • n次伯努利过程抛次数不大于k_max
    • n次伯努利过程至少依次k_max
  • 结合极大似然估算方法,可以发现n和k_max的估算关联: n = 2^(k_max),这种估算方法需要用概率论和数理统计方法推导证明,此处略过。
第一次试验: 抛了3次才出现正面,此时 k=3,n=1
第二次试验: 抛了2次才出现正面,此时 k=2,n=2
第三次试验: 抛了6次才出现正面,此时 k=6,n=3
第n 次试验:抛了12次才出现正面,此时我们估算, n = 2^12
  • 如上试验,共三组,k_max=6,n=3,代如公式3 != 2^6。此处只能说明样本太少,估算误差大。
估算优化
  • 我们假设上面3次试验算一轮,当n足够大,估算误差才小,例如我们进行100 轮,然后每一轮取出k_max,在取出平均数即:k_max/100,在估算数n,下面是LogLog的估算公式:
    在这里插入图片描述
  • 上面公式中DVLL对于的是n,contant是修正因子,具体值不定,可以根据时间情况分钟设置,m代表试验轮次,头上有一横的R就是平均数:(k_max_1+…+k_max_n)/m。
  • 这种通过增加试验次数在取k_max平均数的算法优化就是LogLog的做法,而HyperLogLog和LogLoe有一点区别,不是用平均数,而是调和平均数,相对平均数更不容易受到大数的影响。如下案例
A月薪1000,B月薪30000
平均数:(1000+30000)/2=15500
调和平均数:2/(1/1000 + 1/30000) ~ 1935.484
  • 显然,调和平均数比平均数更准确表达事实情况,下面是调和平均数的计算方式,∑ 是累加符号:
    在这里插入图片描述
  • 以上其实就是他的数学原理。
带入实际案例讲解
  • 上面的内容中通过抛硬币的案例解释了伯努利实验通过k_max来估算n,那么这种估算方法和我们UV统计方式有什么关联,我们需求是统计APP或者网页的一个页面,每天有多少个不同的用户点击进入的次数。同一个用户的反复点击进入记为1。HyperLogLog是按如下几个步骤操作:
  1. 获取比特串
  • 通过Hash函数,将数据转为比特串,比如,输入一个用户id=5,我们转成101,通过这种方式将访问用户数据和上面的抛硬币对应上,比特串中,0 代表反面,1 代表正面,如果一个数据最终被转成10010000,那么按照从右到左,从低位到高位看,我们认为首次出现1 的时候代表正面。
  • 基于上面的估算结论,我们可以通过多次试验的最大抛到正面的次数来预估总共进行了多少次实验,同样更具存储的数据中,转化后出现了1 的最大值k_max来估算出总量n。
  1. 分桶存储
  • 分桶就是分开进行多轮次。抽象到计算机中存储,可以看成是一个以单位是bit,长度是L的大的数组S,将S平均分成M组,这里的M其实就是对应多少轮,然后每组锁占有的比特个数是平均的,设为P,我们可以得出以下公式
    • L = S.length
    • L = M * P
    • 以K为单位,S占用内存= L / 8 / 1024
  • 在Redis中,HyperLogLog设置为: m=16834,p=6,L=168346。占用内存为168346/8/1024 = 12K
  • 如下示意来标识他存储的结构:
0组     第1组      第2组     第3....16833[000 000] [000 000] [000 000] [000 000] .... [000 000]
  1. 对应存储规则
  • 我们回到原始APP页面统计的具体问题中,设APP主页的key为:main, 用户id:idn, n->0,1,2,3 …
  • 在这个统计问题中,不同用户id标识了一个用户,你们我们可以把用户id作为被hash的输入:hash(id) = 比特串
  • 不同的用户id必然有不同比特串,每一个比特串,也必然至少出现一次1 的位置,我们类比每一个比特串就是一次伯努利试验
  • 现在要分轮次,即分桶存储,设定每个比特串钱w位转为10进制后,其值就对应于所在的桶的下标(1~16833)。假设比特串的低两位用来计算桶下标,此时有一个用户id的比特串是:1001 0110 0001 1,他的下标为 11(二进制) = 12 ^ 0 + 12 ^ 1 = 3,处于第三个桶。即第三轮
  • 上面案例中,计算桶号后,剩下的比特串: 1001 0110 000, 从低位到高位看,第一次出现1 的位置是5 ,也就是说,此时第三个桶,第三轮试验中k_max = 5, 5 对应二进制是 101,又因为每个通有p个比特位,单 p >= 3 时候,便可以将101存进去(三个比特位)。
  • 模拟上面流程,多个不同用户id就被分配到不同桶中区了,并且每个桶有其k_max,然后统计出main页面有多少用户点击量,就是一次估算。最终结合所有桶中的k_max,带入估算公式,便得出我们的估算值。
  • 更具上面调和平均数的公式,得出下面HyperLogLog的估算公式,变量的意义和LogLog的一样:
    - HyperLogLog
  • 其中以下表示每个通的估计值,对每个通估计值进行调和平均数求职
    - 其中
Redis中HyperLogLog的原理
  • 首先Redis中HyperLogLog是他的意志高级数据结构,他的实现有16384个桶,即 2^14 = 16384,每个桶有6位,每个桶可以表达的最大数字是 :2 ^ 5 + 2 ^ 4 + 2 ^ 3+ 2 ^ 2 + 2 ^ 1 = 63,二进制是111 111。
  • 对应pfadd key value命令,存储时候,value被hash成64 位,即64bit位,前14位用来分桶,前14位的二进制转成10进制就是通标号。之所以选14位是因为2^14 = 16384 ,刚好最大的时候可以把桶利用完,不造成浪费,假设一个字符串的钱14位是00 0000 0000 0010,其十进制是2 ^ 1 = 2,你们就会被放到编号是2 的桶
14位全是12 ^ 13 + 2 ^ 12 + ......+ 2 ^ 5 + 2 ^ 4 + 2 ^ 3+ 2 ^ 2 + 2 ^ 1 + 2 ^ 0 = 16383 < 16384
  • Index的转化规则:
    • 因为完整value是64位,减去低位14位,剩下高位50 位,极端情况,出现1 的位置是第50位,次数index = 50,转二进制是 110010,不超过6 bit数,所以刚好可以被设置到第2 号桶中去,因为50是最坏的情况,类比第五十次才抛出正面,最坏情况,其他情况必然都能被存储到桶中,
    • 如果不同value有相同的前面 14 位,也就是两个用户hash(userid) 得到的64位低位14 位相同,但是后面出现1 的位置不同。那么比较原来的index是否比新的index打,是则替换,否则不变,存储更大的数字
    • 最终一个key对应的16384 个桶都设置了很多的value,每个桶有一个k_max,此时调用pfcount 时候,按前面介绍估算方法,计算key的设置了多少次的value,就得到对应统计值
  • value被转为64 位比特串,最终被按照上做法记录到每个桶中,64位转十进制2 ^ 64 ,HyperLogLog仅仅用了16384 * 6 /8/1024= 12K存储空间就能够完成2 ^64 数量基数的数据统计。

布隆过滤器

  • 上面HyperLogLog中,如果我想知道某个userId是不是已经存储了,发现找不到对应Redis命令来查找,因为HyperLogLog只提供了add,count的功能,没有提供contant功能。
  • 如果有这样的业务,比如,我们做用户推荐,新闻推荐的时候,他会给我们不停的推荐新内容,怎么去掉已经看过的内容。推送去重这是一个问题
  • 用set存储历史记录,太费内存,在Redis高级数据结构中布隆过滤器(Bloom Filter),专门用来解决去重问题。并且空间上节省90%以上,但是他会有一点不精确,可能导致微小的误判。
Redis中的布隆过滤器
  • Redis4.0 才提供了bloomfilter,但是他是作为一个插件加载到Redis server中,给Redis提供了强大的布隆过滤功能,
  • 布隆过滤器有两个基本指令
    • bf.add添加元素, 一次只能添加一个元素
    • bf.madd 添加元素,一次可以添加多个
    • bf.exists 判断是否存在,一次判断一个
    • bf.mexists 判断多个元素是否存在
布隆过滤器原理
  • 每个bloomFilter 对应到Redis的数据结构就是一个大小的bitmap加上杰哥不一样的无偏hash函数,如下面图,f,g,h就是这样的hash函数。所谓的无偏就是能把元素值算的比较均匀,让元素被hash后映射到位数字中的位置比较随机。
    -
  • 想bloomfilter中添加key时候,会使用多个hash函数对key进行hash,算得一个整数值,然后对维数组长度进行取模运算得到这个整数在位数组中的位置,每个hash函数都会算得一个不同的位置,再把这个位数组的这几个位置都设置为1,就完成add操作。所以其实一个key是会标记多个bit位,这取决于他hash算法的个数,每个hash都出来一个位置。(减少重复率)
  • 向bloomFilter询问key是否存在是,也和add一样,吧hash的几个位置算出,看bitmao里面是不是都是1,有一个是0 就一定不存在 。但是都是1 并不100%保证一定存在,只是极有可能存在,因为这些被设置为1 ,可能是其他key存在的hash位,如果数组比较稀疏,判断的正确率就高,如果数组拥挤,误判就高。
  • bloomFilter使用之前可以指定其参数,Redis提供了自定义参数的BloomFilter,我们需要在add之前用bf.reserve显示的创建,如果对于key已经存在,你们bf.reserve会报错。bf.reserve有三个参数key, error_rate(错误率), initial_size(预计数据大小)
    • error_rate越低,需要空间越大
    • initial_size表示预计放入的元素数量,当实际数量超过这个数,误判就会上升,所以需要提前设置一个较大的数值避免超过导致误判率升高
    • 如果不使用bf.reserver,默认的error_rate是0.01,默认的initial_size是100.
空间占用估计
  • bloomFilter空间占用有一个简单计算公式,不推导了,直接给吧,有两个参数,第一个语句元素数量n,第二个错误率f, 公式根据两个输入得到两个输出,第一个输出是位数组的长度1,也就是需要的存储空间大小bit,第二个输出是hash函数的最佳数量k。hash函数的数量也直接影响错误率,最佳数量会有最低错误率。
k = 0.7 *(1/n)  //约等于
f = 0.6185^(1/n) 
  • 如上公式得出:
    • 位数越长(1/n),错误率发越低
    • 位数月长(1/n),hash函数需要的最佳数量也越多,影响计算效率
    • 当一个元素评价需要1字节8bit的指纹空间(槽空间)时候(1/n = 8),错误率大概2%
    • 错误率0.1% 时候,一个元素平均指纹空间14.377bit,大约15bit
  • 即使15bit也比set强,因为这边是15位,set存储取决于他存储的字符串大小,不是一个量级。
元素超出误判率变化
  • 当实际元素超过预计元素,错误率会有多大变化,这个也有公司,引入参数t 表示实际元素和预计元素的倍数
f = (1-0.5^t) ^k // 极限近似,k是hash函数最佳数量

-暂时就这些

上一篇Redis基础数据结构内部实现简单介绍
下一篇Redis流量控制策略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310583.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[剑指offer]面试题8:旋转数组的最小数字

面试题8&#xff1a;旋转数组的最小数字 题目&#xff1a;把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。输入一个递增排序的数组的一个旋转&#xff0c;输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转&#xff0c;该数…

.NET Core + Kubernetes:快速体验

Kubernetes[1] 是目前非常主流的容器编排工具&#xff0c;在应用创建、应用部署、应用扩容、应用更新等方面都非常的方便&#xff0c;而且在应用故障时&#xff0c;也可以快速自愈。所以基于微服务架构下的产品&#xff0c;了解 Kubernetes 的使用是非常必要的&#xff0c;我猜…

[剑指offer]面试题9:斐波那契数列

面试题9&#xff1a;斐波那契数列 题目一&#xff1a;写一个函数&#xff0c;输入n&#xff0c;求斐波那契&#xff08;Fibonacci&#xff09;数列的第n项。斐波那契数列的定义如下&#xff1a; ❖ 效率很低的解法&#xff0c;挑剔的面试官不会喜欢 代码如下: long long fib(…

Redis分布式锁奥义

分布式锁 分布式系统进行逻辑处理的时候&#xff0c;经常会遇到并发问题&#xff0c;例如直播场景中&#xff0c;用户需要连麦主播&#xff0c;当多个用户在同一个时刻一起连麦时候&#xff0c;应该保证只有一个用户能连麦成功&#xff0c;我们改怎么保证这种业务场景下保证数…

.NET Core + Kubernetes:Pod

在 .NET Core Kubernetes&#xff1a;快速体验 文章中&#xff0c;已经实现将一个 .NET Core API 服务部署在 Kubernetes 集群中&#xff0c;接下来将逐步了解 Kubernetes 中各核心模块。首先当然是 Pod&#xff0c;我相信 Pod 是在接触 Kubernetes 时听到较多的一个词语&…

LBS解决方案

LBS解决方案 LBS&#xff08;基于地理位置的服务&#xff09;服务是现在移动互联网中比较常用的功能&#xff0c;例如外卖中我附近的店铺&#xff0c;通常是以客户位置坐标为中心&#xff0c;查询一定范围内的店铺信息&#xff0c;按照距离由近及原进行倒叙排序 方案一&#…

长沙IT技术圈百万年薪大佬?是否存在?

作者&#xff1a;邹溪源&#xff0c;长沙资深互联网从业者&#xff0c;架构师社区特邀嘉宾&#xff01;01引子不知不觉&#xff0c;IT技术圈开始流传起“百万年薪”的故事&#xff0c;有人问我&#xff0c;长沙有百万大佬么&#xff1f;其实我也不知道。02背景长沙自古以来就是…

网络编程-网络分层的意义

网络 我们生活在一个网络无处不在的一个虚拟世界中&#xff0c;网络中的每一个设备都是一个节点。大多是我们的计算机&#xff0c;但是他还可以连接其他设备&#xff0c;例如打印机&#xff0c;路由器&#xff0c;网关&#xff0c;你的手机&#xff0c;智能家居等。我们可以使…

网络编程-TCP/IP协议栈-IP协议

协议 协议就是约定的一种规则&#xff0c;例如扑克游戏中约定好的各种规则&#xff0c;2<3<4<5<…等&#xff0c;以此作为游戏规则。当所有人都遵循这个规则&#xff0c;那么久可以不需要任何多余的交流就可以进行游戏&#xff0c;这个方式形成的约定就是一种协议…

.NET项目升级手记:可为空引用

c# 8引入了新特性&#xff1a;“可为空引用”&#xff08;详情&#xff09;&#xff0c;这个功能个人觉得挺好的&#xff0c;能够非常明确的表现程序设计者的意图&#xff0c;编译器能够进行检查&#xff0c;尽最大可能减小NullReferenceException错误。如果是新项目&#xff0…

.NET与鲲鹏共展翅,昇腾九万里(一)

2019年1月7日&#xff0c;华为推出鲲鹏920处理器&#xff0c;便宣告了构建鲲鹏生态系统的开始。据官方介绍&#xff0c;鲲鹏是一个包含了鲲鹏计算单元、AI处理单元、智能管理、智能网卡的片上系统SoC&#xff0c;在此之上加上服务器操作系统&#xff0c;从而形成一个生态的闭环…

网络编程-TCP/IP协议栈-TCP协议

TCP协议 TCP协议作用 TCP协议位于协议栈的传输层。当应用层向TCP层发送用于网间传输的&#xff0c;用8字节表示的数据流&#xff0c;TCP则吧数据流分割成适当长度的报文段&#xff0c;最大传输段大小&#xff08;MSS&#xff09;通常受到改计算机连接的网络数据链路层的最大传…

互联网10年,激战如梦

— 1 —1969年&#xff0c;美国国防部研究计划署第一次将互联网应用于军事连接。随后美国西南部四所名校的四台计算机通过这项技术连接起来。谁也没想到&#xff0c;这项计划会对人类的命运产生如此重大影响。1993年&#xff0c;互联网真正诞生。美国白宫宣布开始提供「在线服务…

网络编程-TCP/IP协议栈-UDP/HTTP协议

UDP协议 UDP协议全称是用户数据报协议&#xff0c;在网络中她与TCP协议一样用于处理数据包&#xff0c;两个协议同处于协议栈的传输层&#xff0c;和TCP不同的是&#xff0c;UDP是一种无连接的协议栈。 因为UDP是无连接的&#xff0c;所以相对来说&#xff0c;UDP的报头比TCP要…

十问十答 Ms-PL 许可证

Microsoft 公共许可证&#xff08;The Microsoft Public License&#xff09;是微软为释出开源项目而编写和发布的自由开源软件许可证。如果你用 .NET 开发&#xff0c;你会经常碰见 Ms-PL。在微软的自由开源项目托管地 Codeplex&#xff08;已寿终正寝&#xff0c;微软已战略转…

网络编程-HTTPS协议的实现原理

HTTP传输协议缺点 之前几篇文章中详细讲解了TCP/IP协议栈中的几个协议&#xff0c;其中个就有对HTTP做了一个比较详细的讲解。HTTP是基于TCP进行传输的&#xff0c;其中传输的内容都是明文报文数据&#xff0c;如果我是一个黑客&#xff0c;我会想办法获取这个HTTP消息体&…

从案例角度解析建模平台动态规则引擎

源宝导读&#xff1a;明源云ERP建模平台提供了强大的页面联动规则引擎&#xff0c;原来需要编写代码完成的联动控制逻辑&#xff0c;现在只需要点点鼠标&#xff0c;通过配置完成。本文从实际案例的角度出发&#xff0c;介绍原始的代码逻辑如何转化为引擎规则的过程。一、背景明…

想基于K8s按需扩展应用程序,可从这几方面入手

马修赫瑟&#xff08;Matthew Heusser&#xff09;在花费了十年时间进行编程&#xff0c;测试和项目管理之后&#xff0c;Matt Heusser于2011年创立了自己的公司Excelon Development。该协会前董事会成员Matt还是软件测试人员&#xff0c;是德国波茨坦最具影响力的敏捷测试专业…

windows环境下ELK平台搭建

背景 日志系统主要包括系统日志&#xff0c;应用程序日志和安全日志。系统运维和开发人员可以通过日志了解服务器的软件&#xff0c;硬件信息&#xff0c;检查配置过程中的错误以及错误发生的原因。通常分析日志可以了解服务器的负荷&#xff0c;性能安全性&#xff0c;从而及时…

EntityFramework Core 3.x上下文构造函数可以注入实例呢?

今天讨论的话题来自一位微信好友遇到问题后请求我的帮助&#xff0c;当然他的意图并不是本文标题&#xff0c;只是我将其根本原因进行了一个概括&#xff0c;接下来我们一起来探索标题的问号最终的答案是怎样的呢&#xff1f;老规矩&#xff0c;首先我们定义如下上下文public c…