我的理解:
对Redis底层hash表的实现不熟悉,但是应该和golang中的map底层实现类似,一个buckets数组,然后对key进行hash取值得到一个长度为16位的hash值,根据低8位查找具体某个bucket(落入哈希表数组哪个索引位置处),根据高8位查找对应bucket中的具体key数据。有hash值冲突时采用链表法。完整答案:
Redis的字典使用哈希表作为底层实现,一个哈希表里可以用多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对。
一个键值对放入哈希表时,会根据key值,计算一个hash值,然后根据hash值与哈希表大小掩码做与运算得到一个索引值,索引值决定元素放入哪个哈希桶中(落入哈希表数组哪个索引位置处)。
在进行哈希计算的时候,不可避免会出现哈希冲突,出现哈希冲突的时候,Redis采用链式哈希解决冲突,也就是落入同一个桶中的元素,使用链表将这些冲突的元素链起来(dictEntry中的next指针)。
具体情况还跟数据的主键大小有关,主键类型所占字节数大,则Innodb的每一页16k所能存储的数据量就小,反之主键类型所占字节数小,所能存储的数据量就多,具体可参考:Innodb引擎中B+树一般有几层?能容纳多少数据量?
索引结构为B+树,它是排好序的数据结构。主键索引中,非叶子节点存储的是索引值,叶子结点存储的是行数据,普通索引中,叶子结点存储的是索引值和主键ID,同时叶子结点间是链表组成。
读多写少的场景下使用到。实现方式:版本比较/CAS比较并交换,或者新增表比较版本/修改时间戳
- 建堆:O(N),按我的理解最坏情况下,假如是一个递增序列,那么会形成一条链表,那么此时的时间复杂度就是O(N)。
因为初始化建堆的过程,是一个杂乱无序的数组构成的完全二叉树,所以需要从倒数第一个非叶节点开始与它的叶子节点进行比较,然后移动。不是说每一层选一个根节点进行比较就可以了,是每一层的所有节点都要跟它的左右节点进行比较。这也就导致了它的时间复杂度不是logN,而是O(N)。- 调整堆:O(NlogN),对于重建堆的过程,因为是从最上面的根节点开始进行左右节点的比较,选择一个 较大(大顶堆)/ 较小(小顶堆) 的孩子节点进行交换。而因为只破坏了一层的有序性,另一边子树的有序性没有遭到破坏。所以,另一边子树不需要进行比较,所以,每一层只需要比较一次,一共log层,需要比较logn次。而一共会有 n-1 个这样的元素会被放到根节点进行这样的操作,近似得到 O(NlogN)。
削峰填谷、异步化(站内信告警,避免告警逻辑阻塞正常业务逻辑返回)、解耦…
利用MySQL的唯一索引,或者向Redis中写入标记值。
cat *.log | awk -F" " ‘{ print $2 }’ | sort | uniq -c | sort -nrk 1 -t’ ’ | awk -F" " ‘{ print $2 }’ | head -10
参考:使用Linux命令找出日志文件中访问量最大的10个IP
在nginx中 499状态码的定义是 client has closed connection,也就是客户端断开了连接。所以显然,客户端端主动关闭请求或者客户端网络断掉时,于是nginx就记录了499状态,并且断开了和后面服务端的连接(这样可能导致服务端返回数据时,因为连接断开而报错)
参考:nginx 499错误原因及解决
区别:
reset是彻底回退到指定的commit版本,该commit之后的所有commit都将被清除;revert仅是撤销指定commit的修改,并不影响后续的commit。
reset执行后不会产生记录,revert执行后会产生记录。
我说是父子域名有继承关系,对于父域名下的所有子域名,浏览器都会自动帮其提交cookie。或者前端不使用cookie传递信息,而使用localstorage本地存储用户身份认证信息。
而面试官提示说是通过中间层的代理服务器进行请求的转发。。。我对此不是很了解
我说根据提问者的 user_id 去对N取模来分表,比如 N=64 时,user_id%64得到的值就是对应序号的表 …
我说根据帖子发布的时间戳来构建一个大顶堆,大顶堆大小为20,最后扫描这64张表来填充大顶堆即可~
感觉面试官并不是很想招人,相比一面的面试官体验感极差,就问了一个epoll的问题,然后就算法题,然后做出来说边界处理写的不优雅,我说我继续优化下,没给机会直接说抱歉…挂了。总之就感觉很憋屈~
package mainimport ("fmt"
)// 这是我面试结束后优化的,无需处理边界条件
func GetOCnt(n int) int {res := 0iIndex, oIndex, allCnt := 1, 1, 1for ; allCnt < n; allCnt += iIndex + oIndex {iIndex++res++}return res
}/*
// 这是我第一遍写的代码,面试官说n<=2时的边界处理不行,不优雅,然后给我挂了...
func GetOCnt(n int) int {if n <= 1 {return 0} else if n == 2 {return 1}res := 0iIndex, oIndex, allCnt := 1, 1, 0for ; allCnt < n; allCnt += iIndex + oIndex {iIndex++res++}return res
}
*/func main() {oCnt := GetOCnt(3)fmt.Println("res = ", oCnt)
}