这里是需要打印的内容
.....
在使用条码打印软件设计及打印标签时,有时我们把打印任务提交给打印机,打印机半天才打印出来,打印速度比较慢,那么在条码打印软件中该如何更改打印速度呢?具体操作如下:
1.在条码打印软件中,点击软件上方工具栏中的“文档设置”按钮,弹出文档设置对话框,在文档设置-纸张-打印机纸张/打印机下拉列表中,选择所需的打印机,之后点击属性。
弹出所选打印机的打印首选项,在打印首选项里面点击“选项”框,默认的是使用当前打印机设置(U),取消使用当前打印机设置(U)前面的复选框,就可以手动设置打印机的打印速度及深度。
除了在条码打印软件设置打印速度之外,还可以通过点击电脑上的开始-设备和打印机,在设备和打印机界面找到所需的打印机,在打印机上右击-打印首选项,弹出打印机首选项界面。
然后在打印机首选项界面点击“选项”框,在选项框里面继续设置,方法如上:
以上两种方法都可以调整打印机的打印速度,打印速度越慢,打印质量越好。条码打印软件只有你想不到,没有做不到的。想要了解更多关于条码打印软件的操作技巧,可以到条码打印软件官网查询相应的教程。
作者简介
英明,携程数据研发专家,负责支付离线数据仓库建设及BI业务需求,对并行计算、大数据处理及建模等有浓厚兴趣。
一、背景
支付中心作为携程集团公共部门,主要负责的业务包括交易、实名绑卡、账户、收单等,由于涉及到交易相关的资金流转以及用户实名认证,部分用户操作环节的中间数据应内控/审计要求需要长时间保存。当前研发应用多,日志量大、格式各异,对于日志的存储和使用产生较大的挑战,故支付数据与研发团队群策群力,共同开发了一套统一日志框架。
二、总体架构图
核心模块包括:日志生产、日志采集、日志解析,其中调用流程如下:
1)研发应用/服务接入基于log4j2扩展的统一日志组件,将日志抛送至kafka。
2)周期性启动消费kafka topic的camus job将日志写入hdfs。
3)T+1启动MR job读取camus写入的hdfs内容并load到hive表。
三、日志生产-统一日志组件
支付研发基于log4j2自定义了多个Appender,将应用日志以服务调用形式抛送至kafka,并被log_process_service 服务统一处理并提交至携程常用基础日志框架如:CLOG、CAT、ES,各应用无需关心公司日志框架,统一由日志平台处理。
其优点:
不同日志框架对应着不同的Appender,方便进行日志框架接入的扩展。
采用AOP编程,对于接入的业务侵入性小,接入简单。
定义了丰富的java注解,便于日志配置化输出,其中可打印日志包括但不限于:类名、方法名、方法入参、返回值、异常等,支持敏感字段脱敏。
存在的问题:
日志格式不规范:研发应用数百个,研发人员较多,日志格式差异大,给数据分析和使用带来巨大挑战。
存储时长短:当前公司在线CLOG存储系统只能查询最近几天数据、ES保存稍长一段时间数据且不支持批量查询,基础离线CLOG hive表由于数据量巨大,仅能做到T+2,无法满足T+1的报表需求。
故支付数据团队在研发团队统一日志组件的基础上,结合数据分析和数据存储生命周期开发了统一日志框架。
3.1 统一日志-埋点设计
支付研发团队负责数百个服务或应用,支持的业务包括:路由、鉴权、免密、卡服务、订单、钱包实名、电子支付等,不同的业务又可拆分app、h5、online、offline等项目,整合这些数据是个极大的挑战。如果各系统研发埋点任意指定,会给BI数据分析带来极大的困难,数据分析准确性难以得到保障,故支付数据基于业务特点定义了一套统一日志埋点规范。
字段定义主要是基于日常分析需求,致力于简化数据的使用,故总体原则为json形式,当前原始日志有两部分组成:tag/message,其中tag数据结构为Map,关键数据一般是通过tag内的数据进行检索,明细数据通过message进行检索,tag与message的组成格式为:[[$tag]]$message,目前标准字段包括两类:规范性字段和通用性字段。
3.1.1 规范性字段格式
规范性字段需要应用研发一定程度的参与,提供符合字段命名的类和方法。部分字段名称及定义如下:
字段名称 字段类型 描述 serviceName string 调用服务名称 tag Map keyvalue信息 message string 原始日志 request string 接口请求参数 response string 接口返回值 requesttime string 日志请求时间 responsetime string 日志请求时间 其中tag可以灵活填充,主要扩展字段如下:
名称 字段类型 描述 version string app版本号 plat string 平台信息 refno string 流水号 3.1.2 通用字段格式
日志框架能够自动获取属性,无需研发编码,即可打印。
字段名称 字段类型 描述 applicationid string 携程应用唯一识别号 logtime string 日志生成时间 3.2 分区/分桶字段的定义
当前离线数据分析基于hive引擎,hive的分区分桶设计极大的影响了查询性能,特别是在日志量巨大的场景下,分区字段的选择尤为关键。如:用户进入支付收银台可能会有上百个场景,而每种场景下会有多次服务调用,其中不同场景下服务调用频率差异很大,占用的空间差异也较大,故针对每种场景分配一个唯一的场景号,通过场景号进行分区,可以高效的进行数据分析,而过多的分区也可能导致较多的小文件,对hadoop namenode产生较大的影响,此时结合分桶能够达到优化查询效率且避免分区无限制野蛮增长产生众多过多小文件的问题。四、日志采集
日志采集框架基于LinkedIn的开源项目Camus,Camus使用MapReduce读取kafka数据然后写入hdfs,由于无reduce阶端,所有数据处理及写入都在Map侧,很少会发生数据倾斜,Camus具有接入简单,方便扩展,故我们进行了二次开发,以满足当前业务的需要:
自定义decoder/partitioner,原生的decoder/partitioner支持的hdfs落地路径主要基于日期,较为粗糙,无法适应业务的需要。故自定义decoder 抽取原始日志分区字段,然后代入partitioner中,生成具有业务含义的hdfs输出路径,为特定时间范围数据回刷提供了高效的解决方案。
自定义provider,原生的StringRecordWriterProver仅支持text文件方式落地,占用空间大、压缩后无法并行切分,容易错列错行,而orc格式数据,有效的节约了hdfs占用空间,查询效率高且可以切分,有利于日志解析job的高效执行。其中在配置Camus job过程中需要关注如下问题:
4.1 camus 任务执行
执行频率设置
The earliest offset was found to be more than the current offset
由于kafka消息保存天数有限和单个分区size有限(Server 配置:log.retention.bytes),携程侧为3天和10G,如果camus同步kafka频率较低时,可能会出现数据丢失,故需要根据日志量大小,设置camus 调度任务的执行频率,防止数据丢失。
任务重叠执行
Error: java.io.IOException: target exists.the file size(614490 vs 616553) is not the same.
camus从kafka 读取数据,任务要以单例形式执行,任务执行完成后才会更新kafka的offset,若一个任务执行了多次,就会导致数据大小无法对齐,此时需要删除配置路径下的所有数据后重新启动任务,即可完成修复。
4.2 如何控制camus落地文件的大小当kafka各partition数据写入量不平衡时,由于各partition会写入一个hdfs文件中,如果研发日志集中写入kafka某个partition,会导致这个partition对应的hdfs文件占用空间特别大,如果恰巧这个文件是不可切分的,极端情况下会导致只有一个线程去解析这个大文件,降低了数据读写的并发度,拉长了数据解析时间,遇到这种问题的解决办法是:
临时解决方案:研发日志分散写入kafka partition,不要导致某类数据集中写入一个partition;
高效解决方案:数据侧采用可切分的输入格式,进行数据切分;
4.3 写入orc文件格式注意事项
orc写入timeout
AttemptID:attempt_1587545556983_2611216_m_000001_0 Timed out after 600 secs
orc文件写入速度较text文件会慢很多,如果同时写入的的文件较多或者内存回收占用时间较长,会导致map方法在600秒内没有读、写或状态更新,job会被尝试终结,解决方法是调高默认的task超时时间,由10分钟调高到20分钟。
mapreduce.task.timeout=1200000
OOM 内存溢出
beyond physical memory limits. Current usage: 2.5 GB of 2.5 GB physical memory used; 4.2 GB of 5.3 GB virtual memory used. Killing container.
在orc写文件的时候如果出行较多的OOM,此时需要加大map执行的内存。
mapreduce.map.memory.mb=8096
mapreduce.map.java.opts=-Xmx6000m
五、统一日志-解析
鉴于日志解析工作主要集中在MapReduce的Map侧,而Map侧通过参数调整能够很容易控制map的个数,以提高数据解析的并发度,MapReduce主要分为:intputformat、map、shuffle、reduce等几个核心阶段,通过优化各阶段的执行时间,可以显著提高日志解析的速度。
5.1 inputsplit优化
MR job中影响map的个数主要有:前期日志解析程序的性能较高,一天的全量日志解析约25分钟,中间有段时间任务执行时间从25分钟延迟到4个小时,原因是研发将大量订单号为空的日志写入到指定的partition中,日志量巨大,导致其中少量map在读取大文件时执行时间特别长。经过分析发现text+snappy 文件无法切分,只能够被一个map处理,将camus落地数据格式从text+snappy换为orc+snappy格式,同时开发了支持orc文件格式的CombineFileInputFormat,既减少了小文件对hadoop计算资源果断的占用也提高了job的并发程度。
- 文件个数:如果不采用CombineFileInputFormat,那么不会进行小文件合并,每个文件至少有一个map处理,当小文件太多时,频繁启动和回收线程也会对性能产生影响,同时对集群其它job资源分配产生影响。
- 文件属性:当文件较大且可切分时,系统会生成多个map处理大文件,inputsplit块按照MR最小单元进行文件切割(split),并且一个split对应一个MapTask。
5.2 shuffle优化
使map的输出能够更加均匀的映射到reduce侧,由于默认的分区策略是对map的输出key hash取reduce个数的模,容易导致数据倾斜,解决办法是在key上面增加时间戳或者重写partition函数。5.3 批量日志解析
当前MR的输出会作为hive外表的数据源,hive表会按照业务过程进行分区,所有数据的解析结果路径为:日期+业务过程,而业务过程可能有数百个,采用了MultipleInputs/MultipleOutputs 能够在一个mapreduce job中实现多输入多输出的功能,以适应业务自定义解析,并归一化后统一抛送到reduce侧。5.3.1 空文件生产
在使用的过程中会出现生成众多临时小文件及生成size 为0的小文件,增加了hdfs namenode内存压力,同时空文件也会导致spark表查询失败,可通过LazyOutputFormat进行修复。5.3.2 文件重复创建
MultipleOutputs输出文件一般以name-r-nnnnn的格式进行命名,其中name与程序指定的文件名有关,nnnnn表示reduce任务号。在处理数据较多时,可能会存在reduce侧反复创建已存在的文件,导致任务长时间运行而不能成功,中间生成了大量小文件,对hadoop namenode产生较大压力,影响整个集群响应时间。解决方案为:在reduce侧进行数据写入时,需要对exception进行捕捉,一旦出现数据写入exception,即将对应的写入reduce文件删除并终止程序,由于MR支持高可用,当一个reduce taks 失败后会自动重试,重试一定次数依然不能够成功就会导致整个任务失败,每次重试避免了不停的重复创建已存在的文件,引起NN响应时间极速下降。
5.4 reduce个数调整
目前日志解析的reduce侧主要用于orc数据写入,当reduce个数较少时,会导致reduce内存溢出,而reduce个数较多时,可能会导致非常多的小文件且占用集群过多资源,可以通过计算map侧输入文件的个数及总占用空间,动态计算需要的reduce个数,以达到合理利用资源的目的。六、日志治理
日志落地导致的一个问题是存储空间增长迅速,当前支付中心日均新增ORC压缩原始数据量TB级别且还在持续增长中。支付数据侧根据研发、产品的需求对不同类型日志进行分级,对于不同类别的日志设置不同的存储周期,主要划分为:研发排障日志、审计日志、数据分析日志等;同时在camus将日志写入hdfs时,由于按照业务分区进行落地,导致生成了大量小文件,需要对这些小文件进行合并并且设置TTL,避免对hadoop namenode产生较大的影响。七、总结与展望
目前日均TB级数据解析时间在30分钟内完成,后期计划将日志系统导入clickhouse等对实时要求高的场景共运营使用,以支持业务精细化运营和分析。Java与大数据架构
7年老码农,10W+关注者。【Java与大数据架构】全面分享Java编程、Spark、Flink、Kafka、Elasticsearch、数据湖等干货。欢迎扫码关注!
我们在网页开发过程中经常会有打印页面的需求,通过JS来实现的方法有很多。下面本篇文章就来给大家介绍几种使用JavaScript打印页面的方法,希望对大家有所帮助。
方式一:window.print()
print() 方法用于打印当前窗口的内容。
调用print()方法所引发的行为就像用户单击浏览器的打印按钮。通常,这会产生一个对话框,让用户可以取消或定制打印请求。
使用window.print()方法打印的页面分几种情况:
1、整体打印打印
现在就轻松实现了页面的打印,但是这种方式会将整个页面打印,如果想要实现指定区域的打印需要通过下面的设置
2、局部打印
首先,在html中,通过star和end来标记打印区域
这块内容不需要打印
这里是需要打印的内容
.....
这块内容不需要打印
然后,在点击事件中添加如下代码function doPrint() {
bdhtml=window.document.body.innerHTML;
sprnstr="";
eprnstr="";
prnhtml=bdhtml.substr(bdhtml.indexOf(sprnstr)+17);
prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr));
window.document.body.innerHTML=prnhtml;
window.print();
}
过滤打印区域的内容
例如
预览
打印
这里是需要打印的内容
.....
上面的预览和打印按钮不希望打印,如果要过滤的话可以做下面的样式设置
@media print {
.noprint{
display: none;
}
}
或:
.noprint{
display: none;
}
分页打印
使用 window.print() 打印时,如果内容超出会自动分页。但是我们如果需要自定义分页范围,如碰到表格分页打印,可以通过进行如下设置:
方式二、jqprint()
jqprint是一个基于jQuery编写的页面打印的一个小插件,但是不得不承认这个插件确实很厉害。
在Web打印的方面,前端的打印基本是靠window.print()的方式进行打印的,而这个插件在其基础上进行了进一步的封装,可以轻松实现打印网页上的某个区域,这是个亮点。
引入
js
function a(){
$("#ddd").jqprint();
}
html
test test test test test 设置模板打印$("#printContainer").jqprint({
debug: false,
//如果是true则可以显示iframe查看效果(iframe默认高和宽都很小,可以再源码中调大),默认是false
importCSS: true,
//true表示引进原来的页面的css,默认是true。如果是true,先会找$("link[media=print],"若没有会去找$("link")中的css文件)
printContainer: true,
//表示如果原来选择的对象必须被纳入打印(注意:设置为false可能会打破你的CSS规则)。
operaSupport: true
//表示如果插件也必须支持歌opera浏览器,在这种情况下,它提供了建立一个临时的打印选项卡。默认是true
});
另外还可以使用html 标签引入Webbrowser控件(只兼容IE)或者调用windows底层打印,报安全警告,不建议使用(不支持
.stop
.prevent
出现情况代码如下:<div @click="handle(item)" class="div1"> <div @click="handle(el)" class="div2"></div> </div>
handle(el) { console.log(el) // div1点击打印div1值,div2点击分别打印div1,div2的值 }
想要只打印当前点击的值,就需要阻止事件冒泡,在vue中,我们这样绑定事件可以实现
<div @click.stop="handle(item)" class="div1"> <div @click.stop="handle(el)" class="div2"></div> </div> // 下面这段可以取消默认事件 <div @click.prevent="handle(item)" class="div1"> <div @click..prevent="handle(el)" class="div2"></div> </div>