es插件平台

6 篇文章 0 订阅
3 篇文章 0 订阅

前言

  ES插件应用到ES很多地方,如:报警、分词、安全。。。。 但这些插件都是在技术层面的,业务层面肯定是缺失的,需要我们来补充
1、跟据某个业务字段或是业务规则来打分,打分高的排前面
2、跟据数据库字段来生成索引的mapping
3、异构数据的同步索引,跟据规则处理异构数据
4、跟据某些业务规则来触发告警
5、更多。。。。。。。。。

因此,我们很想自已来开发ES插件来满足业务需求,但ES插件在开发上确实不方便,如:权限严格、不支持热加载需要重启、对初学者不友好、版本升级(特别是大版本)后不向下兼容 等。所以我设想增加一层,如果我们能做一个插件平台,它与es打交道,其它的业务插件都在此平台上运行。这样就能一劳永逸地解决上述问题。

es插件平台开发

  所谓的插件平台,这是对业务层面来说的,其实它仍然是一个es插件。现在以es6.3.2这个版本进行说明es如何开发这个es插件,下载es6.3.2:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-3-2 ,解压后就可通过bin/elasticsearch 启动es,前提是你安装好了jdk。我们开发好的es插件是放到 "plugins"目录下的,这个目录初始为空,es默认并没有带有任何处置插件。整个项目的示例代码在: https://github.com/rjzjh/tams-es-plugin 。现在来一步步分解这个项目。

要开发一个es插件,在maven项目中引入依赖包:

 <dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>6.3.2</version>
 </dependency>

还需要引入一个打包用的maven插件:

	    <plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<version>2.3</version>
				<configuration>
					<appendAssemblyId>false</appendAssemblyId>
					<outputDirectory>${project.build.directory}/releases/</outputDirectory>
					<descriptors>
						<descriptor>${basedir}/src/assembly/plugin.xml</descriptor>
					</descriptors>
				</configuration>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

这个插件就是跟据plugin.xml文件来进行打包,最后放在tagert/releases 目录下生成一个zip包。这个zip包就是我们想要的插件,只要把这个zip解压到"plugins"目录,重启es,这个插件就生效了。

它的插件总入口在类:net.wicp.tams.common.es.plugin.TamsRestHandlerPlugin

public class TamsRestHandlerPlugin extends Plugin implements ActionPlugin {

	public static KeyConfigManager keyConfigManager;
	public static CommonService executor;
	public static URLClassLoader cloasLoader;

	@Override
	public List<RestHandler> getRestHandlers(final Settings settings, final RestController restController,
			final ClusterSettings clusterSettings, final IndexScopedSettings indexScopedSettings,
			final SettingsFilter settingsFilter, final IndexNameExpressionResolver indexNameExpressionResolver,
			final Supplier<DiscoveryNodes> nodesInCluster) {
		Logger logger = Loggers.getLogger(TamsRestHandlerPlugin.class, settings);
		logger.info("-------------------begin plugin------------------------------------");
		Properties props = IOUtil.fileToProperties("/plugin-default.properties", TamsRestHandlerPlugin.class);
		Conf.overProp(props);
		logger.info("-----size:{}", Conf.copyProperties().size());
		logger.info("path={},packagebase={}", Conf.get("common.es.plugin.path"),
				Conf.get("common.es.plugin.packagebase"));

		TamsRestHandlerPlugin.executor = new CommonService();
		String path = Conf.get("common.es.plugin.path");
		path = (StringUtil.isNull(path) || "none".equals(path))
				? IOUtil.mergeFolderAndFilePath(IOUtil.getCurFolder(TamsRestHandlerPlugin.class).getParent(), "/plugin")
				: path;
		File pluginDir = new File(path);
		if (!pluginDir.exists()) {
			try {
				FileUtils.forceMkdir(pluginDir);
			} catch (IOException e) {
				logger.error("创建插件目录:" + path + "失败", e);
			}
		}
		String[] packages = Conf.get("common.es.plugin.packagebase").split(",");
		ClassLoadManager classLoadManager = new ClassLoadManager(path, 2, packages);
		// ClassLoadManager classLoadManager = new ClassLoadManager(path, 2, packages);
		TamsRestHandlerPlugin.cloasLoader = classLoadManager.getCloasLoader();
		TamsRestHandlerPlugin.keyConfigManager = new KeyConfigManager(TamsRestHandlerPlugin.cloasLoader);
		TamsRestHandlerPlugin.executor.setBusiManager(classLoadManager);
		TamsRestHandlerPlugin.executor.setConfigManager(TamsRestHandlerPlugin.keyConfigManager);
		logger.info("-------------------------tams plugins start sucess------------------------------");
		// return singletonList(new RestPutMappingAction(settings, restController));
		return Arrays.asList(new ConnectorRest(settings, restController));
	}
}

