蘭陵N梓記

一指流沙,程序年华


  • 首页

  • 归档

  • 关于

  • 搜索
close

飞哥讲代码9:提升性能,线程数合适就行

时间: 2020-07-18   |   分类: 技术     |   阅读: 4203 字 ~9分钟

案例

两周前,参与某一老产品的性能优化有如下收获:

  • 同事说,我配置了 1000个线程 ,但是总消耗时间还是需要 10分钟 左右,似乎没有真正的并发。
  • 经过分析代码,狂改一通代码,结果是:只配置了 32个线程 ,总消耗时间下降至 44秒 。

这个产品已有一定的年头,采用Java开发,但Maven配置的编译source/target还是 1.6(直接把配置修改为1.8整个产品编译会有问题。对于老产品,稳定优先,维护者并没有太多的动力升级到1.8,因为一升级需要对所有历史分支都升级并验证)。 为了线程安全,代码中大量地存在如下Double-Check写法(伪代码),无法享受Java高版本带来的红利,并不高效:

Description desc = cache.get(key);
if (desc == null) {
    synchronized(cache) {  // 这个是全局锁,极大影响并发
        if (desc == null) {  
            desc = getDescription(....);  // 此方法还会调用其它类似写法的Cache,主要逻辑是查询以及反射类,以及嵌套类,效率并不高
            cache = new CopyOnWriteMap(cache) // 对象Copy
            cache.add(key, desc);
        }
    }
}
return desc;
阅读全文 »

飞哥讲代码8:提升性能,线程级缓存复用

时间: 2020-07-05   |   分类: 技术     |   阅读: 2399 字 ~5分钟

案例

去年在做BCM切换进行如火如荼时,一位兄弟找到我,有如下对话:

■■(工号) 2019-08-27 14:50
飞哥,下午有时间吗?▲▲的性能瓶颈的问题想跟你讨论一下
◆◆◆(工号) 2019-08-27 14:51
好
■■(工号) 2019-08-28 10:39
飞哥,性能有提升, 8W8 压到了 9W7
提升了1W

一个下午的时间,到底发生了什么,对代码做了什么优化,性能提升将近1W TPS?

出现性能瓶颈的组件是平台一个很成熟的中间件,从x86切换到arm下性能基准测试情况如下:

  • 组网:3 client + 1 server
  • 环境:4VM(arm 8C64G) VS 4VM(x86 8C64G)
  • 基准测试:TPS x86 VS arm = 1 VS 0.6
阅读全文 »

飞哥讲代码7:消除重复,需要脚本模块化

时间: 2020-06-27   |   分类: 技术     |   阅读: 2936 字 ~6分钟

案例

这次就不上代码了。情况是这样的,我们某一新产品,采用微服务架构,每个微服务独立的源码仓:

  • 每个服务都要支持手工安装,DF部署,容器部署。
  • 每个服务都要支持修改密钥,密码等。
  • 每个服务都要支持容灾,WatchDog等

上面的功能实现都需要采用Shell脚本,当搞定一个服务时,只需要复制到其它的服务,是最为常见的做法。但这种做法也带来了大量的重复,导致维护极其困难。真是拷贝一时爽,维护成了火葬场。主要问题表现:

  • 服务内重复: 同一服务内脚本不同场景下复制粘贴,如手工安装与DF部署,都需要创建OS用户,没有抽取公共函数复用
  • 服务间重复: 不同服务间脚本复制粘贴,如同样是修改密码,只是配置文件路径不一样,配置项略有差别,没有抽取公共脚本复用。
  • 缺少封装性: 部分脚本从头到尾没有任何函数提取,大块脚本从顶写到尾,全局变量到处飞,阅读极其困难。
  • 健壮性不足: 脚本中的操作没有判断返回值或退出状态码,脚本没有太多的可靠性的防护。
阅读全文 »

飞哥讲代码6:消除重复,需要配置代码分离

时间: 2020-06-21   |   分类: 技术     |   阅读: 2198 字 ~5分钟

案例

下面的代码来自我们某一平台产品前端源码(Java语言)中:

private static Map<String, Map<String, String>> constructConstrainMap() {
    Map<String, Map<String, String>> typeConstrainMap = new HashMap<String, Map<String, String>>();
    Map<String, String> imageConstrainPatternMap = new HashMap<String, String>();
    imageConstrainPatternMap.put("allowdPatten", "^[a-zA-Z0-9_~.=@-]$");
    imageConstrainPatternMap.put("allowdMin", "1");
    imageConstrainPatternMap.put("allowdMax", "256");
    imageConstrainPatternMap.put("allowdValue", null);
    imageConstrainPatternMap.put("noEcho", "false");
    imageConstrainPatternMap.put("description", "com.huawei.....");
    typeConstrainMap.put(TPropType.IAA_S_IMAGE_ID.value(), imageConstrainPatternMap)

    Map<String, String> netWorkConstrainPatternMap = new HashMap<String, String>();
    // 省略 put ...

    Map<String, String> containerConstrainPatternMap = new HashMap<String, String>();
    // 省略 put ...

    // 省略 其它的Constrain代码 ...
}

上面的代码在一个方法中构造了16个Constrain,它是提供给BME控件用于输入框的校验。显然代码出现了重复(相似),也较容易想到采用外部配置文件方式来简化样板代码,但采用什么配置方式呢?

阅读全文 »

飞哥讲代码5:消除重复,需要搞点设计模式

时间: 2020-06-13   |   分类: 技术     |   阅读: 4367 字 ~9分钟

案例

下面的代码来自我们某一平台产品源码(Java语言)中:

public class RemoteExecuteHandler {
    public Future<RemoteExecuteResult> handleDownload() throws SspException {
        try {
            initSshClient();
            Future<RemoteExecuteResult> feture = downloadPackage();
            return feture;
        } catch (SspException e) {
            LOGGER.error("CMC download package failed", e);
            closeSshClient();
            throw e;
        }
    }

    public Future<RemoteExecuteResult> handleLoad() throws SspException {
        try {
            initSshClient();
            Future<RemoteExecuteResult> feture = loadPackage();
            return feture;
        } catch (SspException e) {
            LOGGER.error("Load site package failed", e);
            closeSshClient();
            throw e;
        }
    }

    // 下面还有几个类似的方法,不再一一列表
}

上面的代码较直观地出现重复(相似),除了执行具体的动作与日志不一样,都是样板代码。当然还存在其它问题:

阅读全文 »

飞哥讲代码4:消除重复,需要了解框架机制

时间: 2020-06-05   |   分类: 技术     |   阅读: 4224 字 ~9分钟

案例

下面的代码来自我们某一平台产品源码(Java语言)中(代码一):

public class ServiceFactory {
    private static ServiceFactory instance = new ServiceFactory();

    public static ServiceFactory getInstance() {
        return instance;
    }

    @Getter 
    @Setter
    @Autowired 
    private AppTemplateDesignServie appTemplateDesignServie;
   
    @Getter 
    @Setter
    @Autowired 
    private AppTemplateExportServie appTemplateExportServie;
    
    // 下面还有十多个Service对象注入,提供Getter与Setter,不再一一列出
}

再来看另一平台服务的代码(Java语言)(代码二):

阅读全文 »

飞哥讲代码3:简洁高效的线程安全

时间: 2020-05-31   |   分类: 技术     |   阅读: 3381 字 ~7分钟

案例

下面的代码来自我们某一中间件产品源码(Java语言)中(写法一):

// ConcurrentMap<String, AtomicLong> rejectMessageCounts = new ConcurrentHashMap<>();
private AtomicLong getRejectMessageCount(String serviceName) {
    AtomicLong rejectMessageCount = rejectMessageCounts.get(serviceName);
    if (null == rejectMessageCount) {
        rejectMessageCount = new AtomicLong();
        AtomicLong currentValue = rejectMessageCounts.putIfAbsent(serviceName, rejectMessageCount);
        if ( null != currentValue) {
            rejectMessageCount = currentValue;
        }
    }
    return rejectMessageCount;
}

上面的代码是线程安全的,但不够简洁,Java 1.8的ConcurrentMap提供computeIfAbsent()方法,可以简化为(写法二):

private AtomicLong getRejectMessageCount(String serviceName) {
    return rejectMessageCounts.computeIfAbsent(serviceName, (key)-> new AtomicLong());
}
阅读全文 »

飞哥讲代码2:把大象装进冰箱要几步

时间: 2020-05-23   |   分类: 技术     |   阅读: 1806 字 ~4分钟

案例

下面的代码来自我们某一老产品源码(C语言)中:

VOS_INT STARTER_Download(VOD_VOID) {
    VOS_UINT32 count, sleepTimeLen;
    VOS_CHAR ascExcuteFile[INSTALL_MAX_DIRNAME_LEN]={ 0 };
    VOS_BOOL enIsHaveUpdateOk = VOS_FALSE;
    VOS_INT siRet;

    BOOTTRACE(TRACE_TIP, "Checking and updating files...");

    if(LOAD_Init()==VOS_FALSE) {
        BOOTTRACE(TRACE_ERR, "The LOAD Init return error");
        return VOS_ERR;
    }

    siRet=LOAD_Begin(LD_STAGE_INSCHK, &g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
    if(siRet != VOS_OK) {
        LOAD_End();
        BOOTTRACE(TRACE_ERR, "The LOAD Begin return error");
        return VOS_ERR;
    }

    while(VOS_TRUE) {
        for(count=0;count<g_downloadFileCount;count++) {
            if (g_pstFileListInfo[count].enLoadCheckResult == LS_SUCESS_UPDATE ) {
                enIsHaveUpdateOk = VOS_TRUE;
            }
        }

        for(count=0;count<g_downloadFileCount;count++) {
            if (g_pstFileListInfo[count].enLoadCheckResult != LS_SUCESS_UPDATE &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_NOT_NEED_UPDATE) &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE)) {
                BOOTTRACE(TRACE_ERR, "update file %s error and result=%d",
                    g_pstFileListInfo[count].acFileName,
                    g_pstFileListInfo[count].enLoadCheckResult);
                break;
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (enIsHaveUpdateOk == VOS_TRUE) ) {
                BOOTTRACE(TRACE_ERR, "Not all files are updated,download these file again");
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &&
                (enIsHaveUpdateOk == VOS_TRUE) ) {
                BOOTTRACE(TRACE_ERR, "Not all files version are consistent with inschk,download these file again");
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
                BOOTTRACE(TRACE_ERR, "Fail to connect witch OMU server and local file %s is uncertain, I will still download these files", g_pstFileListInfo[count].acFileName);
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &&
                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
                BOOTTRACE(TRACE_ERR, "OMU fesuse to update and %s local check result=%d or some file updated", g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].bLocalCheck);
                break;    
            }

            if (g_pstFileListInfo[count].ucFileType == PROG_FILE_TYPE ) {
                siRet = snprintf_s(ascExcuteFile, sizeof(ascExcuteFile),  sizeof(ascExcuteFile)-1,
                         "%s/%s", g_pstFileListInfo[count].acFileExecuteDir, g_pstFileListInfo[count].acFileName);
                if (siRet <= 0 ) {
                    BOOTTRACE(TRACE_ERR, "[%s:%d] snprintf_s failed,", __FUNCTION__, __LINE__);
                    break;
                }
                (void)chmod(ascExcuteFile, S_IRUSE | S_IXUSR);
            }
        }

        if (count == g_downloadFileCount) {
            BOOTTRACE(TRACE_TIP, "All %d files checked or updated OK.", g_downloadFileCount);
            for(count=0;count<g_downloadFileCount;count++) {
                BOOTTRACE(TRACE_LOD, "%d update result is %d and local check result is %d.",
                 g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].enLoadCheckResult,
                 g_pstFileListInfo[count].bLocalCheck);
            }
            break;
        } else {
            if (g_pstFileListInfo[count].enLoadCheckResult == LS_DISK_FULL){
                sleepTimeLen=INSTALL_DISK_FULL_AGAIN_TIMELEN;
            } else {
                sleepTimeLen=INSTALL_CONNECT_OMU_AGAIN_TIMELEN;
            }

            BOOTTRACE(TRACE_ERR, "Update file error so sleep for %d second and try again", sleepTimeLen);
            SLEEP(sleepTimeLen);

            siRet=LOAD_Begin(LD_STAGE_INSCHK, &g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
            if(siRet != VOS_OK) {
                LOAD_End();
                BOOTTRACE(TRACE_ERR, "The LOAD Begin return error");
                return VOS_ERR;
            }
        }
    }

    BOOTTRACE(TRACE_DBG, "Exit STARTER_Download");
    LOAD_End();
    return VOS_OK;
}

上面的代码我已是删除了每个条件判断的注释,但是代码看起还是有点长。如果不仔细读,还真不看出不函数完成的功能。再来看优化重构之后的代码:

阅读全文 »
1 2 3 4 5 6 7 8 9
兰陵子

兰陵子

Programmer & Architect

164 日志
4 分类
57 标签
RSS 订阅
GitHub 知乎
© 2009 - 2022 蘭陵N梓記
Powered by - Hugo v0.101.0
Theme by - NexT
0%