周日处理一个spring-security的问题。顺带把spring的类加载机制和spring的security也看了一遍。
觉得spring的整个设计还是蛮有意思的。用的spring是4.3.18,后续用到的源码也都是这个版本的。
阅读全文…
记spring的XmlBeanFactory加载机制
作者: inter12
日期: 14 九月, 2020
没有评论 | 527 views
基于Junit的几个性能压测工具
作者: inter12
日期: 10 六月, 2020
没有评论 | 764 views
最近新写了一基于phoneix存储的系统,想做一下接口的压力测试
简单搜索了一下相关开源组件,找了几个不错的组件,都是基于junit整合的。ps: 搞Java的好处就是先去github找一下是否有成熟的组件,自己写太累,也不完善。
先说结论:如果你的框架没有强制依赖guava的话,那么选哪个都可以,如果强制依赖了guava的话,那么用com.github.javatlacati » contiperf
目前找了几个 :
junitperf » junitperf。最近一直更新已经是2005年了,应该早不维护了。
com.github.noconnor » junitperf : 最新的是这个2019年,最新版本是1.15.0 ,目前是支持junit5
com.github.javatlacati » contiperf : 2019年还在更新,基于junit4,它的前身是org.databene » contiperf 不过最近更新也是在2014年了
com.github.houbb » junitperf : 2020年更新,底层依赖的是 com.github.noconnor » junitperf和com.github.javatlacati » contiperf ,是对于两者的重新包装。 目前是支持junit5
组件对比
组件
|
noconnor » junitperf
|
javatlacati » contiperf
|
houbb » junitperf
|
最新junit版本
|
5
|
4
|
5
|
输出报告
|
console,html,csv,custom,multiple
|
html
|
console,html,csv,custom,multiple
|
指标
|
吞吐、min、max、avg、success、error
|
吞吐、min、max、avg、med、90线
|
同noconnor » junitperf
|
定制指标
|
可以随意定制90线,95线等指标
|
可以随意定制90线,95线等指标
|
可以随意定制90线,95线等指标
|
多线程
|
支持
|
支持
|
支持
|
结果预期
|
支持
|
支持
|
支持
|
输出
|
通过JUnitPerfRule定义
|
通过标注 report定义
|
|
参数
|
丰富
|
丰富
|
有裁剪,没有所有都支持
|
从更新时间来说,junitperf比较持续,而且功能上也没有什么区别,就采用了junitperf来做junit的集成性能测试。
houbb » junitperf 其实是包装了 noconnor » junitperf 和javatlacati » contiperf 。 是一个封装器,也改写了使用方法。
使用姿势
noconnor » junitperf的使用姿势
public class PerformanceTest { //定义输出模式,CsvReportGenerator,HtmlReportGenerator,CustomStatisticsCalculatorImpl,CustomStatisticsCalculatorImpl @Rule public JUnitPerfRule perfTestRule = new JUnitPerfRule(new ConsoleReportGenerator()); /** * threads :执行线程数 * durationMs :执行时间 * rampUpPeriodMs:平滑预热时间,默认是精致 * warmUpMs : 准备时间 * maxExecutionsPerSecond:每秒执行个数 * @throws InterruptedException */ @Test @JUnitPerfTest(threads = 50, durationMs = 125_000, rampUpPeriodMs = 2_000, warmUpMs = 10_000, maxExecutionsPerSecond = 11_000) public void test() throws InterruptedException { System.out.println("haha"); ThreadLocalRandom current = ThreadLocalRandom.current(); TimeUnit.SECONDS.sleep(current.nextInt(10)); } }
houbb » junitperf 使用姿势
/** * @author lukexue * @create 2020-06-10 15:02 **/ public class PerformanceTest2 { /** * 配置:2个线程运行。准备时间:1000ms。运行时间: 2000ms。 * 要求:最快不可低于 210ms, 最慢不得低于 250ms, 平均不得低于 225ms, 每秒运行次数不得低于 4 次。 * 20% 的数据不低于 220ms, 50% 的数据不得低于 230ms; * reporter : 输出格式html */ @Test @JunitPerfConfig(threads = 50, warmUp = 10000, duration = 125000, reporter = {ConsoleReporter.class}) //ConsoleReporter,HtmlReporter @JunitPerfRequire(min = 210, max = 250, average = 225, timesPerSecond = 4, percentiles = {"20:220", "50:230"}) public void test() throws InterruptedException { System.out.println("haha"); ThreadLocalRandom current = ThreadLocalRandom.current(); TimeUnit.SECONDS.sleep(current.nextInt(10)); } }
结果输出
最终结果输出
</div> <div>15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Started at: 2020-06-10 15:07:26.854 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Invocations: 1340 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Success: 1340 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Errors: 0 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Thread Count: 50 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Warm up: 10000ms 15:09:31.976 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Execution time: 125000ms 15:09:31.977 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Throughput: 11/s (Required: 4/s) - PASSED 15:09:31.978 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Min latency: 0.003639ms (Required: 210.0ms) - PASSED 15:09:31.978 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Max latency: 9005.115ms (Required: 250.0ms) - FAILED 15:09:31.979 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Ave latency: 4351.276ms (Required: 225.0ms) - FAILED 15:09:31.979 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Percentile: 50% 4004.3013ms (Required: 230.0ms) - FAILED 15:09:31.980 [main] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Percentile: 20% 1004.48737ms (Required: 220.0ms) - FAILED 15:09:31.982 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Started at: 2020-06-10 15:07:26.854 15:09:31.982 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Invocations: 1340 15:09:31.982 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Success: 1340 15:09:31.982 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Errors: 0 15:09:31.982 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Thread Count: 50 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Warm up: 10000ms 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Execution time: 125000ms 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Throughput: 11/s (Required: 4/s) - PASSED 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Min latency: 0.003639ms (Required: 210.0ms) - PASSED 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Max latency: 9005.115ms (Required: 250.0ms) - FAILED 15:09:31.983 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Ave latency: 4351.276ms (Required: 225.0ms) - FAILED 15:09:31.984 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Percentile: 50% 4004.3013ms (Required: 230.0ms) - FAILED 15:09:31.984 [pool-2-thread-1] INFO com.github.houbb.junitperf.core.report.impl.ConsoleReporter - Percentile: 20% 1004.48737ms (Required: 220.0ms) - FAILED</div> </div> <div>
唯一的遗憾是包是强依赖与 guava,如果你自己用了guava版本比它还低的话就跑不起来,因为我的业务也用了hbase,里面依赖的低版本的guava,结果很尴尬。这个也是java的问题
参考资料:
https://segmentfault.com/a/1190000015722861
https://github.com/houbb/junitperf
https://github.com/noconnor/JUnitPerf#multiple-reports
yarn 设计之 Dispatcher
作者: inter12
日期: 10 十二月, 2019
没有评论 | 1,137 views
Dispatcher是yarn代码中使用场景比较多的一个类,整体的设计思路是一个生产者和消费者模型,不过支持的多生产者和多消费者的模式。
不同的生产者和消费者之间通过一个Map<Class<? extends Enum>, EventHandler> eventDispatchers 来映射,数据传递通过一个无界的BlockingQueue来持有,消费是启动一个Thread来做处理。Thread是同步的根据注册的类型,切换不同的handler来处理,这个过程是同步的。
所有的handler实现EventHandler接口或者是MultiListenerHandler,MultiListenerHandler的实现是为了满足一个事件有不同的事件通知,其中EventHandler是一对一的消息模型,MultiListenerHandler是一对多的消息模型。
事件继承AbstractEvent类
具体实现上有 MultiThreadedDispatcher、AsyncDispatcher两种
AsyncDispatcher:单线程的事件生产和消费消息
MultiThreadedDispatcher : 持有多个AsyncDispatcher,也就是一个AsyncDispatcher集合,添加事件时候通过轮训的方式添加到对应的AsyncDispatcher中,每个AsyncDispatcher维护自己的异步消费线程。
落地的场景有以下几种:
ResourceManager — AsyncDispatcher
————————————————
注册的事件类型 –> 事件的处理类RMAppEventType –> ApplicationEventDispatcherRMAppAttemptEventType –> ApplicationAttemptEventDispatcherNodesListManagerEventType –> NodesListManagerSchedulerEventType –> SchedulerEventDispatcherRMNodeEventType –> NodeEventDispatcherRMAppManagerEventType –> RMAppManagerAMLauncherEventType –> ApplicationMasterLauncherRMFatalEventType –> ResourceManager.RMFatalEventDispatcher
RMApplicationHistoryWriter — MultiThreadedDispatcher
————————————————
WritingHistoryEventType –> ForwardingEventHandlerdispatcher个数 :yarn.resourcemanager.history-writer.multi-threaded-dispatcher.pool-size=10
SystemMetricsPublisher — MultiThreadedDispatcher
————————————————
SystemMetricsEventType –> ForwardingEventHandlerdispatcher个数 :yarn.resourcemanager.system-metrics-publisher.dispatcher.pool-size=10
CommonNodeLabelsManager — AsyncDispatcher
————————————————
NodeLabelsStoreEventType –> ForwardingEventHandler
NodeManager — AsyncDispatcher
————————————————
ContainerManagerEventType –> ContainerManagerImplNodeManagerEventType –> NodeManager
ContainerManagerImpl — AsyncDispatcher
————————————————
ContainerEventType –> ContainerEventDispatcherApplicationEventType –> ApplicationEventDispatcherLocalizationEventType –> ResourceLocalizationServiceContainersMonitorEventType –> ContainersMonitorContainersLauncherEventType –> ContainersLauncherLogHandlerEventType –> LogHandlerSharedCacheUploadEventType –> SharedCacheUploadService
ResourceLocalizationService 复用的是ContainerManagerImpl的AsyncDispatcher
————————————————
LocalizerEventType –> LocalizerTracker
如果发现AsyncDispatcher 异步下发性能不够的话,一般会看到这个日志
Size of event-queue is 1000
Size of event-queue is 2000
说明下游的handler处理性能不行了
原生的日志里面有一个问题,不好的点就是 不知道是哪块的逻辑处理性能不行,日志只到AsyncDispatcher级别,有点烦人
slf4j + log4j + commons log 的相关配置
作者: inter12
日期: 19 八月, 2019
没有评论 | 1,193 views
之前一直没有系统的整理 日志依赖相关的包,最近恰好查一个问题,需要在一个最简单的环境下,打印日志。就花了点时间整理了一下各个日志包之间的使用关系。
阅读全文…
hdfs-namenode之间自动ha切换过程
作者: inter12
日期: 17 四月, 2019
没有评论 | 2,118 views
整个namenode之间的ha保证是通过ZKFC这个组件来完成的。
阅读全文…
datanode同namenode之间的几个心跳
作者: inter12
日期: 4 四月, 2019
没有评论 | 2,732 views
heartBeat : dfs.heartbeat.interval 默认是3秒
阅读全文…
hdfs dfsadmin setBalancerBandwidth 命令解析
作者: inter12
日期: 28 三月, 2019
没有评论 | 3,378 views
hdfs dfsadmin -setBalancerBandwidth 这个命令是datanode做balance或者mover时候一个比较核心的参数配置
阅读全文…
hive on spark 折腾记
作者: inter12
日期: 27 二月, 2019
没有评论 | 1,671 views
搞这个的原因是因为不想走spark sql,历史包袱太重。所以折衷的使用 hive on spark
有两种形式可以设置hive on spark .
一种是修改hive-site.xml 中的配置
另一种是讲spark目录下的spark-default.conf文件copy到$HIVE_HOME/conf 目录下
两者的效果是一样的
<property> <name>hive.execution.engine</name> <value>spark</value> </property> <property> <name>hive.enable.spark.execution.engine</name> <value>true</value> </property> <property> <name>spark.home</name> <value>/data/service/spark</value> </property> <property> <name>spark.master</name> <value>yarn</value> </property> <property> <name>spark.submit.deployMode</name> <value>cluster</value> </property> <property> <name>spark.eventLog.enabled</name> <value>true</value> </property> <property> <name>spark.eventLog.compress</name> <value>true</value> </property> <property> <name>spark.eventLog.dir</name> <value>viewfs://jssz-bigdata-cluster/tmp/sparklog</value> </property> <property> <name>spark.serializer</name> <value>org.apache.spark.serializer.KryoSerializer</value> </property> <property> <name>spark.yarn.historyServer.address</name> <value>http://10.69.1.34:18080</value> </property> <property> <name>spark.driver.cores</name> <value>1</value> </property> <property> <name>spark.driver.memeory</name> <value>4g</value> </property> <property> <name>spark.driver.extraJavaOptions</name> <value>-Dspark.driver.log.level=INFO -XX:+UseG1GC</value> </property> <property> <name>spark.executor.memeory</name> <value>15g</value> </property> <property> <name>spark.executor.cores</name> <value>1</value> </property> <property> <name>spark.executor.extraJavaOptions</name> <value>-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseG1GC</value> </property> <property> <name>spark.shuffle.service.enabled</name> <value>true</value> </property> <property> <name>spark.dynamicAllocation.enabled</name> <value>true</value> </property> <property> <name>spark.dynamicAllocation.minExecutors</name> <value>1</value> </property> <property> <name>spark.dynamicAllocation.maxExecutors</name> <value>50</value> </property> <property> <name>spark.dynamicAllocation.schedulerBacklogTimeout</name> <value>10s</value> </property> <property> <name>hive.spark.client.rpc.max.size</name> <value>268435456</value> </property> <property> <name>spark.rpc.message.maxSize</name> <value>256</value> </property> <property> <name>spark.scheduler.mode</name> <value>FAIR</value> </property> <property> <name>spark.blacklist.enabled</name> <value>true</value> </property> <property> <name>spark.speculation</name> <value>true</value> </property> <property> <name>spark.task.maxFailures</name> <value>10</value> </property> <property> <name>spark.rdd.compress</name> <value>true</value> </property> <property> <name>spark.executor.heartbeatInterval</name> <value>20s</value> </property> <property> <name>spark.network.timeout</name> <value>120s</value> </property> <!-- 解决shuffle 的问题 --> <property> <name>spark.sql.tungsten.enabled</name> <value>true</value> </property> <!-- 解决UDF的问题 --> <property> <name>spark.jars</name> <value>/data/service/hive/lib/com.bilibili.hiveudf.jar</value> </property>
在 添加 ${SPARK_LIB}/spark-*.jar 到 hive的classpath下。
问题一 cluster模式下 作业连接超时。
看了一下提交的作业信息
</div> <div>SparkSubmit --properties-file /tmp/spark-submit.3467179554612125337.properties --class org.apache.hive.spark.client.RemoteDriver /data/src/hive/apache-hive-2.3.4-bin/lib/hive -exec-2.3.4.jar --remote-host jssz-bigdata-hive-04 --remote-port 16317 --conf hive.spark.client.connect.timeout=1000 --conf hive.spark.client.server.connect.timeout=90000 --conf hive.spark.client.channel. log.level=null --conf hive.spark.client.rpc.max.size=1195725856 --conf hive.spark.client.rpc.threads=8 --conf hive.spark.client.secret.bits=256 --conf hive.spark.client.rpc.server.address=null</div> <div>
因为cluster模式下,AM是运行在远程的,数据通信是通过 –remote-host 这个参数来进行回传 。后来发现是nodemanager节点不能解析域名,配置加上后解决
问题二 无法识别hive 的UDF
在配置中添加 spark.jars 配置,把UDF的包给加上去。
问题三 Unable to acquire ** bytes of memory异常
修改配置
设置spark.sql.tungsten.enabled = false。
设置spark.executor.cores=1。
问题四 hive server 内存不足
因为hive on spark 本质上也是通过 spark-submit命令来提交。所以提交一个作业时候会消耗一定的内存,那么就
export HADOOP_CLIENT_OPTS=”-Xmx1024m”
阅读全文…
yarn-label Scheduler
作者: inter12
日期: 12 二月, 2019
没有评论 | 1,469 views
需要对于yarn集群进行实时和离线作业的分离,就单独搞一个yarn,实时对于资源的竞争比较敏感,所以用了标签来做机器上的隔离来保证资源的隔离性
阅读全文…