前端调用rpc接口_api接口调用

前端调用rpc接口_api接口调用问题背景需要根据id通过rpc调用查询具体信息,因为没有提供批量查询的接口,所以做法是挨个遍历查询,那意味着:如果有100个id,就需要顺序进行100次rpc调用,假设每次rpc接口的调用时间是50ms(这个速度很快了),那单单rpc调用就要占用5s,所以接口的响应会非常慢。下面进行优化。优化方案:方案一:让服务方提供批量查询接口,需要服务提供方配合,这里暂不采用。方案二:rpc服务的调用由顺序调用修改为并行调用,采用线程池实现rpc的并发调用。具体实现如下:1)创建线程的类public

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

问题背景
需要根据id通过rpc调用查询具体信息,因为没有提供批量查询的接口,所以做法是挨个遍历查询,那意味着:
如果有100个id,就需要顺序进行100次rpc调用,假设每次rpc接口的调用时间是50ms(这个速度很快了),那单单rpc调用就要占用5s,所以接口的响应会非常慢。下面进行优化。

优化方案:
方案一:让服务方提供批量查询接口,需要服务提供方配合,这里暂不采用。
方案二:rpc服务的调用由顺序调用修改为并行调用,采用线程池实现rpc的并发调用。

具体实现如下:
1)创建线程的类
public class MyThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {

        return new Thread(r);
    }
}

2)创建线程处理类,因为需要获取rpc调用的结果所以是实现callable类
说明:这里需要获取spring提供的bean,获取方式是通过参数传入
public class RegisterTask implements Callable {

    private String  registerId;
    private String  cityCode;
    // 这里需要获取spring提供的bean,获取方式是通过参数传入
    private RegisterClient registerClient;
    public RegisterTask(String registerId, RegisterClient registerClient, String  cityCode){

        this.registerId = registerId;
        this.cityCode = cityCode;
        this.registerClient = registerClient;
    }

    @Override
    public List<StudentLessonDto> call() throws Exception {

        // 这里就是进行rpc调用
        return registerClient.queryLessonsByRegistId(registerId, cityCode);
    }
}

3)方法getDetail()内部创建线程池
        ThreadFactory namedThreadFactory = new MyThreadFactory();
        int queueCapacity = 10000, corePoolSize = 10, maximumPoolSize = 10;
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(queueCapacity);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 10, TimeUnit.SECONDS, arrayBlockingQueue, namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

4) 方法getDetail()内部线程池提交线程,并获取执行的结果
        // 线程池进行rpc调用
        ArrayList<Future<List<StudentLessonDto>>> futures = new ArrayList<>();
        for (String id : registerIdList) {

            Future future = threadPoolExecutor.submit(new RegisterTask(id, registerClient, cityCode));
            futures.add(future);
        }

        // 获取线程调用的结果
        for (Future future : futures) {

            try {

                List<StudentLessonDto> list = (List<StudentLessonDto>) future.get();
                if (!CollectionUtils.isEmpty(list)) {

                    result.put(list.get(0).getRegistId(), list);
                }
            } catch (InterruptedException e) {

                log.error(“并发获取报名的讲次异常”, e);
            } catch (ExecutionException e) {

                log.error(“并发获取报名的讲次异常”, e);
            }
        }

之后经过测试和上线。

结果:
第一天没啥问题,第二天开始有问题,主要现象如下:
1) 服务调用异常,异常信息大致如下:
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:503)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(
    …….
Caused by: java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
    at java.base/java.lang.Thread.start0(Native Method)

2)机器无法登陆,异常如下:
root:fork failed: Cannot allocate memory

内存耗用的一干二净,root都没有内存了。最后重启机器才行。

下面定位问题:
最近新上的代码,肯定是我的新增的多线程部分除了内存,耗费了大量内存,但是怎么解释呢??
说明肯定是线程资源没有得到释放,但是我是在方法内部创建的线程池,方法执行后按道理对应的线程池和线程资源应该会释放的(我个人错误的理解)。

