1.手机证书过期安装不了软件是什么原因?

2.大厂都是如何解决Ja日志级别,重复记录、丢日志问题?

重复签名的解决方式_重签名是什么意思

首先简单理解一下数字签名:

1)A使用数字签名签署了一份合同并将该合同发送给B;

2)那么,A的数字签名即包括合同原文(以哈希值形式)+签字或印章外观+A的私钥(为便于理解,具体签署场景与技术实现上略有差异)。

在第三方电子合同平台,不同的签署人使用自己的数字签名签约时对应的合同原文都不同(可能添加了他人的数字签名),因此,每一次签约动作对应的数字签名也就不同。

故,数字签名不能重复使用。

手机证书过期安装不了软件是什么原因?

写在前面:加密和签名是两回事,加密的目的是防止信息泄露,签名的目的是防止篡改和伪造

MD5、SHA-1、SHA-256、HMAC-SHA256等属于哈希算法,计算数字摘要,不可逆,有碰撞

DES、AES、RSA等属于加密算法,对数据进行加解密,可逆

MD5签名通常先按照一定规则排列待签名数据,进行加盐(拼key),然后使用MD5摘要算法计算摘要,得到的散列值即为sign

MD5验签即按照相同的规则排列待签名数据,使用相同的key,然后使用MD5摘要算法计算摘要,对比自己得到的sign值和对方传过来的sign值是否相等

参考资料:

MD5算法原理

MD5作为一种散列算法,虽然很难发生散列碰撞,但是仍然存在两种不同数据会发生碰撞

已知明文A,可以计算得到另一个明文B和A的MD5值相同,但是并不能保证B是一段有意义的文字

未知明文A,已知MD5值X,无法计算得到明文A

暴力枚举、字典法、彩虹表法(对字典表的优化)

参考资料:

MD5破解方法

网上的这篇文章说的比较清楚: SHA1算法原理

SHA-1一般被应用于数字证书的签名哈希算法,或者RSA签名中的哈希算法

经过权威机构证实,sha1算法的不安全性越来越高,sha指纹成本越来越低,随即微软、谷歌等IT巨头相继发布弃用sha1哈希算法声明,第三方认证机构自2016年1月1日起,将全面停止签发SHA1算法的数字证书。

网上的这篇文章说的比较清楚: SHA256算法原理

SHA-1算法和SHA-256算法并不是近亲,SHA-256算法属于SHA-2算法。SHA-1是160位的哈希值,而SHA-2是组合值,有不同的位数,SHA-256就是256位的SHA-2。SHA-1算法和MD5算法都是由MD4算法导出,所以这俩是近亲。

顾名思义,慢哈希就是很慢,主要为了防止暴力破解。由于慢,通常都用在客户端或者对性能没什么要求的场景

业内通用的一般是MD5(MD5(password)+salt)或SHA256(SHA256(password)+salt)

客户端进行SHA256(password),并传输给服务端,服务端进行SHA256(SHA256(password)+salt)

ps:小数据如果既要加密又要签名,可以直接使用RSA私钥加密整个数据,接收方公钥解密,不做签名

比如赠送代金券的接口,拿到一个真实请求以后重复调用。

解决方案:

大厂都是如何解决Ja日志级别,重复记录、丢日志问题?

