Jenkins使用痛点小析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jenkins使用痛点小析相关的知识,希望对你有一定的参考价值。

参考技术A

Jenkins 刚开始搭建的时候,我们惊叹,这也太方便了吧?功能还这么强,慢慢的,我们会发现对方的缺点了,嗯,恋爱的味道,不对,似乎扯远了,还是说回来 Jenkins 了。

我们很难想象 Jenkins ,这么庞大的一个应用,居然没有数据库。那配置在哪保存呢?运行日志了?构建数据了?等等这些都是需要保存的啊。

屏幕快照 2019-12-19 下午8.29.10.png 屏幕快照 2019-12-19 下午8.29.10.png

当jenkins job数量达到一定量级,访问量大时候,会非常卡顿,仿佛回到了零几年的时候,网页那么卡。
查原因我们会发现瓶颈在 I/O 。因为jenkins每次访问,都需要读取配置,都需要读写日志,这些都是以文件方式写入磁盘的,是 所有slave 节点和 一台master 通信。
可是我们是没有办法做负载均衡的

当我们部署后端服务时候,肯定做 LB(负载均衡) , Jenkins master 因为只能单节点,啊,挂了master,所有slave都掉链子了。

配置 存储 master节点磁盘,嗯,还好,比较小
构建日志 存储在master节点磁盘,这个,百万行代码的编译日志几百M大小,每天N个业务构建M次,存储在master,哈哈,每天上班第一件事清磁盘?
构建产物 存储在master节点磁盘,这个,占磁盘,不安全

针对这种情况了,日志用 ELK ,产物放到到 对象存储

调度,一个好高深的话题,教材上学过操作系统对进程的各种调度算法,什么 先入先出 最短耗时 最高优先级(PRI,NI) 等等,而类似的集群调度, k8s 可能是最常见的了,但是 Jenkins 对于任务调度这块,实际来讲,确实很弱, 虽然 调度 也是 Jenkins 的核心能力之一

k8s 里面有 node节点 概念, Jenkins 也有
k8s 里面有 pod 概念, Jenkins 没有,类似的, Jenkins 是限制 node 的最大并行个数
k8s 里面有调度器, 进行 Predicates Priorities 两个过程, Jenkins 算法很简单,默认就是调度到 最近一次成功节点 上。

这样会带来一个比较严重的问题,会导致 部分机器处于极度打满,部分机器确空转,资源利用率严重两级分化

针对这点,我们其实有两种小的补救。
一种是降低node节点并行数量,比如原来是最大限制是10,下降到2后,第三个任务,比如调度另一个节点了,缺点就是可能造成更多排队情况
一种就是利用插件了,比如插件 throttle-concurrents 会比较均匀分配 https://plugins.jenkins.io/throttle-concurrents

总体而言,调度这块,Jenkins确实有很长路走

微服务 相比 单体应用 似乎高大上了很多,我们把服务抽象出来,只专注于某一部分,然后各个部分串联起来。
Jenkins 里面,一次构建,我们可能会写一个长长的脚本,举例子来说,我们需要构建一个移动端产物apk/ipa, 我们需要
clone code -> 更新依赖库 -> 编译 -> 产物保存 -> 分发到商店
传统上,我们可以把这一串代码都写到 job 配置里面,但更好的做法,我们是把每一步抽象出来,每一步都是一个服务(一个job)

怎么串联起来呢? 没有流水线之前,是 Jenkins 上下游任务关联 , 哈哈,当任务量多了,我们发现,调用链很难捋清楚了,当然微服务里面有自己的解决办法 - 链路追踪,网关

流水线 ,可以帮我们把这些串联起来,我们最后需要管理的只是流水线

小思考,不足之处,欢迎交流

Android Hook Dexposed原理小析

dexposed是阿里巴巴在xposed框架上面开发的hotpatch一套框架

当然hotpatch的方式有很多,这里先介绍下dexposed原理

Demo中有个test函数, 在调用hook之前正常返回”11111”; 调用hook之后, 却返回”newTestMethod”, 被我们给修改

public class Demo
{
    String TAG = "===[hookdemo]===";

    public static String staticTest(String param1)
    {
        return "staticTest";
    }

    public String test(String param1)
    {
        return "11111";
    }

    public void demo()
    {
        String param1 = "param1";
        Log.d(TAG, "===========before hook test:" + this.test(param1));
        hook(Demo1.class, "test", "(Ljava/lang/String;)Ljava/lang/String;");
        Log.d(TAG, "===========after hook test:" + this.test(param1));

        Log.d(TAG, "===========before hook staticTest:" + this.staticTest(param1));
        hook(Demo1.class, "staticTest", "(Ljava/lang/String;)Ljava/lang/String;");
        Log.d(TAG, "===========after hook staticTest:" + this.staticTest(param1));
    }

    private native void hook(Class<?> clazzToHook, String methodName, String methodSig);
}

