王二麻子个人博客

愿居于一城,与卿所见美好......

推荐文章

在windows下切换node版本,很简单!

    如果您很忙或者很急 请直接阅读 三、【步骤】

    一、【问题背景】

    生活里偶尔穿梭在大街小巷中,工作中时常并行于多项目任务里......
    当多个项目并行时,由于创建的时间或人为选择等因素,各个项目里有着差异的node版本,这样我们在不同的项目里需要切换不同版本的Node.js,所以nvm应运而生。

    二、【NVM】

    NVM (Node Version Manager): Nodejs的版本管理工具
    早期的nvw只支持Linux 和Mac,而window用户较多使用的是nvmw。但最近由于重装系统偶然发现已有更新nvm支持window,而且快捷方便,不需要设置环境变量。

    三、【步骤】
    • 如果已经安装过node版本,请先自行卸载,这一步很重要!!!

      npm ls -g --depth=0   // 查看全局安装中是否有早前安装的node
      
    • 卸载完后直接下载nvm安装 (推荐使用nvm-setup.zip)[地址]:https://github.com/coreybutler/nvm-windows/releases

    亲,您没有看错,就这样两步就完成了!

    这里不需要使用git去clone,也不用设置环境变量、arch等,亲测成功。

    四、【常用命令】
    nvm                  // 会提示nvw下的相关命令
    nvm ls               // 查看已安装node版本
    nvm install vXX      // 安装对应vXX版本的node
    nvm uninstall vXX    // 卸载对应vXX版本的node
    nvm use xxx          // 选择使用XXX版本
    
    
    五、【您可能遇到的坑】

    虽说简单,但常年写代码 哪有不踩坑 o(╥﹏╥)o

    • [踩坑A]:很多人反馈只有在git cmd 或 git bash(或某指定的文件夹)可以使用,但在项目文件下使用NVM无法切换

      [问题原因]:在安装nvm前安装了node版本或者安装了全局node

      [解决方案]:卸载已安装的node版本后重新安装NVM (控制面板--> 卸载程序)

    • [踩坑B]:当执行nvw install xxx 安装完指定版本时,你满心欢喜的要使用时 nvm use ...报错了,提示信息: exit status 乱码...

      [问题原因]:网上有些说安装要使用原默认目录c:盘符,也有些说要安装在根目录,其实是因为安装nvm时使用路径存在空格导致解析出错 (如:Program Files)

      [解决方案]:重新安装nvm避免路径存在空格,安装完记得重启才会生效

    • [踩坑C]:执行install 时node安装成功,但npm没成功

      [问题原因]:npm下载连接失败

      [解决方案]:nvm uninstall vxxx 卸载对应版本后 打开nvm文件夹中下的settings.txt添加以下代码添加淘宝镜像下载:

      root: D:\nvm
      path: D:\nvm\nodejs
      node_mirror: https://npm.taobao.org/mirrors/node/
      npm_mirror: https://npm.taobao.org/mirrors/npm/
      

    讲了这么多,肯定还有人觉得每次换个项目得用nvw use ...去切换,好麻烦啊!就不能自动切换呢?
    人性本懒,但懒是人类最大的生产力,也是进步的最大动力!
    所以其实这样的工具也已经存在AVN: 有兴趣的请推荐阅读:avn-Automatic Version Switching for Node


    作者:岁寒3友
    链接:https://www.jianshu.com/p/1886243db936
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    阅读全文>>