《新手教程》关于“手机证书过期”导致无法安装软件的解决办法!安装软件经常出现些“证书 X X ”的问题导致无法安装软件,现总结一下可能出现的问题!首选需要说明的是证书有有效期问题,不管证书是不是在有效期内,都是可以安装的,需要做的只是在安装时调整一下手机的时间。然后需要说明的,确保手机中 “设置-手机设置-应用程序-程序管理”中,“软件安装”为“全部”,“在线证书检查”为“关”。1.证书错误证书错误的提示最常见,问题原因(1)需要自签名 的程序没有签名就安装,(2)别人用私有证书(就是提供串号申请的证书)签名过的软件,(3)重复签名的软件(就是本来已经签名过一次,又再次签名)。解决办法:(1)签名后安装,(2)去下载没有签名过的软件来自己签名,(3)用没有重复签名的软件安装。没有证书的找人做去。2.证书限制这个问题不是很常见,但出现还是比较烦人的。原因就是制作证书和签名都需要key,有的签名软件在遇到key不符时会提示,但有的仍然继续签名,这样签名的软件在安装时就会提示证书限制。还有一个原因是证书文件在传播过程中损坏。解决办法:先尝试更换key文件,最好叫帮你做证书的那个人把他的key文件发给你,如果仍不能解决,重新制作 证书 即可。3.证书过期、证书未生效每个证书都有一个有效期,只有在证书有效期内的才能安装,在电脑上双击打开证书可以查看有效期。但是签名好的软件不能看有效期的,那就只能在安装时尝试了。解决办法:就是修改手机时间。一般先调会正常的日期,然后以3个月为一档的调整,调一次安装一次,看错误报告。证书过期是目前手机的时间在证书的有效期之后,朝前调即可,证书未生效则反过来,手机时间在证书有效期前,这个要朝后调(这个其实很多时候调到正确的日期就不会出现这个错误提示)。FREE:出现问题的解决思路1.先看你安装的软件是否需要签名,不要需不需要签名的软件都拿了签名。签名前先看文件名后缀 .sisx 的不需要签名, .sis 的才需要签名,但不是全部 .sis 的文件都要签名。 一般需要签名的在下载时都会说明。2.看看该证书以前有没有成功签名安装过软件。证书曾经成功签名安装过的说明证书是有效的,可以跳过4。3.更换软件来尝试签名,不要在一个软件上抱死。其他软件可以签名安装的就可以说明是原安装程序的问题,重新下载即可。4.根据错误提示选择是更换key文件或重新做证书。5.基本这几步就能解决80%以上的问题了,如果还不能安装,再求助。

1SLF4J日志行业的现状

框架繁不同类库可能使用不同日志框架,兼容难,无法接入统一日志,让运维很头疼!

配置复杂由于配置文件一般是xml文件,内容繁杂!很多人喜欢从其他项目或网上闭眼copy!

随意度高因为不会直接导致代码bug,测试人员也难发现问题,开发就没仔细考虑日志内容获取的性能开销,随意选用日志级别!

Logback、Log4j、Log4j2、commons-logging及ja.util.logging等,都是Ja体系的日志框架。不同的类库,还可能选择使用不同的日志框架,导致日志统一管理困难。

SLF4J(SimpleLoggingFacadeForJa)就为解决该问题而生

提供统一的日志门面API图中紫色部分,实现中立的日志记录API

桥接功能蓝色部分,把各种日志框架API桥接到SLF4JAPI。这样即使你的程序使用了各种日志API记录日志,最终都可桥接到SLF4J门面API

适配功能红色部分,绑定SLF4JAPI和实际的日志框架(灰色部分)

SLF4J只是日志标准,还是需要实际日志框架。日志框架本身未实现SLF4JAPI,所以需要有个前置转换。Logback本身就按SLF4JAPI标准实现,所以无需绑定模块做转换。

虽然可用log4j-over-slf4j实现Log4j桥接到SLF4J,也可使用slf4j-log4j12实现SLF4J适配到Log4j,也把它们画到了一列,但是它不能同时使用它们,否则就会产生死循环。jcl和jul同理。

虽然图中有4个灰色的日志实现框架,但业务开发使用最多的还是Logback和Log4j,都是同一人开发的。Logback可认为是Log4j改进版,更推荐使用,已是社会主流。

SpringBoot的日志框架也是Logback。那为什么我们没有手动引入Logback包,就可直接使用Logback?

spring-boot-starter模块依赖spring-boot-starter-logging模块,而spring-boot-starter-logging自动引入logback-classic(包含SLF4J和Logback日志框架)和SLF4J的一些适配器。

2异步日志就肯定能提高性能?

如何避免日志记录成为系统性能瓶颈呢?这关系到磁盘(比如机械磁盘)IO性能较差、日志量又很大的情况下,如何记录日志。

2.1案例

定义如下的日志配置,一共有两个Appender:

FILE是一个FileAppender,用于记录所有的日志

CONSOLE是一个ConsoleAppender,用于记录带有time标记的日志