ndk 中的部分

#include <jni.h>
#include "log.h"
#include "Dalvik.h"

static void showMethodInfo(const Method* method)
{
    //看看method的各个属性都是啥:
    LOGD("accessFlags:%d",method->accessFlags);
    LOGD("clazz->descriptor:%s",method->clazz->descriptor);
    LOGD("clazz->sourceFile:%s",method->clazz->sourceFile);
    LOGD("methodIndex:%d",method->methodIndex);
    LOGD("name:%s",method->name);
    LOGD("shorty:%s",method->shorty);
}

/**
 * 使用jni GetMethodID 方法获取jmethodID 强制转为 Method 的hook 方法 示例
 */
static void newTestMethod(const u4* args, JValue* pResult,
                          const Method* method, struct Thread* self) {

    // args 是原来函数的参数数组, 原来test函数只有一个String型参数
    // 并且要注意, 如果是不是static函数, 下标0 是函数所在类的实例obj
    // 在dvm中Object,  jni 中的jobject 和 java 中的 Object类 都不是同一个东西
    // String类对应StringObject
    // 取出参数打印出来看看
    StringObject* param1 = NULL;

    if(dvmIsStaticMethod(method))
        param1 = (StringObject*)args[0];
    else
        param1 = (StringObject*)args[1];
    LOGD("param1:%s",dvmCreateCstrFromString(param1));

    //JValue 是个union ,要返回int 就 pResult->i=1; 返回Object对象就 pResult->l = ojb;
    // 但是, 在dvm中的Object,  jni 中的jobject 和 java 中的 Object类 都不是同一个东西
    // 所以, 我们这里使用dvm的函数来创建一个StringObject*
    pResult->l = dvmCreateStringFromCstr("newTestMethod");

    // 一般情况应该使用宏 : RETURN_XXX(result);
    return;
}

extern "C" JNIEXPORT void JNICALL
Java_com_zhaoxiaodan_hookdemo_Demo1_hook(JNIEnv *env, jobject instance, jobject clazzToHook,
                                                jstring methodName_, jstring methodSig_) {

    const char *methodName = env->GetStringUTFChars(methodName_, 0);
    const char *methodSig = env->GetStringUTFChars(methodSig_, 0);

    jmethodID methodIDToHook = env->GetMethodID((jclass) clazzToHook,methodName,methodSig);

    // 找不到有可能是个static
    if(nullptr == methodIDToHook){
        env->ExceptionClear();
        methodIDToHook = env->GetStaticMethodID((jclass) clazzToHook,methodName,methodSig);
    }


    if(methodIDToHook != nullptr)
    {
        //主要在这里替换
        //jmethodID 在dvm里实际上就是个Method 结构体
        Method* method = (Method*) methodIDToHook;

        //看看method的各个属性都是啥:
        showMethodInfo(method);

        //设置Method 的 accessFlags 为 枚举型
        // ACC_NATIVE 表示 这个method 切换成了一个native 方法
        // 这个枚举 在 dalvik/libdex/DexFile.h
        // 类似:
        // ACC_PUBLIC       = 0x00000001,       // class, field, method, ic
        // ACC_PRIVATE      = 0x00000002,       // field, method, ic
        // ACC_PROTECTED    = 0x00000004,       // field, method, ic
        SET_METHOD_FLAG(method, ACC_NATIVE);

        //既然是一个native方法, 那就把 nativeFunc 指针指向我们的hook, 用来替换test的新方法
        method->nativeFunc = &newTestMethod;

        // registersSize是函数栈大小, insSize是参数占用大小
        // 如果是native方法, 就没有额外开销了
        // 所有开销就是参数占用, 所以把它设置成跟参数占用空间
        method->registersSize=method->insSize;

        //未知
        method->outsSize=0;
    }

    env->ReleaseStringUTFChars(methodName_, methodName);
    env->ReleaseStringUTFChars(methodSig_, methodSig);
}

原理就是, Method结构体表示了一个java层函数, 而其中的accessFlags属性如果是ACC_NATIVE ,

dvm在call 原java层函数的时候, 则会转向调用 属性nativeFunc 所指向的函数

所以我们把不是native的java层函数的accessFlags强制改为ACC_NATIVE, 然后把nativeFunc 指向我们的新函数,

则完成了方法的修改只不过, 这里使用native方法替换了java层的原方法

 

以上是关于Jenkins使用痛点小析的主要内容,如果未能解决你的问题,请参考以下文章

Jenkins常用插件介绍

Jenkins的“Build Monitor View” 插件:助力监控所有Pipeline执行状态

Jenkins的“Build Monitor View” 插件:助力监控所有Pipeline执行状态

今晚8点!使用 Jenkins + Artifactory + Kubernetes 实现应用自动化持续发布

Jenkins和Gitblit集成实现提交后自动构建

[京东云][centos]配置VNC,部署Jenkins