需求场景:我们的产品需要对接客户的权限系统,即登录时使用客户的认证系统进行认证,集成认证的方式是调用客户提供的jar包并调用userService的authenticate方法。同时需要在classpath中提供key的key文件。从需求来看,这个集成并不复杂,而且客户也提供了比较详细的接口文档和示例案例,所以开发工作量很小。最大的障碍是客户有安全需求,内部的Jar包等文件无法复制,我们的开发环境无法连接到客户的内网。客户提供的Jar包没有Maven管理,所以我们只能直接导入。在我们的Scala项目中,我们可以直接将依赖的jar包放在模块的lib文件夹下。使用sbt进行编译打包任务时,会自动将lib下的jar包放入classpath中。那么,第一个需要解决的问题就是:既然不能将客户的jar包复制到我的开发环境中,那么如何处理依赖呢?既然在开发环境中获取不到jar包,那就打个mock包吧。幸运的是,需要编写的代码只涉及ServiceConfig、ServiceManager和UserService这三个类以及这些类的几个方法。其中,ServiceConfig提供认证所需的属性值,通过set方法进行设置。因为最后需要调用的其实是UserService的authenticate方法,你只需要为它提供一个简单的实现,定义其他相关的类型和方法就可以保证编译通过。第一个问题很容易解决。由于我们使用了sbtassembly并编写了相应的脚本来支持整个产品的打包,所以最终的打包结果是一个完整的mort.jar包。也就是说,我们所依赖的外部Jar包也会被打包到最终的jar文件中。于是,第二个问题接二连三的来了:既然程序代码和外部的jar包都被打包到了最终的部署包中,那么当我们将包拷贝到客户的部署环境中时,如何将之前的mock包替换为real呢?执行?事实上,sbtassembly并没有将所有依赖的外部包组装成最终的部署包。只要在sbt的依赖中加入provided,就可以保证部署包中不包含第三方依赖包。中间。因此,我们可以重写sbt脚本,在执行程序集时排除掉mock包,这是首要的解决方法。方法是在build.sbt中添加如下脚本:excludedJarsinassembly:={valcp=(fullClasspathinassembly).valuecpfilter{_.data.getName="customer_provided_mock.jar"}}部署包不再包含这个外部依赖包,但是在部署的时候,我们要把真正的jar包放到部署环境的类路径下。然而事与愿违,当我们将真正的jar包放到本地的classpath中时,运行时却找不到jar包。哪里有问题?原因是我们的程序不是普通的java程序,而是spark应用,部署环境是集群环境。运行程序就是通过sparksubmit将部署包提交给spark的集群管理器。这就需要分析一下sparksubmit的工作原理,如下图所示:在集群部署模式下,driver端通过spark-submit将spark应用提交到集群,然后分发到job到worker节点。我们系统的主程序入口是com.bigeyedata.mort.Main。程序的运行是通过spark-submit调用部署包的Main,即在spark驱动下运行,而不是通过java运行虚拟机在本地执行mort.jar。.这就是本地设置classpath不生效的根本原因。我注意到spark-submit提供了--jar参数。除了spark应用jar包以外的其他jar包都可以通过该参数指定自动传输到集群中。注意,如果--jar指定多个jar包,则用分隔符分隔,与--driver-class-path的分隔符不同,使用:。所以我修改了启动器的脚本,将其设置为:exec$SPARK_HOME/bin/spark-submit\--classcom.bigeyedata.mort.Main\--driver-class-path$MORT_HOME/libs/*.jar\--masteryarn-client\--deploy-modecluster\--jars/appcom/mort/thirdparty_jars/customer_provided.jar\--queuequeue_0100_01\$MORT_HOME/mort.jar>$MORT_HOME/mort.log2>&1还有一个问题需要解决:How放置用户认证所需的密钥文件?这个文件还是不能作为内嵌资源文件打包到部署包中。因为这个文件的内容需要区分测试环境和生产环境。部署到生产环境时,需要换成另一个密钥文件。客户的文档声明此文件(不是jar文件)需要放在运行的类路径中。解决方法同上,但还是不能直接将key文件放到本地classpath中,而是使用spark-submit的--files参数。所以需要在之前的脚本中spark-submit添加如下内容:--files/appcom/mort/thirdparty_jars/clientKey.pk\三个问题给我造成了一些困扰,尤其是第二个问题的解决方法,让回顾sparksubmit的工作原理,了解相关参数的作用。虽然花费了一些时间,但问题的解决是值得的。【本文为专栏作家“张艺”原创稿件,转载请联系原作者】点此阅读更多该作者好文
