blog icon indicating copy to clipboard operation
blog copied to clipboard

my personal blog

Results 17 blog issues
Sort by recently updated
recently updated
newest added

Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 9.12.0 to 10.4.1. Release notes Sourced from highlight.js's releases. 10.4.1 Security fixes: (fix) Exponential backtracking fixes for: Josh Goebel cpp handlebars gams perl jboss-cli r erlang-repl powershell...

dependencies

> [我的博客](https://www.penglei.wang/) 转载请注明原创出处。 # 需求 小程序新版本上线需要审核,如果有接口新版本返回内容发生了变化,后端直接上线会导致旧版本报错,不上线审核又通不过。 之前是通过写新接口来兼容,但是这样会有很多兼容代码或者冗余代码,开发也不容易能想到这一点,经常直接修改了旧接口,于是版本控制就成了迫切的需求。 # 思路 所有请求都是走的网关,很自然的就能想到在网关层实现版本控制。首先想到的是在`ZuulFilter`过滤器中实现,前端所有请求都在请求头中增加一个`version`的`header`,然后进行匹配。但是这样只能获取到前端的版本,不能匹配选择后端实例。 查询资料后发现应该在负载均衡的时候实现版本控制。同样是前端所有请求都在请求头中增加一个`version`的`header`,后端实例都配置一个版本的`tag`。 # 实现 首先需要说明的是我选择的控制中心是`consul`,网关是`zuul`。 负载均衡策略被抽象为`IRule`接口,项目默认情况下使用的`IRule`的子类`ZoneAvoidanceRule extends PredicateBasedRule`,我们需要实现一个`PredicateBasedRule`的子类来替换`ZoneAvoidanceRule`。 `PredicateBasedRule`需要实现一个过滤的方法我们就在这个方法里实现版本控制,过滤后就是默认的负载均衡策略了,默认是轮询。 ```java /** * Method that provides an instance of {@link AbstractServerPredicate} to...

## 序 长期处于CRUD工作中的我突然有一天关心起自己项目的`qps`了.便用`jmeter`测试了访问量最大的接口,发现只有可怜的`17r/s`左右......看到网络上比比皆是的几百万`qps`,我无地自容啊. 于是就准备进行性能优化了,不过在优化前我们需要进行性能测试,这样才能知道优化的效果如何.比如我第一步就是用`redis`加了缓存,结果测试发现居然比不加之前还要慢???所以性能测试是非常重要的一环,而`jmh`就是非常适合的性能测试工具了. ## 准备工作 准备工作非常的简单,引入`jmh`的`maven`包就可以了. ```java org.openjdk.jmh jmh-core 1.22 provided org.openjdk.jmh jmh-generator-annprocess 1.22 provided ``` ## 第一个例子 ```java package jmh; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder;...

> 程序员都很希望别人能写技术文档,自己却很不愿意写文档。因为接口数量繁多,并且充满业务细节,写文档需要花大量的时间去处理格式排版,代码修改后还需要同步修改文档,经常因为项目时间紧等原因导致文档滞后于代码,接口调用方的抱怨声不绝于耳。而程序员是最擅长"偷懒"的职业了,自然会有多种多样的自动生成文档的插件.今天要介绍的就是Swagger. ### 接下来我们在Spring Boot中使用Swagger2构建API文档 Swagger是一个简单但功能强大的API表达工具。它具有地球上最大的API工具生态系统,数以千计的开发人员,使用几乎所有的现代编程语言,都在支持和使用Swagger。使用Swagger生成API,我们可以得到交互式文档,自动生成代码的SDK以及API的发现特性等。 **我们先来看看具体效果:** ![tim 20170806152444](https://user-images.githubusercontent.com/14230327/29001371-94eb2702-7abb-11e7-97f0-358f77892ea7.png) 可以看到Swagger-Ui是以controller分类,点击一个controller可以看到其中的具体接口,再点击接口就可以看到接口的信息了,如图: ![tim 20170806152444](https://user-images.githubusercontent.com/14230327/29001404-6e983986-7abc-11e7-92da-7ac5afedc781.png) 我们可以看到该接口的**请求方式**,**返回数据信息**和需要传递的**参数**.而且以上数据是自动生成的,即使代码有一些修改,Swagger文档也会自动同步修改.非常的方便. - ### 构建RESTful API 在使用Swagger2前我们需要有一个RESTful API的项目. Spring-Boot创建RESTful API项目非常的方便和快速,这里不再介绍如何创建,需要的可以参照[项目代码](https://github.com/DigAg/digag-server) - ### 添加Swagger2依赖 在pom.xml文件中加入以下依赖. ``` io.springfox springfox-swagger2 2.7.0 io.springfox...

# 序 最近终于有需要消息队列的业务需求出现了,就决定自己搭建一个`Kafka`集群作为业务测试用。如果没问题的话就不去购买云服务了,还能省下不少钱呢。对于`Kafka`之前自己也写过demo稍微了解了一下,这次就把实践的要点记录下来。 # 安装Kafka `Kafka`的安装可以说是非常简单了。 * 首先去[官网](http://kafka.apache.org/downloads)找到下载链接,注意要下载二进制版本。 * 然后用`wget`下载到服务器上,再解压(`tar xzvf`)就ok了 * `Kafka`是依赖于`zookeeper`的,不过官方的安装包里已经自带了`zookeeper`,单机版直接用已经写好的脚本启动就可以了,我是按[文档](https://zookeeper.apache.org/doc/r3.4.14/zookeeperStarted.html)搭了个`zookeeper`集群。 ``` bin/zookeeper-server-start.sh config/zookeeper.properties 需要后台运行的加 -daemon 参数 bin/zookeeper-server-start.sh -daemon config/zookeeper.properties 用netstat -ntlp命令可以看到 tcp 0 0 0.0.0.0:2181 0.0.0.0:* LISTEN...

# 列表对象 列表数据类型是`Redis`里非常常用的类型,当我们想用一个键关联一组对象时就可以用列表数据类型来存储。列表的功能并不复杂,现在就来看看`Redis`是怎么实现列表功能的。 ## 列表的编码 列表的编码一共有三种: * `OBJ_ENCODING_ZIPLIST` 压缩列表 * `OBJ_ENCODING_QUICKLIST` 编码为ziplist的快速列表 * `OBJ_ENCODING_LINKEDLIST` 不再使用的旧列表,使用双端链表 其中`OBJ_ENCODING_LINKEDLIST`编码如下面代码所示,已经被标记为不使用了。 ```c #define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */ ``` 而`OBJ_ENCODING_ZIPLIST`编码虽然有定义创建函数,但是我下载了源码然后全文搜索也没找到哪里有调用这个函数,也已经不使用了。...

## OBJ_ENCODING_ZIPLIST `ziplist`也就是压缩列表,是`Redis`为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,在`Redis2.8`的时候是作为小数据量的列表底层实现。`ziplist`本身并没有定义结构体,下面是《redis设计与实现》里的说明图。 ![](https://user-gold-cdn.xitu.io/2019/4/7/169f6e2f69485c84?w=1990&h=912&f=png&s=340214) ![](https://user-gold-cdn.xitu.io/2019/4/7/169f6e92a846e2b9?w=2000&h=716&f=png&s=214664) ### ziplist entry 下面是`ziplist`的`entry`逻辑定义,并不是实际的编码,但是可以用来理解`entry`是怎么组成的。 ```c /* We use this function to receive information about a ziplist entry. * Note that this is not how the...

# 字符串对象 字符串数据类型是`Redis`里最常用的类型了,它的键和值都是字符串,使用起来非常的方便。虽然字符串数据类型的值都统称为字符串了,但是在实际存储时会根据值的不同自动选择合适的编码。字符串对象的编码一共有三种:`int`、`raw`、`embstr`。 ## Redis对象 Redis用统一的数据结构来表示一个对象,具体定义如下: ```c typedef struct redisObject { unsigned type:4; unsigned encoding:4; // 当内存超限时采用LRU算法清除内存中的对象 unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or * LFU data...

# 序 `HashMap`是Java中常用的Map接口的实现类,因为在日常工作中非常频繁的出现,所以在大部分的Java面试中都会问几个关于HashMap的问题。掌握HashMap的实现原理,已经是Java程序员的基础操作了。 # Map接口 映射(Map)是一种用于存放键/值对的数据结构。如果提供了键,就能直接找到相对应的值。HashMap(哈希映射)是Map接口的一个实现类,主要使用哈希来实现键与值的映射。 ``` 定义。映射是一种用于存放键/值对的数据结构,主要支持两种操作:插入(put),即将一组新的键值对存入映射中;查找(get),即根据给定的键得到相应的值。 ``` # HashMap的底层数据结构 HashMap的底层是用散列表实现的,散列表是一种用数组来存储键值对的数据结构,它使用一个散列函数将键转换成数组的一个索引然后存储值。不过会有不同的键被散列成同个索引的情况出现,这叫做碰撞冲突。HashMap用拉链法来解决这个问题,即散列表数组中的每个元素都指向一条链表,链表中的每个节点都存储了被散列到这个索引的键值对。 ![image](https://user-images.githubusercontent.com/14230327/54877642-413d3980-4e5c-11e9-802f-bb01c8e0c9ac.png) # HashMap的散列函数 根据散列表的定义我们知道,想要弄清楚HashMap的实现,我们首先需要知道HashMap的散列函数是怎么实现的,即HashMap是如何将一个键映射到数组的索引的。 ```java static final int hash(Object key) { int h; return (key == null) ?...

> [我的博客](https://www.penglei.wang/) 转载请注明原创出处。 # 序 之所以会想来写泛型相关的内容,是因为看到这样的一段代码: ![](https://user-gold-cdn.xitu.io/2018/8/2/164f9ada63c9edb0?w=523&h=27&f=png&s=3910) 当时我的内心是这样的: ![](https://user-gold-cdn.xitu.io/2018/8/2/164f9ae4ffddf5c9?w=113&h=62&f=jpeg&s=2588) 所以就赶紧去复习了下,记录下来。基础不扎实,源码看不懂啊。 # 泛型介绍 Java 泛型(generics)是 JDK 5 中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,在Java集合框架里使用的非常广泛。 定义的重点是提供了编译时类型安全检测机制。比如有这样的一个泛型类: ``` public class Generics { private T value; public T getValue() {...