0%

openAPI统一错误码

API网关返回错误

错误描述消除建议errorcodemsg
APPKey为空请求中填写正确的APP Key0x02401000Token or AppKey is null
APPKey对应的合作方不存在请求中填写正确的APP Key0x02401001Consumer inexistence!
签名为空请求中填写正确的签名信息0x02401002Signature is null.
签名不正确请求中填写正确的签名信息0x02401003Invalid Signature.
API令牌的身份验证失败检查token是否填写正确0x02401004Token authentication failed
API令牌为空检查token是否填写正确0x02401005Token is null.
API令牌异常检查token是否填写正确0x02401006Token Exception.
API令牌过期重新获取token0x02401007Token Expiration
API接口未授权向API接口管理员申请接口访问权限0x02401008Unauthorized Consumer!
权限验证异常检查API网关服务是否异常0x02401009Authentication Exception!
参数转换异常,具体错误见异常信息检查API接口参数0x0240100aParameters Convert Exception!
API接口调用次数受限向API接口管理员申请增加接口访问次数0x0240100bLimited number of calls.
接口调用统计异常重启网关服务0x0240100cCallStatistic Exception!
服务调用异常检查服务提供方是否正常0x02400004Call Service Exception!

参数错误

阅读全文 »

Maven下载依赖抛出一个ssl数字证书的异常:PKIX path building failed: SunCertPathBuilderException: unable to find valid certification path to requested target,记录一下这个问题的前因后果即解决办法

问题原因

在我这篇博客中:Maven依赖下载失败的原因及解决方案 ,我将maven的仓库地址设置为 ‘http://maven.aliyun.com/nexus/content/groups/public' ,别看写着是http开头,实际访问,却是一个由GlobalSign Organization Validation CA颁发证书的https站点,而这个ca机构颁发的证书,在jre/lib/security的可信证书容器cacerts中是没有存放过的,所以报出ssl数字证书不可信的异常。

不信,可以使用这条命令:

1
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts

默认密码为: ‘changeit’

查阅一遍可信ca名单 ,你看看有没有GlobalSign

解决办法

解决办法也很简单,直接将被质疑的证书导入cacerts即可,这一点很多其他博客也说明过,但他们只关注了keytool的命令是如何来导入证书的,并没有跟读者说明该导入的证书如何去获取

获取被质疑的证书

阅读全文 »

项目Github地址:github/booklet

Redis 提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照(snapshotting,RDB),它可以将存在于某一时刻的所有数据都写入硬盘里面。