作者:王二麻子分类:【javaEE浏览(238评论(0

2020-12-25 22:22:23

Spring session redis监听导致创建大量监听线程

    Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程

    待解决的问题

    Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程:

    最近网站为了提高性能,采用spring session将session保存在redis中。结果原本1G左右内存的程序,不到一天直接涨到2G,最后OOM直接宕机,对jvm线程进行分析查看,发现session redis监听线程多达几千个;一番分析后原因如下:Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程

    解决办法

    为spring session添加springSessionRedisTaskExecutor线程池。

    /**
     * 用于spring session,防止每次创建一个线程
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor springSessionRedisTaskExecutor(){
        ThreadPoolTaskExecutor springSessionRedisTaskExecutor = new ThreadPoolTaskExecutor();
        springSessionRedisTaskExecutor.setCorePoolSize(8);
        springSessionRedisTaskExecutor.setMaxPoolSize(16);
        springSessionRedisTaskExecutor.setKeepAliveSeconds(10);
        springSessionRedisTaskExecutor.setQueueCapacity(1000);
        springSessionRedisTaskExecutor.setThreadNamePrefix("Spring session redis executor thread: ");
        return springSessionRedisTaskExecutor;
    }
    

    原因

    在Spring Session(redis)的配置类源码中(RedisHttpSessionConfiguration):

    @Autowired(
        required = false    //该处理监听的线程池不是必须的,如果不自定义默认将使用SimpleAsyncTaskExecutor线程池
    )
    @Qualifier("springSessionRedisTaskExecutor")
    public void setRedisTaskExecutor(Executor redisTaskExecutor) {
        this.redisTaskExecutor = redisTaskExecutor;
    }
    

    springSessionRedisTaskExecutor不是必须的,如果不自定义则spring默认将使用SimpleAsyncTaskExecutor线程池。

    题外话

    SimpleAsyncTaskExecutor:每次都将创建新的线程(说是“线程池”,其实并非真正的池化,但它可以设置最大并发线程数量。)
    @EnableAsync开启异步方法,背后默认使用的就是这个线程池。使用异步方法时如果业务场景存在频繁的调用(该异步方法),请自定义线程池,以防止频繁创建线程导致的性能消耗。如果该异步方法存在阻塞的情况,又调用量大,注意有可能导致OOM(线程还未结束,又增加了更多的线程,最后导致内存溢出)。@Async注解可以选择使用自定义线程池。

    它创建了SimpleAsyncTaskExecutor

    说回RedisHttpSessionConfiguration,我们接着看:

    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(this.redisConnectionFactory);
        if (this.redisTaskExecutor != null) {
            container.setTaskExecutor(this.redisTaskExecutor);
        }
    
        if (this.redisSubscriptionExecutor != null) {
            container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
        }
    
        container.addMessageListener(this.sessionRepository(), Arrays.asList(new PatternTopic("__keyevent@*:del"), new PatternTopic("__keyevent@*:expired")));
        container.addMessageListener(this.sessionRepository(), Collections.singletonList(new PatternTopic(this.sessionRepository().getSessionCreatedChannelPrefix() + "*")));
        return container;
    }
    

    RedisMessageListenerContainer正是处理监听的类,RedisMessageListenerContainer设置了不为空的redisTaskExecutor,因为spring session默认没有配置该Executor,那RedisMessageListenerContainer在处理监听时怎么使用线程呢?我们接着看RedisMessageListenerContainer的源码:

    public void afterPropertiesSet() {
        if (this.taskExecutor == null) {
            this.manageExecutor = true;
            this.taskExecutor = this.createDefaultTaskExecutor();
        }
    
        if (this.subscriptionExecutor == null) {
            this.subscriptionExecutor = this.taskExecutor;
        }
    
        this.initialized = true;
    }
    
    protected TaskExecutor createDefaultTaskExecutor() {
        String threadNamePrefix = this.beanName != null ? this.beanName + "-" : DEFAULT_THREAD_NAME_PREFIX;
        return new SimpleAsyncTaskExecutor(threadNamePrefix);
    }
    

    afterPropertiesSet()这个方法熟悉吧,这个方法将在所有的属性被初始化后调用(InitializingBean接口细节这里不再赘述)。
    所以如果用户没有定义springSessionRedisTaskExecutor,Spring session将调用createDefaultTaskExecutor()方法创建SimpleAsyncTaskExecutor线程池。而这个“线程池”处理任务时每次都创建新的线程。所以你会发现很多个redisMessageListenerContailner-X线程。

    阅读全文>>

作者:王二麻子分类:【javaEE浏览(370评论(0

2020-12-07 19:53:27

周杰伦2019新歌-说好不哭-网盘链接

    暌违两年半之久的新歌,作为周董2019年的主打歌,给粉丝带来了莫名的惊喜和感动。

    特此奉上下载链接:

    https://pan.baidu.com/s/1wRLqCPUaYE1Y4jqiSjQ7wQ

    提取码下载地址:

    http://sharehoo.cn/shop/source/136, 注册登录即可免费下载哦

    阅读全文>>

作者:王二麻子分类:【生活浏览(331评论(0

2019-09-25 21:22:50