分类: 默认

  • 开源软件依赖License检测

    开源软件依赖License检测

    开源软件的License是一个很重要的声明,这代表了软件是基于何种许可证向世人开放的,对于其的使用又需要遵循何种规则。

    开源软件自身又会依赖其他的开源软件,而那些依赖又会有自己的License,所以对于依赖的License检查是非常重要的。因为有些License是不兼容的,比如一个基于Apache License的开源软件是不能包含一个依赖于GPLv3的库。

    所以检查依赖的License就变得很重要。

    如果你精通各类开源软件,看名字就知道软件对应的License和兼容性,那自然不需要其他辅助,但是大部分情况这个很难做到。

    License Maven Plugin是一个专门处理这种问题的插件。对于任何一个maven项目,简单地运行

    mvn license:add-third-party -Dlicense.useMissingFile -Dlicense.includeOptional=true

    输出如下:

    Lists of 67 third-party dependencies.
    (BSD License) AntLR Parser Generator (antlr:antlr:2.7.7 – http://www.antlr.org/)
    (Apache Software License 2.0) A Swiss Army Knife for OSGi (biz.aQute.bnd:bndlib:2.4.0 – http://www.aQute.biz/Code/Bnd/bndlib)
    (Eclipse

  • Knime中集成Java代码

    Knime中集成Java代码

    Knime是一个非常强大的数据分析平台,支持常用的各种数据清洗,分析等功能。

    但是有些时候数据的预处理,比如打标记等等需要一些外部逻辑,这种时候用java代码可能更快。

    为了让数据处理更流畅,而不是在Knime中输出一个中间结果,然后在放回Knime中继续这样断断续续的方法,Knime提供了各种语言的集成,比如Java,Python等。其中Java代码的集成是原生支持的,而Python等语言是需要安装插件的。

    这里用阿里天池全球城市计算AI挑战赛的数据作为说明。

    假定我们读取文件每次只读取同一天的数据,比如要计算星期二的,就只读取同样为星期二的历史数据。workflows需要用到

    • List Files
    • Java Snippet
    • Rule-based Row Filter
    • Table Row To Variable Loop Start
    • CSV Reader

    其中List Files可以将指定目录的文件全部列出

    然后我们在Java Snippet中写逻辑过滤就行了,这里追加一个星期标识

    // system imports
    import org.knime.base.node.jsnippet.expression.AbstractJSnippet;
    import org.knime.base.node.jsnippet.expression.Abort;
    import org.knime.base.node.jsnippet.expression.Cell;
    import org.knime.base.node.jsnippet.expression.ColumnException;
    import org.knime.base.node.jsnippet.expression.TypeException;
    import static org.knime.base.node.jsnippet.expression.Type.*;
    
  • Docker Hub镜像构建测试

    Docker Hub提供了镜像构建服务,特别是和代码仓库关联起来的时候可以自动构建最新的镜像,这个功能可以保证你的镜像时刻是最新的。

    但是有时候构件本身可能是成功的,比如你成功生成了相关的jar,并放到了合适的运行容器中,但是可能由于第三方依赖或其他原因导致你的镜像其实并不能正常工作。

    人工验证可以发现问题,但是这里使用Docker Hub提供的测试服务更加快捷。

    我们以dubbo-admin为例,这是一个非常标准的Spring Boot项目,构建以后生成jar包可以直接运行。而我们的测试目标就是构建出的镜像可以正常对外提供服务,这里我们检测swagger文档地址是否返回200。不同的项目可以使用不同的检测标准。

    首先添加一个检测脚本test.sh

    LOOP_SIZE=60
    i=0
    
    while [[ $i -lt LOOP_SIZE ]]; do
    	status_code=$(curl --write-out %{http_code} --silent --output /dev/null http://admin:8080/swagger-resources)
    
      if [[ "$status_code" -eq 200 ]] ; then
        echo "Tests passed!"
        exit 0
      else
        curl -v 
  • 使用JGit获取变更细节

    有时候多个项目在一个代码仓库中,可能每个文件夹都是一个项目。如果每次使用CI自动部署的话就需要判断最近的改动属于哪个文件夹/项目。

    通过JGit直接获取两个commit之间的diff然后判断是比较直接的方法,具体使用哪两个commit就看需要的。可以使用CI系统上一次成功构建的commit sha,也可以直接使用最近两天的commit的。

    代码如下:

    Repository repo = FileRepositoryBuilder.create(new File(basePath + ".git"));
    Git git = new Git(repo);
    ObjectReader reader = repo.newObjectReader();
    ObjectId newObjectId = repo.resolve("HEAD^{tree}");
    ObjectId oldObjectId = repo.resolve(successSha + "^{tree}");
    
    
    System.out.println("Starting diff " + oldObjectId + " : " + 
  • 压测前的影子表预热

    影子表和buffer pool

    影子表并不是一个数据库的特殊功能,简单来说只是和原表结构一致但是名字不一样的普通表而已。所以创建影子表并不需要特别的操作,根据数据库中间件的支持规则创建就行了。

    buffer pool是一个缓存数据和索引信息到内存的存储区,简单理解就是一个热数据区,或者叫缓存。具体的配置和计算比较复杂,但是总体而言,buffer pool命中率越高,性能越好。

    预热的价值

    因为影子表的数据是冷数据,这一部分数据并不在buffer pool中,需要逐步加载到内存中,因此需要预热过程。如果没有预热,会出现性能问题,但是这一部分并不是我们期待的,因为线上buffer pool中是包含了真实数据的。

    执行预热

    执行预热就是低流量的压测,让影子表的数据被访问到,并加载到buffer pool中。

    其次就是执行预热前,需要先dump出线上的buffer pool,然后在压测完成重新load之前导出的buffer pool。

    其他要点

    预热的时候要注意因为buffer pool的空间是公用的,要注意不要让影子表的数据影响线上数据了。业务高峰期很难成功,因为线上的流量大,真实数据占用buffer pool的量比较大,预热数据的buffer很快就被线上请求踢出。

    预热时要密切观察慢查询的量,有问题就需要降速或者停止,严重的情况还需要在DB上kill查询,并重新加载buffer pool。…

  • 内联第三方依赖到自己的包中

    Java世界一个很难绕过的问题就是依赖包,绝大部分项目总会或多或少的依赖第三方包。Maven或者Gradle等可以帮助我们轻松的管理第三方依赖,但是对于自己对外提供的包,特别是作为中间件或者基础组件等提供出去的包,还是会遇到一些第三方依赖的问题,主要有两个问题

    • 包依赖比较少,而且依赖第三方包中的极少部分代码
    • 一些关键依赖版本敏感,不希望使用方随意变更

    第一个情况可以先打一个fatjar,然后通过ProGuard精简代码。

    第二个情况就需要把第三方包的代码拷贝到自己的包中,在自己的代码中直接使用拷贝进来的三方包代码(pakcage name不一样),这样就可以最大程度保证稳定性。

    当然大部分情况下对于第三方包的版本依赖没有那么敏感,上面说到的情况其实是大部分针对asm,cglib和objenesis等几个字节码增强的包。

    具体的操作可以借助jarjar工具,先将三方包重新打包,然后修改Gradle的Jar任务,将重新打包后的jar复制到自己的包中。

    task cglibRepackJar(type: Jar) { repackJar -repackJar.baseName = "cglib-repack" repackJar.version = cglibVersion doLast() {
            project.ant {
                taskdef name: "jarjar", classname: "org.pantsbuild.jarjar.JarJarTask", classpath: configurations.jarjar.asPath
                jarjar(destfile: repackJar.archivePath) {
                    configurations.cglib.each { originalJar -zipfileset(src: originalJar) 
  • 全链路压测改造

    全链路压测是基于实际的生产业务场景、系统环境,模拟海量的用户请求和数据对整个业务链进行压力测试,并持续调优的过程。

    全链路压测针对是线上真实环境,主要的目的是针对业务场景越发复杂化、海量数据冲击下整个业务系统链的可用性、服务能力的瓶颈,让技术更好的服务业务,创造更多的价值。简单来说就是为了快速准确找出系统的优化点。

    全链路压测听起来很好,各个大厂都可以找到相关的博客或者分享文章,但是要实施全链路压测需要很大的工作量,对于系统需要进行改造。

    由于全链路压测涉及整个技术生态,不同的公司使用的技术和基础设施各不相同,所以改造内容也不同,但是大致的改造是类似的,主要在以下几个方面:

    流量标记

    流量标记的作用是让所有服务或者说是代码在任何一个时刻都能知道当前是否为压测。因为实际业务中链路一般都比较长,从头开发这样的一个功能还是比较复杂。

    目前大部分系统为了全链路追踪一般都是用了OpenTracing标准的某种实现,那么在OpenTracing中的Span中的Context就是一个绝好的信息载体。

    对于对外暴露的HTTP API请求,需要从URL中获取到压测信息,然后将其传递到RPC或者其他调用层,RPC层依次传递对应的标志就行了。

    RPC框架

    RPC上的改动比较上,主要是需要用上下文传递压测标记。这里可以用RPC框架自带的上下文,当然用OpenTracing的比较方便,这一步改动不大。

    数据库中间件

    既然要做全链路压测,那么肯定不能只测试读接口,对于写接口,需要考虑到数据隔离的问题。

    这个时候影子表是比较合适的选项,影子表是与真实表对应的一个概念,与真实表同构,只是名称不同。在MySQL的innodb引擎中,影子表与真实表存储的文件不同,但是共用buffer pool。总体而言,影子表的使用是安全,能够有效模拟真实表,同时又能起到逻辑隔离的效果:

    数据库中间件需要支持的是影子表偏移的,而且还需要支持配置,因为根据业务和系统情况,并不是所有表都需要影子表,而且影子表的偏移各不相同。

    其次就是和影子表有关的其他改造,比如初始化,预热,buffer pool恢复,数据构造和数据清理等都是需要考虑的。

    MQ中间件

    MQ中间件主要是两个问题,一个是压侧标识传递,另外一个是队列隔离。

    日志组件

    日志组件上主要是压测流量日志是否需要打印特定标识,是否需要单独的降级开关。

    线程池

    业务系统或多或少用到了线程池,而线程池一般都需要改造用于支持压测标识的传递。

    Mock

    一个完整的业务流程很难只和自己的系统打交道,外部系统一般不纳入压测中,比如第三方保险/语音电话服务/短信等等,有时候也会遇到下游系统并没有准备好加入压测链路,所以需要Mock。

    具体的Mock返回数据要根据情况创造。

    降级

    降级并不是全链路压测必须的,但是提供降级开关可以在压测出现问题的时候中断部分接口,依然执行全链路压测,以免压测失败。…

  • 快速搭建本地OpenWhisk环境

    快速搭建本地OpenWhisk环境

    OpenWhisk是IBM开源的FAAS平台。OpenWhisk 简化了微服务的部署,消除了管理自己的消息代理或部署自己的工作服务器的需求。

    有时候为了方便本地开发验证,需要搭建一个OpenWhisk环境,但是OpenWhisk依赖多,配置比较复杂,要从头搭建一个还是比较繁琐。

    官方提供了快速搭建工具,可以快速启动一整套环境来

    git clone --depth=1 https://github.com/apache/incubator-openwhisk-devtools.git
    
    cd incubator-openwhisk-devtools/docker-compose
    
    make quick-start

    会基于Docker启动openwhisk/controller,openwhisk/invoker,zookeeper,kafka,redis等组件。…

  • MySQL下的CommunicationsException问题

    这周的一天早上一个定时任务突然报错,错误如下

    ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet successfully received from the server was 67,409 milliseconds ago. The last packet sent successfully to the server was 60,060 milliseconds ago. ### The error may exist in 
  • ubuntu快速安装docker

    最近换了一个硬盘,重新装了一下系统。
    自然各种环境和工具也要重新装。

    apt install没法安装docker-ce,官方文档虽然详细,但是步骤挺多的。然后就发现官方的安装脚本,还支持镜像。

    curl -fsSL get.docker.com -o get-docker.sh

    sudo sh get-docker.sh –mirror Aliyun