另一种方法叫只追加文件(append-only file,AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。

这篇文章梳理了Redis两种持久化方法的知识点,并通过Docker + Docker-Compose进行环境的模拟,来进行数据的备份与恢复等操作。

至于测试数据,我通过一个python脚本批量录入三百万条key-value键值对(会消耗719.42M内存,来源于redis-cli info信息),没有python环境的同学,可以使用我在项目里准备的另一个shell脚本

python脚本代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: UTF-8 -*-
# file write.py
# author liumapp
# github https://github.com/liumapp
# email liumapp.com@gmail.com
# homepage http://www.liumapp.com
# date 2019/9/9
#
import redis

r = redis.Redis(host="127.0.0.1", port=6379, db=0, password="admin123")
print("开始插入三百万条数据,每10万条数据提交一次批处理")
with r.pipeline(transaction=True) as p:
value = 0
while value < 3000000:
print("开始插入" + str(value) + "条数据")
p.sadd("key" + str(value), "value" + str(value))
value += 1
if (value % 100000) == 0:
p.execute()

RDB

RDB持久化是通过创建快照来获得数据副本,即简单粗暴的直接保存键值对数据内容

要启用RDB(并关闭AOF),我们需要修改Redis的配置文件(./redis_config/redis.conf):

阅读全文 »

转自: http://suo.im/4oTqHu

从人工到自动化,从重复到创新,技术演进的历程中,伴随着开发者工具类产品的发展。

阿里巴巴将自身在各类业务场景下的技术积淀,通过开源、云上实现或工具等形式对外开放,本文将精选了一些阿里巴巴的开发者工具,希望能帮助开发者们提高开发效率、更优雅的写代码。

由于开发者涉及的技术领域众多,笔者仅从自己熟悉的领域,以后端开发者的视角盘点平时可能用得到的工具。每个工具按照以下几点进行介绍:

1、工具名称和简介

2、使用场景

3、使用教程

4、获取方式

一、Java 线上诊断工具 Arthas

Arthas 阿里巴巴2018年9月开源的一款Java线上诊断工具。

阅读全文 »

转自: https://www.cnblogs.com/kongzhongqijing/p/6867960.html

redis cli命令

redis安装后,在src和/usr/local/bin下有几个以redis开头的可执行文件,称为redis shell,这些可执行文件可做很多事情。

可执行文件作用
redis-server 启动redis
redis-cliredis命令行工具
redis-benchmark基准测试工具
redis-check-aofAOF持久化文件检测工具和修复工具
redis-check-dumpRDB持久化文件检测工具和修复工具
redis-sentinel启动redis-sentinel

本文重点介绍的redis-cli命令。

可以使用两种方式连接redis服务器。

第一种:交互式方式

redis-cli -h {host} -p {port}方式连接,然后所有的操作都是在交互的方式实现,不需要再执行redis-cli了。

$redis-cli -h 127.0.0.1-p 6379

127.0.0.1:6379>set hello world

阅读全文 »

转自:https://yq.aliyun.com/articles/38175

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。以下是整理的几个在JDK库中常用的几个设计模式。

  • Birdge 桥接模式

    这个模式将抽象和抽象操作的实现进行了解耦,这样使得抽象和实现可以独立地变化。
    GOF在提出桥梁模式的时候指出,桥梁模式的用意是”将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化”。这句话有三个关键词,也就是抽象化、实现化和脱耦。
    在Java应用中,对于桥接模式有一个非常典型的例子,就是应用程序使用JDBC驱动程序进行开发的方式。所谓驱动程序,指的是按照预先约定好的接口来操作计算机系统或者是外围设备的程序。

  • Adapter 适配器模式

    用来把一个接口转化成另一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

    java.util.Arrays#asList()
    java.io.InputStreamReader(InputStream)
    java.io.OutputStreamWriter(OutputStream)
阅读全文 »

转自:https://www.cnblogs.com/aspirant/p/8628843.html

一道经典考题,如果corePolllSize=10,MaxPollSize=20,如果来了25个线程 怎么办,

先达到 corePoolSize,然后 优先放入队列,然后在到MaxPollSize,然后拒绝;

答案:

当一个任务通过execute(Runnable)方法欲添加到线程池时:
1、 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
2、 如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
3、如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,再有新的线程,开始增加线程池的线程数量处理新的线程,直到maximumPoolSize;
4、 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
5、 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

  • 当线程数小于corePoolSize时,提交一个任务创建一个线程(即使这时有空闲线程)来执行该任务。
  • 当线程数大于等于corePoolSize,首选将任务添加等待队列workQueue中(这里的workQueue是上面的BlockingQueue),等有空闲线程时,让空闲线程从队列中取任务。
  • 当等待队列满时,如果线程数量小于maximumPoolSize则创建新的线程,否则使用拒绝线程处理器来处理提交的任务。

慢慢的启动到10,然后把剩下的15个放到阻塞队列里面,并开始在线程池里面创建线程,直到最大MaximumPoolSize;

当然是先放在阻塞队列(如果数量为0,就一直等待,LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列,两边都可以进出的,那种,

参考:聊聊并发(七)——Java中的阻塞队列

尤其是那个车间里工人的例子,好好看看,理解线程很有用:

阅读全文 »

转自: https://blog.csdn.net/WitsMakeMen/article/details/46874717

Integer 作为传参的时候是地址传递,可以参考如下例子,在程序刚启动的时候把 Integer 的index 对象锁住 ,并且调用了 wait方法,释放了锁的资源,等待notify,最后过了5秒钟,等待testObject 调用notify 方法就继续执行了。大家都知道锁的对象和释放的对象必须是同一个,否则会抛出 java.lang.IllegalMonitorStateException 。由此可以证明 Integer作为参数传递的时候是地址传递,而非值传递。

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
public class IntegerSyn {

public static void main(String[] args) throws InterruptedException {
Integer index = 0;
TestObject a = new TestObject(index);
synchronized (index) {
new Thread(a).start();
index.wait();
}
System.out.println("end");
}
}

class TestObject implements Runnable {
private Integer index;

public TestObject(Integer index){
this.index = index;
}

public void run() {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (index) {
index.notify();
}
}
}

那就会有人问了,为什么执行如下代码的时候两次的输出结果是一样的?

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws InterruptedException {
Integer index = 0;
System.out.println(index);
test(index);
System.out.println(index);
}

public static void test(Integer index){
index++;
}

理由很简单,可以看到 Integer 类中final的value字段,说明一旦integer类创建之后他的值就不能被修改,在 index++ 的时候Integer是创建一个新的类,所以这个第二次输出的时候结果是一样的!

private final int value;

阅读全文 »

操作Gitlab进行日常代码推拉的过程中,突然遇到如标题所述异常,这篇博客记录这个问题的解决办法

场景复现

对Gitlab私有仓库进行代码push操作,产生如下异常信息:

1
2
3
4
5
6
7
8
Counting objects: 875, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (523/523), done.
Writing objects: 100% (875/875), 42.94 MiB | 9.72 MiB/s, done.
Total 875 (delta 206), reused 2 (delta 0)
error: RPC failed; result=22, HTTP code = 500
fatal: The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly

Gitlab官方对此issue的反馈信息:https://gitlab.com/gitlab-org/gitlab-ce/issues/12629

查看官方issue后,可以发现官方对此问题的解决方式基本是以下两种方案:

  • 更换CentOS操作系统为Ubuntu

  • 更换Nginx引擎为Tomcat

两种方案操作成本都很昂贵,不可接受

问题出现原因

因为gitlab本身自己封装了nginx、redis等工具,包括这些工具的配置也一并解决,所以在推代码的过程中,如果一次性提交的commit体积过大,超出max package的限定值,那么可能会产生上述异常

阅读全文 »

org.springframework.data.redis是Spring框架对Redis的默认集成,我们在实际项目中,也经常使用它的RedisTemplate去操作Redis,一般来说没什么问题,但是细心一点的同学会发现,经过这种方法写入redis的数据会出现乱码问题

问题复现

项目依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
阅读全文 »