三门问题

三门问题(Monty Hall problem)亦称为蒙提霍尔问题、蒙特霍问题或蒙提霍尔悖论,大致出自美国的电视游戏节目Let’s Make a Deal。问题名字来自该节目的主持人蒙提·霍尔(Monty Hall)。参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车,选中后面有车的那扇门可赢得该汽车,另外两扇门后面则各藏有一只山羊。当参赛者选定了一扇门,但未去开启它的时候,节目主持人开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。作为参赛者究竟要不要换?

Read More ...

Java自签名证书问题

使用Sonatype Nexus自建了一个Maven仓库,出于安全考虑使用了 HTTPS 协议,不过 SSL 证书用的是自签名的证书,在使用Maven时遇到了如下错误:

sun.security.validator.ValidatorException: PKIX path building failed:
    sun.security.provider.certpath.SunCertPathBuilderException:
    unable to find valid certification path to requested target

这是因为自签名的证书不在Java的可信证书范围内,因此需要手动将对应证书加入Java的可信证书列表中,具体步骤如下:

1. 使用keytool导入证书

# cert_name.crt 为待导入的证书文件
# store_file 为导入的证书文件的存储文件名
# cert_name 为导入的证书存储别名
# 导入证书时需要输入密码,需要将该密码记住,后面将会用到
keytool -import -file cert_name.crt -keystore $JAVA_HOME/jre/lib/security/store_file -alias cert_name

2. 在Java程序的启动参数添加可信证书参数

# 123456即为上一步输入的密码
-Djavax.net.ssl.trustStorePassword=123456 -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/store_file

完成上述两步之后自签名的证书也就可以被Java程序所信任,不在出错。

对于Maven,只需要在 MAVEN_OPTS 环境变量中添加上述参数即可:

# 配置在 ~/.bash_profile 或 ~/.bashrc 中即可
export MAVEN_OPTS="$MAVEN_OPTS -Djavax.net.ssl.trustStorePassword=123456 -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/store_file"

Java技能树

Java核心技术总结

Java核心技术总结

Read More ...

服务自动注册与发现

在企业级系统中,针对业务进行模块化拆分是不可避免的,而系统模块化拆分之后,必然存在A模块(服务使用方)依赖B模块(服务提供方)的场景,通常拆分之后的模块都是相对独立的,所以这样的场景下一般由服务提供方提供远程调用接口给服务使用方使用。而服务提供方为了保证在高并发的情况下仍然能为服务使用方提供稳定的服务,通常会对服务提供方部署多个实例,并对来自服务使用方的请求就行负载均衡,使这些请求尽量均匀的分布在所部署的各个服务提供方实例上。

而要实现负载均衡,通常可以使用LVS、HAProxy、协议代理等技术解决。不过LVS的代价相对较大,而剩余的技术基本都是以加入代理的方式来实现负载均衡。如服务提供方与服务使用方之间的通信协议是基于HTTP的,那么简单有效的方法是在服务提供方、使用方之间加一层HTTP反向代理(nginx、apache),利用反向代理完实现负载均衡。但是使用代理的方式会增加一次额外的请求转发,无论代理的性能做得多好,这次额外的请求转发总还是需要消耗时间的。而且代理的引入也会导致服务提供、使用方之间的调用风险增加。比如之前在我司的业务系统中就遇到过一次nginx代理重复转发了一个请求,而服务提供方又没法判断重复请求,最后因为这个重复的请求导致系统出现问题。再者由于代理的存在,每次增加新的服务提供方部署实例时,可能都需要修改代理的配置,这样就不利于自动化新增服务提供方实例来对整个系统进行扩容了。

Read More ...

Maven本地第三方库依赖

在使用Maven作为项目构建工具的过程中,有时还是会不可避免的遇到依赖的第三方库在Maven中央库中没有,只能使用本地依赖,虽然这样的情况极少发生,但当真的遇到时,应该如何优雅的解决呢?

如果是简单粗暴的引入一个本地依赖的话,一般像下面这样配置就好了:

<project>
    ...
    <dependencies>
        ...
        <dependency>
            <groupId>org.jhat</groupId>
            <artifactId>third-party</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/libs/third-party.jar</systemPath>
        </dependency>
        ...
    </dependencies>
    ...
</project>

这种方式使用起来最简单,但是并不建议这么做,因为Maven在打包的过程中会忽略system类型依赖,也就是说system类型的依赖信息不会写入MANIFEST.MF文件中,自然也不会将其拷贝到jar/war包的libs目录下,打成一个单独的jar包时也不会包含system类型依赖的任何内容。如果要解决上述问题,不同的Maven插件都需要单独配置对system类型依赖的处理,也就是说在不同的使用场景下,都需要用对应的Maven插件针对system类型依赖进行处理。

Read More ...