把大量日志输出到文件中,日志文件会非常大,若性能测试结果也混在其中,就很难找到那条日志了。所以,这里使用EvaluatorFilter对日志按照标记进行过滤,并将过滤出的日志单独输出到控制台。该案例中给输出测试结果的那条日志上做了time标记。

配合使用标记和EvaluatorFilter,可实现日志的按标签过滤。

测试代码:实现记录指定次数的大日志,每条日志包含1MB字节的模拟数据,最后记录一条以time为标记的方法执行耗时日志:

执行程序后发现,记录1000次日志和10000次日志的调用耗时,分别是5.1s和39s

对只记录文件日志的代码,这耗时过长了。

2.2源码解析

FileAppender继承自OutputStreamAppender

在追加日志时,是直接把日志写入OutputStream中,属同步记录日志

所以日志大量写入才会旷日持久。如何才能实现大量日志写入时,不会过多影响业务逻辑执行耗时而影响吞吐量呢?

2.3AsyncAppender

使用Logback的AsyncAppender,即可实现异步日志记录。

AsyncAppender类似装饰模式,在不改变类原有基本功能情况下,为其增添新功能。这便可把AsyncAppender附加在其他Appender,将其变为异步。

定义一个异步AppenderASYNCFILE,包装之前的同步文件日志记录的FileAppender,即可实现异步记录日志到文件

记录1000次日志和10000次日志的调用耗时,分别是537ms和1019ms

异步日志真的如此高性能?并不,因为它并没有记录下所有日志。

3AsyncAppender异步日志的天坑

记录异步日志撑爆内存

记录异步日志出现日志丢失

记录异步日志出现阻塞。

3.1案例

模拟个慢日志记录场景:首先,自定义一个继承自ConsoleAppender的MySlowAppender,作为记录到控制台的输出器,写入日志时睡1s。

配置文件中使用AsyncAppender,将MySlowAppender包装为异步日志记录

测试代码

耗时很短但出现日志丢失:要记录1000条日志,最终控制台只能搜索到215条日志,而且日志行号变问号。

原因分析AsyncAppender提供了一些配置参数,而当前没用对。

源码解析

includeCallerData默认false:方法行号、方法名等信息不显示

queueSize控制阻塞队列大小,使用的ArrayBlockingQueue阻塞队列,默认容量256:内存中最多保存256条日志

discardingThreshold丢弃日志的阈值,为防止队列满后发生阻塞。默认队列剩余容量<队列长度的20%,就会丢弃TRACE、DEBUG和INFO级日志

neverBlock控制队列满时,加入的数据是否直接丢弃,不会阻塞等待,默认是false

//阻塞队列:实现异步日志的核心BlockingQueueblockingQueue;//默认队列大小publicstaticfinalintDEFAULT_QUEUE_SIZE=256;intqueueSize=DEFAULT_QUEUE_SIZE;staticfinalintUNDEFINED=-1;intdiscardingThreshold=UNDEFINED;//当队列满时:加入数据时是否直接丢弃,不会阻塞等待booleanneverBlock=false;