在入口类继承虚类:org.elasticsearch.plugins.Plugin 。要开发不同类型的接口需要实现 不同的接口,我现在想开发一个rest接口形式的插件,对外会提供http接口.那么我实现了接口:ActionPlugin。这个插口有一个方法必须实现“getRestHandlers”,这就是插件的扩展点了。这里面我做的很简单,就是引入了“common-connector”模块,自定义了ClassLoadManager,这个classload会对“Conf.get(“common.es.plugin.packagebase”)”这个配置项配置的目录中的业务插件(下节会讲)进行懒加载。

  此插件现在仅开发了一个hander:“ConnectorRest”,这个hander是对cat进行了扩展,所以它继承了虚类:“org.elasticsearch.rest.action.cat.AbstractCatAction”,这个方式是指示此hander会对哪个url进行处理:

@Override
	protected void documentation(StringBuilder sb) {
		sb.append("/_cat/tams/connector\n");
	}

构造函数里指示对请求的类型的要求,支持post和get:

public ConnectorRest(Settings settings, RestController controller) {
		super(settings);
		controller.registerHandler(GET, Conf.get("common.es.plugin.connector.url"), this);
		controller.registerHandler(POST, Conf.get("common.es.plugin.connector.url"), this);
	}

而处理逻辑较为简单:

	@Override
	protected RestChannelConsumer doCatRequest(RestRequest request, NodeClient client) {
		Thread.currentThread().setContextClassLoader(TamsRestHandlerPlugin.cloasLoader);
		BytesReference content = request.content();
		String contextstr = new String(content.toBytesRef().bytes);
		// logger.info("contextstr=" + contextstr);
		JSONObject inputparam = JSONObject.parseObject(contextstr);
		CusDynaBean inputBean = keyConfigManager.getInputBeanInputBody(inputparam);
		// logger.info("transactionNo=" + inputBean.getStrValueByName("transactionNo"));
		String appKey = inputparam.getJSONObject(XMLNameSpace.ControlInfo).getString(Request.requestCommand);
		IBusiApp bean = executor.getBusiManager().getBean(appKey);
		if (AbsBusiApp.class.isAssignableFrom(bean.getClass())) {
			((AbsBusiApp) bean).setNodeClient(client);
			((AbsBusiApp) bean).setLogger(logger);
		}
		CusDynaBean outbean = executor.exe(inputBean, bean);
		RestResponse response = new BytesRestResponse(RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE,
				outbean.getJsonObj().toJSONString());
		return channel -> {
			try {
				channel.sendResponse(response);
			} catch (final Exception e) {
				channel.sendResponse(new BytesRestResponse(channel, e));
			}
		};
	}

它会把请求的参数按“common-connector”模块的参数要求进行组装并调用相关的实现逻辑,然后把“common-connector”模块的结果原样返回给浏览器。

  经过此处理逻辑后,所有的只要满足“common-connector”模块的处理逻辑,放到此插件配置的自定义了ClassLoadManager能读取到的目录,就可以在浏览器调用了。而示例代码中的"tams-es-plugin-mapping"模块就是这么一个满足“common-connector”模块的处理逻辑。这个模块的pom文件要注意的是需引入maven插件:

			<plugin>
				<groupId>net.wicp.tams</groupId>
				<artifactId>ts-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>plugintar</id>
						<phase>package</phase>
						<goals>
							<goal>plugin</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