但是看到一篇博客(https://blog.csdn.net/lbh199466/article/details/104934207/),
因为核心线程一直没有释放,所以对应的线程池和线程资源并没有释放。

栈中的引用对象就是一种GcRoots, 所以如果核心线程一直不被回收,那么对应的线程与对象资源都不会被回收。线程栈和线程中的对象占用的对象都不会释放。引用关系:ThreadPoolExecutor->Worker->thread,然后因为thread一直不释放,所以对应的worker和池资源也都会不会释放。
所以:
方法内部定义线程池,核心线程数不为零,核心线程不会被回收,导致相关内存资源都不会被释放。
也可以参考:https://zhuanlan.zhihu.com/p/72515308

查看java进程中的线程的个数
验证上面的结论,参考https://blog.csdn.net/blueheart20/article/details/78905267(获取当前进程数的方法)
获取当前服务器上java进程的线程个数。下面挺一种实例
jps 获取java进程pid
top -Hp pid 获取进程中的线程个数 如 Threds:1190 total,代表进程中有1190个线程,可以的确看到当前线程数很多

最终解决方案:
1)参考 https://www.cnblogs.com/qxynotebook/p/7398882.html
在线程池中,有核心线程,对于核心线程超时也回收,所以,需要确保核心线程超时之后也被回收。
解决办法:在结果返回之前设置核心线程也回收:
threadPoolExecutor.allowCoreThreadTimeOut(true);
2)参考:https://blog.csdn.net/wchgogo/article/details/78185643(unable to create new native thread)
栈对内存的消耗:目前没有像堆那样指定最大占用内存,设置Xss指点单个线程的占用内存大小,默认线程占用空间时1M,可以设置为512k。

服务器中影响最多线程数的因素:
1)内存,线程肯定是占用内存的,如果内存耗尽,那自然不能继续创建线程。
单个线程占用内存大小可通过-Xss设置,现在默认1M,一般建议512k就够了。
如果Xss设置过大,则浪费内存空间;
如果Xss设置过小,代码中有遍历或递归导致调用太深的时候,就有可能耗尽StackSpace,爆出StackOverflow的错误;

2)机器设置的最大线程数
操作系统会限制进程允许创建的线程数,使用ulimit -u命令查看限制。某些服务器上此阈值设置的过小,比如1024。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183301.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 树莓派3B+ 人脸识别(OpenCV)

    树莓派3B+ 人脸识别(OpenCV)树莓派3B+人脸识别(OpenCV)相信大家都看了前面的OpenCV安装和人脸检测教程,有了基础后,现在我们正式进入重头戏——人脸识别的教程。注意:该教程面向python2.7+OpenCV2.4.9(官方源)其它版本需进行一些小的修改,文中会具体注明。1.生成人脸识别数据目录结构./data数据根目录./data/gener…

    2022年6月25日
    20
  • 手写代码实现卷积操作(Python)

    手写代码实现卷积操作(Python)在卷积神经网络中,才用卷积技术实现对图片的降噪和特征提取。一般我们构建卷积神经网络都是使用成熟的框架,今天我就来自己实现一下卷积,并使用不同的卷积核来看看效果。卷积操作的原理可以由下图表示:一个3*3的卷积核,以滑动窗口的形式在图片上滑动,每滑动一次,就计算窗口中的数据的加权之和,权值就是卷积核的数据。通过这个过程将图片进行转化。准备图片数据:使用P…

    2022年5月28日
    53
  • 博弈论案例分析题及答案_微软技术支持面试题

    博弈论案例分析题及答案_微软技术支持面试题相信下面这个问题很多人都见过,博弈论中经典案例–“强盗分金”,测试一下自己的逻辑是否正确五个海盗抢到了100颗宝石,每一颗都一样大小和价值连城。他们决定这么分:  抽签决定自己的号码(1、2、3、4、5)  首先,由1号提出分配方案,然后大家表决,当且仅当超过半数的人同意时,按照他的方案  进行分配,否则将被扔进大海喂鲨鱼  如果1号死后,…

    2022年10月16日
    0
  • 简述python中的数字类型有哪些_python中都有哪些数据类型

    简述python中的数字类型有哪些_python中都有哪些数据类型python中数据类型有:整型、长整型、浮点型、字符串类型、布尔类型、列表类型、元组类型、字典类型、集合类型。数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语言,数据类型类似,但具体表示方法有所不同,以下是Python编程常用的数据类型:1.数字类型Python数字类型主要包括int(整型)、long(长整型…

    2022年5月26日
    53
  • 手机设备上touchstart与click的区别

    手机设备上touchstart与click的区别1.基本定义touchstart手指触碰开始就能触发click1.手指触碰2.手指未在屏幕上移动3.在这个dom上手指离开屏幕4.触摸和离开屏幕之间的时间间隔较短因此,click事件有其独特的地方,不能完全用touchstart替代。2.click延时问题因为手机浏览器上,两次轻触是放大操作,在第一次被轻触后,浏览器需要先等一段时间,检…

    2022年6月22日
    32
  • 函数重载与函数重写(有的书也叫做“覆盖”)的区别

    函数重载与函数重写(有的书也叫做“覆盖”)的区别

    2021年9月29日
    40

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号