@Overridepublicvoidstart(){...blockingQueue=newArrayBlockingQueue(queueSize);if(discardingThreshold==UNDEFINED)//默认丢弃阈值是队列剩余量低于队列长度的20%,参见isQueueBelowDiscardingThreshold方法discardingThreshold=queueSize/5;...}

@Overrideprotectedvoidend(EeventObject){if(isQueueBelowDiscardingThreshold()&&isDiscardable(eventObject)){//判断是否可以丢数据return;}preprocess(eventObject);put(eventObject);}

privatebooleanisQueueBelowDiscardingThreshold(){return(blockingQueue.remainingCapacity()<discardingThreshold);}

privatevoidput(EeventObject){if(neverBlock){//根据neverBlock决定使用不阻塞的offer还是阻塞的put方法blockingQueue.offer(eventObject);}else{putUninterruptibly(eventObject);}}//以阻塞方式添加数据到队列privatevoidputUninterruptibly(EeventObject){booleaninterrupted=false;try{while(true){try{blockingQueue.put(eventObject);break;}catch(InterruptedExceptione){interrupted=true;}}}finally{if(interrupted){Thread.currentThread().interrupt();}}}}

队列满时:offer不阻塞,而put会阻塞

neverBlock为true时,使用offer

publicclassAsyncAppenderextendsAsyncAppenderBase<ILoggingEvent>{//是否收集调用方数据booleanincludeCallerData=false;protectedbooleanisDiscardable(ILoggingEventevent){Levellevel=event.getLevel();//丢弃≤INFO级日志returnlevel.toInt()<=Level.INFO_INT;}protectedvoidpreprocess(ILoggingEventeventObject){eventObject.prepareForDeferredProcessing();if(includeCallerData)eventObject.getCallerData();}}publicclassAsyncAppenderBase<E>extendsUnsynchronizedAppenderBase<E>implementsAppenderAttachable<E>{

默认队列大小256,达到80%后开始丢弃<=INFO级日志后,即可理解日志中为什么只有两百多条INFO日志了。

queueSize过大

可能导致OOM

queueSize较小

默认值256就已经算很小了,且discardingThreshold设置为大于0(或为默认值),队列剩余容量少于discardingThreshold的配置就会丢弃<=INFO日志。这里的坑点有两个:

因为discardingThreshold,所以设置queueSize时容易踩坑。比如本案例最大日志并发1000,即便置queueSize为1000,同样会导致日志丢失

discardingThreshold参数容易有歧义,它不是百分比,而是日志条数。对于总容量10000队列,若希望队列剩余容量少于1000时丢弃,需配置为1000

neverBlock默认false

意味总可能会出现阻塞。

若discardingThreshold=0,那么队列满时再有日志写入就会阻塞

若discardingThreshold!=0,也只丢弃≤INFO级日志,出现大量错误日志时,还是会阻塞

queueSize、discardingThreshold和neverBlock三参密不可分,务必按业务需求设置:

若优先绝对性能,设置neverBlock=true,永不阻塞

若优先绝不丢数据,设置discardingThreshold=0,即使≤INFO级日志也不会丢。但最好把queueSize设置大一点,毕竟默认的queueSize显然太小,太容易阻塞。

若兼顾,可丢弃不重要日志,把queueSize设置大点,再设置合理的discardingThreshold

以上日志配置最常见两个误区

再看日志记录本身的误区。

4如何选择日志级别?

使用{}占位符,就不用判断loglevel了吗?

据不知名网友说道:SLF4J的{}占位符语法,到真正记录日志时才会获取实际参数,因此解决了日志数据获取的性能问题。是真的吗?

验证代码:返回结果耗时1s

若记录DEBUG日志,并设置只记录>=INFO级日志,程序是否也会耗时1s?三种方法测试:

拼接字符串方式记录slowString

使用占位符方式记录slowString

先判断日志级别是否启用DEBUG。

前俩方式都调用slowString,所以都耗时1s。且方式二就是使用占位符记录slowString,这种方式虽允许传Object,不显式拼接String,但也只是延迟(若日志不记录那就是省去)日志参数对象.toString()和字符串拼接的耗时。

本案例除非事先判断日志级别,否则必调用slowString。所以使用{}占位符不能通过延迟参数值获取,来解决日志数据获取的性能问题。

除事先判断日志级别,还可通过lambda表达式延迟参数内容获取。但SLF4J的API还不支持lambda,因此需使用Log4j2日志API,把Lombok的@Slf4j注解替换为@Log4j2注解,即可提供lambda表达式参数的方法:

这样调用debug,签名Supplier<?>,参数就会延迟到真正需要记录日志时再获取:

所以debug4并不会调用slowString方法

只是换成Log4j2API,真正的日志记录还是走的Logback,这就是SLF4J适配的好处。

总结

SLF4J统一了Ja日志框架。在使用SLF4J时,要理清楚其桥接API和绑定。若程序启动时出现SLF4J错误提示,可能是配置问题,可使用Men的dependency:tree命令梳理依赖关系。

异步日志解决性能问题,是用空间换时间。但空间毕竟有限,当空间满,要考虑阻塞等待or丢弃日志。若更希望不丢弃重要日志,那么选择阻塞等待;如果更希望程序不要因为日志记录而阻塞,那么就需要丢弃日志。

日志框架提供的参数化记录方式不能完全取代日志级别的判断。若日志量很大,获取日志参数代价也很大,就要判断日志级别,避免不记录日志也要耗时获取日志参数!