它会把"tams-es-plugin-mapping"模块打包为一个完整的tar包,这样就方便部署了,只需把这个tar包解压到ClassLoadManager能读取到的目录就完成了部署。

插件平台配置

“plugin-default.properties”文件是其默认的配置,如果有不同可做修改调整,其中这几个配置较为重要:

common.es.plugin.packagebase=net.wicp.tams.common.es.plugin,
common.es.plugin.path=/data/es/plugins
common.es.plugin.connector.url=/_cat/tams/connector

url:这个插件平台hander响应的地址

path: 这个指示业务业务插件存放的目录,就是自定义的classload可以加载的目录。

packagebase:指示业务插件会存放在哪个包下面,这样可以缩小搜索范围。类似于spring的component-scan。

插件部署

  在运行此插件平台,需要在部署运行前还需要添加java的相关策略,修改文件:$JAVA_HOME\jre\lib\security\java.policy添加下列策略:

    permission java.util.PropertyPermission "*", "read,write";
    permission java.lang.RuntimePermission "createClassLoader"; 
    permission java.lang.RuntimePermission "getClassLoader"; 
    permission java.lang.RuntimePermission "closeClassLoader"; 
    permission java.io.FilePermission "/data/es/plugins", "read"; 
    permission java.io.FilePermission "/data/es/plugins", "write"; 
    permission java.io.FilePermission "<<ALL FILES>>" , "read,write"; 
    permission java.lang.RuntimePermission "accessDeclaredMembers"; 
    permission java.lang.RuntimePermission "setContextClassLoader"; 
    permission java.net.SocketPermission "*:*","accept,connect,resolve";

  在总的目录 D:\source\github\tams-es-plugin下执行mvn命令:mvn clean install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true ,把tams-es-plugin-platform模块的target\releases目录下tams-es-plugin-platform-3.6.5.zip文件解压到 es插件的plugins目录下。完成了插件平台的部署

  业务插件插件部署:把tams-es-plugin-mapping模块target目录下的tams-es-plugin-mapping.tar文件解压到配置项:“common.es.plugin.connector.url” 所配置的文件夹“/data/es/plugins”目录下。完成业务插件的部署

业务插件的调试

在业务插件开发和故障定位过程中,单步调试必不可少,但插件的运行依赖于ES,所以不能像正常代码一样以main方法为入口的调试,但它是java代码,那么利用远程调试也能达到一样的效果。

要进行远程调试,首先修改elasticsearch.bat(window环境),elasticsearch(linux环境)启动参数,加上“-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9999” 其中9999是指远程调试端口。然后启动es,那么启动程序会进入等待状态:

配置远程启动(Remote Java Application):注意port就是上面配置的端口号

启动后就会进到我们设置的断点处进行单步调试:

再看es的控制台已加载到我们的插件平台了(tamsRest):

功能测试

插件平台

  插件平台“tams-es-plugin-platform”主要的功能是管理好自定义的classload,实现对所有业务插件的热加载。它也是业务插件与ES的一个桥梁。它规范了业务插件的http接口必需满足“common-connector”模块对输入输出参数的定义。它也定义了一个功能:重载加所有的业务插件,这样就可以实现热加载了。

其中参数:“requestCommand”:“Refresh” 是指示要调用的命令的,其它的参数随便填。

业务插件

  业务插件“tams-es-plugin-mapping”是被插件平台所管理的业务插件,它主要实现了下列功能:

  • 跟据数据库的表生成对应的用于生成ES静态mapping用的Json字符串。数据库的字段类型与ES的类型会有一个默认的映射关系。

这个json就是指示创建索引时的字段名和字段类型,可以跟据需求进行修改,然后使用下面的功能进行索引的创建。

  • 在ES上创建静态索引,它的mapping是跟据上面生成的json字符串来生成的,中间可以修改。

  • 把上面2个功能聚合为一个功能,跟据数据库的表直接生成索引。

第二、第三个功能对ES的影响:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

偏锋书生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值