Java 基于 LinkedHashMap 实现 LRU 缓存
核心思想
- LRU(最近最少使用)算法最常见的实现方法是使用一个双向链表或类似的数据结构,最近访问的数据会被移动到链表头部,链表尾部的节点就是最久未被访问的数据。
- LRU 算法可以使用双向链表实现,也就是在各个 Node 节点之间增加
prev指针和next指针,以此构成双向链表。将新增或者访问到的节点移动到链表的头部,超出容量时则从链表的尾部删除节点。 - 要满足 O (1) 时间复杂度,可以使用 HaspMap,里面储存的是 key 与链表节点,这样可以快速查找节点,然后将它删除或者移动到链表的头部。
- LRU 的算法核心是哈希链表,本质就是哈希表 + 双向链表的结合体 (HashMap + DoubleLinkedList),时间复杂度是 O (1),底层的数据结构如下图所示:
Hexo Next 主题详细配置之一
Kubernetes 创建 TLS 证书
前言
Kubernetes 系统的各组件需要使用 TLS 证书对通信进行加密,可以使用 CloudFlare 的 PKI 工具集 CFSSL 来生成 Certificate Authority(CA)和其它证书。使用到证书的 Kubernetes 组件如下:
| 组件 | 使用的证书(证书的名称可能跟下面的不一样) |
|---|---|
| ca 根证书 | ca.pem、ca-key.pem |
| etcd | ca.pem、etcd-server-key.pem、etcd-server.pem |
| kube-apiserver | ca.pem、kube-apiserver-key.pem、kube-apiserver.pem |
| kube-controller-manager | ca.pem、kube-controller-manager-key.pem、kube-controller-manager.pem |
| kube-scheduler | ca.pem、kube-scheduler-key.pem、kube-scheduler.pem |
| kubelet | ca.pem |
| kube-proxy | ca.pem、kube-proxy-key.pem、kube-proxy.pem |
| kubectl | ca.pem、admin-key.pem、admin.pem |
Knife4j 基础使用教程
1、前言
特别注意
如何没有特别标注说明,本文默认使用的 Knife4j 版本是 2.x。
1.1、Knife4j 简介
Knife4j 是为 Java MVC 框架集成 Swagger 生成 Api 文档的增强解决方案,前身是 swagger-bootstrap-ui,致力于 springfox-swagger 的增强 UI 实现。knife4j 为了契合微服务的架构发展,由于原来 swagger-bootstrap-ui 采用的是后端 Java 代码 + 前端 UI 混合打包的方式,在微服务架构下显的很臃肿,因此项目正式更名为 knife4j,更名后主要专注的方面如下:
- 后端 Java 代码以及前端 UI 模块进行了分离,在微服务架构下使用更加灵活
- 提供专注于 Swagger 的增强解决方案,不同于只是单纯增强前端 UI 部分
1.2、Knife4j 模块
| 模块名称 | 说明 |
|---|---|
| knife4j | 为 Java MVC 框架集成 Swagger 的增强解决方案 |
| knife4j-admin | 云端 Swagger 接口文档注册管理中心,集成 gateway 网关对任意微服务文档进行组合集成 |
| knife4j-extension | chrome 浏览器的增强 swagger 接口文档 ui, 快速渲染 swagger 资源 |
| knife4j-service | 为 swagger 服务的一系列接口服务程序 |
| knife4j-front | knife4j-spring-ui 的纯前端静态版本,用于集成非 Java 语言使用 |
| swagger-bootstrap-ui | knife4j 的前身,最后发布版本是 1.9.6 |
JWT 基础使用教程
JWT 的概述
JWT(JSON Web Token)是目前最流行的跨域身份验证解决方案。
传统的身份验证
- 用户向服务器发送用户名和密码
- 验证服务器后,相关数据(如用户角色,登录时间等)将保存在当前会话中
- 服务器向用户返回
session_id,Session 信息都会写入到用户的 Cookie 中 - 用户的每个后续请求都将通过在 Cookie 中取出
session_id并传递给服务器 - 服务器收到
session_id并对比之前保存的数据,确认用户的身份
这种模式最大的问题是,没有分布式架构,无法支持横向扩展。如果使用一个服务器,该模式完全没有问题。但是,如果它是服务器群集或面向服务的跨域体系结构的话,则需要一个统一的 Session 数据库(Redis)来保存会话数据实现共享,如果保存 Session 的数据库(Redis)挂掉,整个认证体系都会挂掉。
Redisson 分布式锁使用教程
大纲
前言
学习资源
Redisson 简介
Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。充分地利用了 Redis 键值数据库提供的一系列优势,基于 Java 实用工具包中的常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。Redisson 的宗旨是促进使用者对 Redis 的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。值得一提的是,Redisson 底层采用的是 Netty 框架。支持 Redis 2.8 以上版本,支持 Java 1.6+ 以上版本。
Redis 分布式锁中 Lua 脚本的使用
大纲
Lua 简介
从 Redis 2.6.0 版本开始,通过内置的 Lua 解释器,可以使用 EVAL 命令对 Lua 脚本进行求值。Redis 使用单个 Lua 解释器去运行所有脚本,并且 Redis 也保证脚本会以原子性 (atomic) 的方式执行。当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。这和使用 MULTI / EXEC 包围的事务很类似。在其他别的客户端看来,脚本的效果 (effect) 要么是不可见的 (not visible),要么就是已完成的 (already completed)。在 Lua 脚本中,可以使用 redis.call () 函数来执行 Redis 命令。
Lua 在 Reids 中的使用方式
Redis 中内嵌了 Lua 脚本的解释器,并提供了执行 Lua 脚本的入口 eval 命令,格式为 eval script numkeys key [key ...] arg [arg...]。其中 eval 为命令,script 为执行的命令脚本,numkeys 为脚本中共涉及到的 key 的数量,后续接收若干个 key 的输入和若干个 arg 的输入。在 Lua 脚本中使用 KEYS[index], 和 ARGV[index] 来获取实际输入的参数,这有点类似于 SQL 的占位符。另外一层原因由于 Redis 集群的固有模式导致 EVAL 命令在集群中涉及多个 KEY 的操作时,要求所有的 KEY 都在同一个 Hash Solt 上。在集群环境中调用 EVAL 命令,Redis 会对脚本先做一个的校验。KEYS[1] KEYS[2] 是要操作的键,可以指定多个,在 Lua 脚本中可以通过 KEYS[1]、KEYS[2] 获取 Key 的值。特别注意,这些键要在 Redis 中存在,不然就获取不到对应的值。ARGV[1] ARGV[2] 参数在 Lua 脚本中可以通过 ARGV[1]、ARGV[2] 获取值。
