슬 래 그 Elastic Search 소스 코드 분석 - 시작 프로 세 스 (상)
20778 단어 elasticsearch자바
옮 겨 싣 기 원본 주 소 는 다음 과 같 습 니 다.http://www.54tianzhisheng.cn/2018/08/11/es-code02/
전제 조건
위의 글 은 ElasticSearch 소스 코드 해석 - 환경 구축 을 썼 습 니 다. 그 중에서 server 모듈 을 여 는 Elasticsearch 류 를 시작 하 라 고 했 습 니 다. org. elasticsearch. bootstrap. Elasticsearch. 안에 있 는 main 함 수 를 실행 하면 ElasticSearch 를 시작 할 수 있 습 니 다. 이 글 은 시작 절 차 를 설명 합 니 다. 지면 이 많 기 때문에 두 편 으로 나 누 어 썼 습 니 다.
시작 프로 세 스
main 방법 입구
입 구 를 볼 수 있 는 것 은 main 방법 입 니 다. 방법 은 권한 을 검사 한 다음 에 오류 로그 모니터 (로그 설정 전에 상태 로그 에 error 가 나타 나 지 않도록 합 니 다) 입 니 다. 그 다음 에 Elasticsearch 대상 을 만 든 다음 에 정적 방법 main 방법 (18 줄) 을 호출 하여 만 든 대상 과 인자, Terminal 기본 값 을 전달 합 니 다.정적 main 방법 에서 elasticsearch. main 방법 을 호출 합 니 다.
public static void main(final String[] args) throws Exception { //1、
// we want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
// presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy)
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission perm) {
// grant all permissions so that we can later set the security manager to the one that we want
}
});
LogConfigurator.registerErrorListener(); //
final Elasticsearch elasticsearch = new Elasticsearch();
int status = main(args, elasticsearch, Terminal.DEFAULT); //2、 Elasticsearch.main
if (status != ExitCodes.OK) {
exit(status);
}
}
static int main(final String[] args, final Elasticsearch elasticsearch, final Terminal terminal) throws Exception {
return elasticsearch.main(args, terminal); //3、command main
}
Elasticsearch 클래스 는 Environment Aware Command 클래스 를 계 승 했 기 때문에 Environment Aware Command 클래스 는 Command 클래스 를 계 승 했 지만 Elasticsearch 클래스 는 main 방법 을 다시 쓰 지 않 았 기 때문에 위 에서 호출 한 elasticsearch. main 은 사실 Command 의 main 방법 을 호출 했 습 니 다. 코드 는 다음 과 같 습 니 다.
/** Parses options for this command from args and executes it. */
public final int main(String[] args, Terminal terminal) throws Exception {
if (addShutdownHook()) { // Runtime.getRuntime().addShutdownHook Hook, Hook
shutdownHookThread = new Thread(() -> {
try {
this.close();
} catch (final IOException e) {
try (
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw)) {
e.printStackTrace(pw);
terminal.println(sw.toString());
} catch (final IOException impossible) {
// StringWriter#close declares a checked IOException from the Closeable interface but the Javadocs for StringWriter
// say that an exception here is impossible
throw new AssertionError(impossible);
}
}
});
Runtime.getRuntime().addShutdownHook(shutdownHookThread);
}
beforeMain.run();
try {
mainWithoutErrorHandling(args, terminal);//4、mainWithoutErrorHandling
} catch (OptionException e) {
printHelp(terminal);
terminal.println(Terminal.Verbosity.SILENT, "ERROR: " + e.getMessage());
return ExitCodes.USAGE;
} catch (UserException e) {
if (e.exitCode == ExitCodes.USAGE) {
printHelp(terminal);
}
terminal.println(Terminal.Verbosity.SILENT, "ERROR: " + e.getMessage());
return e.exitCode;
}
return ExitCodes.OK;
}
위의 코드 는 처음에 체크 함 수 를 이용 하여 프로그램 이 종 료 될 때 이 Hook 을 터치 합 니 다. 이 방법 은 주요 코드 는 main Without Error Handling () 방법 입 니 다. 그 다음 에 아래 는 catch 유지 방법 이 던 진 이상 입 니 다. 방법 코드 는 다음 과 같 습 니 다.
/*** Executes the command, but all errors are thrown. */
void mainWithoutErrorHandling(String[] args, Terminal terminal) throws Exception {
final OptionSet options = parser.parse(args);
if (options.has(helpOption)) {
printHelp(terminal);
return;
}
if (options.has(silentOption)) {
terminal.setVerbosity(Terminal.Verbosity.SILENT);
} else if (options.has(verboseOption)) {
terminal.setVerbosity(Terminal.Verbosity.VERBOSE);
} else {
terminal.setVerbosity(Terminal.Verbosity.NORMAL);
}
execute(terminal, options);//5、 EnvironmentAwareCommand execute(),( command execute )
}
위의 코드 는 3 ~ 14 줄 에서 들 어 오 는 인 자 를 분석 하고 terminal 을 설정 합 니 다. 중요 한 execute () 방법 은 Environment Aware Command 의 execute () (Command 류 의 추상 적 인 execute 방법 을 다시 썼 습 니 다) 입 니 다. 위의 상속 도 에서 Environment Aware Command 가 Command 를 계승 하고 다시 쓴 execute 방법 코드 는 다음 과 같 습 니 다.
@Override
protected void execute(Terminal terminal, OptionSet options) throws Exception {
final Map settings = new HashMap<>();
for (final KeyValuePair kvp : settingOption.values(options)) {
if (kvp.value.isEmpty()) {
throw new UserException(ExitCodes.USAGE, "setting [" + kvp.key + "] must not be empty");
}
if (settings.containsKey(kvp.key)) {
final String message = String.format(
Locale.ROOT, "setting [%s] already set, saw [%s] and [%s]",
kvp.key, settings.get(kvp.key), kvp.value);
throw new UserException(ExitCodes.USAGE, message);
}
settings.put(kvp.key, kvp.value);
}
//6、 ide vm options path.data、path.home、path.logs
putSystemPropertyIfSettingIsMissing(settings, "path.data", "es.path.data");
putSystemPropertyIfSettingIsMissing(settings, "path.home", "es.path.home");
putSystemPropertyIfSettingIsMissing(settings, "path.logs", "es.path.logs");
execute(terminal, options, createEnv(terminal, settings));//7、 createEnv
//9、 elasticsearch execute ,elasticsearch EnvironmentAwareCommand execute
}
방법 앞 에는 전송 참조 에 따라 설정 을 판단 합 니 다. 설정 이 비어 있 으 면 putSystem Property IfSetting IsMissing 방법 으로 바로 이동 합 니 다. 여기 에는 path. data, path. home, path. logs 설정 es 의 data, home, logs 디 렉 터 리 세 가지 속성 이 설정 되 어 있 습 니 다. 여 기 는 우리 ide 가 설정 한 vm options 에 따라 설정 되 어 있 습 니 다.이것 도 우리 가 지난 글 에서 말 한 설정 정보 입 니 다. 설정 하지 않 으 면 바로 잘못 보고 하 는 이유 입 니 다.다음은 putSystem Property IfSetting IsMissing 방법 코드 에서 어떻게 하 는 지 보 겠 습 니 다.
/** Ensure the given setting exists, reading it from system properties if not already set. */
private static void putSystemPropertyIfSettingIsMissing(final Map settings, final String setting, final String key) {
final String value = System.getProperty(key);// key(es.path.data)
if (value != null) {
if (settings.containsKey(setting)) {
final String message =
String.format(
Locale.ROOT,
"duplicate setting [%s] found via command-line [%s] and system property [%s]",
setting, settings.get(setting), value);
throw new IllegalArgumentException(message);
} else {
settings.put(setting, value);
}
}
}
이 세 가지 방법 을 실행 한 후:
이 방법 에서 벗 어 나 계속 보면 execute 방법 이 방법 을 호출 한 것 을 발견 할 수 있 습 니 다.
execute(terminal, options, createEnv(terminal, settings));
여기 서 먼저
createEnv(terminal, settings)
방법 을 살 펴 보 자.protected Environment createEnv(final Terminal terminal, final Map settings) throws UserException {
final String esPathConf = System.getProperty("es.path.conf");//8、 vm options es.path.conf
if (esPathConf == null) {
throw new UserException(ExitCodes.CONFIG, "the system property [es.path.conf] must be set");
}
return InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings, getConfigPath(esPathConf)); //8、 prepareEnvironment
}
우리 ide vm options 에 설 치 된 es. path. conf 를 읽 습 니 다. 이전 글 에서 도 이 설정 을 꼭 해 야 합 니 다. es 가 시 작 될 때 우리 의 설정 과 플러그 인 을 불 러 오기 때 문 입 니 다.위 코드 6 줄 의 prepare Environment 방법 을 계속 살 펴 보 겠 습 니 다.
public static Environment prepareEnvironment(Settings input, Terminal terminal, Map properties, Path configPath) {
// just create enough settings to build the environment, to get the config dir
Settings.Builder output = Settings.builder();
initializeSettings(output, input, properties);
Environment environment = new Environment(output.build(), configPath);
// es.path.conf yml ,
if (Files.exists(environment.configFile().resolve("elasticsearch.yaml"))) {
throw new SettingsException("elasticsearch.yaml was deprecated in 5.5.0 and must be renamed to elasticsearch.yml");
}
if (Files.exists(environment.configFile().resolve("elasticsearch.json"))) {
throw new SettingsException("elasticsearch.json was deprecated in 5.5.0 and must be converted to elasticsearch.yml");
}
output = Settings.builder(); // start with a fresh output
Path path = environment.configFile().resolve("elasticsearch.yml");
if (Files.exists(path)) {
try {
output.loadFromPath(path); //
} catch (IOException e) {
throw new SettingsException("Failed to load settings from " + path.toString(), e);
}
}
// re-initialize settings now that the config file has been loaded
initializeSettings(output, input, properties); //
finalizeSettings(output, terminal);
environment = new Environment(output.build(), configPath);
// we put back the path.logs so we can use it in the logging configuration file
output.put(Environment.PATH_LOGS_SETTING.getKey(), environment.logsFile().toAbsolutePath().normalize().toString());
return new Environment(output.build(), configPath);
}
준 비 된 환경 은 위의 그림 과 같 습 니 다. 구 축 된 환경 을 통 해 프로필 elasticsearch. yml 이 yml 로 끝 나 는 지 확인 하고, Yml 나 json 으로 끝 나 는 경우 이상 을 던 집 니 다 (5.5.0 버 전의 다른 두 가지 형식 이 만 료 되 었 습 니 다. yml 형식 만 사용 할 수 있 습 니 다). 그리고 이 프로필 을 불 러 와 서 내용 (KV 구조) 을 읽 습 니 다.
createEnv 방법 에서 벗 어 나 execute 방법 을 계속 봅 시다.
Environment Aware Command 류 의 execute 방법 코드 는 다음 과 같 습 니 다.
protected abstract void execute(Terminal terminal, OptionSet options, Environment env) throws Exception;
이것 은 추상 적 인 방법 입 니 다. 그러면 그의 실현 방법 은 Elasticsearch 류 에서 코드 는 다음 과 같 습 니 다.
@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException {
if (options.nonOptionArguments().isEmpty() == false) {
throw new UserException(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments());
}
if (options.has(versionOption)) {
final String versionOutput = String.format(
Locale.ROOT,
"Version: %s, Build: %s/%s/%s/%s, JVM: %s",
Version.displayVersion(Version.CURRENT, Build.CURRENT.isSnapshot()),
Build.CURRENT.flavor().displayName(),
Build.CURRENT.type().displayName(),
Build.CURRENT.shortHash(),
Build.CURRENT.date(),
JvmInfo.jvmInfo().version());
terminal.println(versionOutput);
return;
}
final boolean daemonize = options.has(daemonizeOption);
final Path pidFile = pidfileOption.value(options);
final boolean quiet = options.has(quietOption);
// a misconfigured java.io.tmpdir can cause hard-to-diagnose problems later, so reject it immediately
try {
env.validateTmpFile();
} catch (IOException e) {
throw new UserException(ExitCodes.CONFIG, e.getMessage());
}
try {
init(daemonize, pidFile, quiet, env); //10、
} catch (NodeValidationException e) {
throw new UserException(ExitCodes.CONFIG, e.getMessage());
}
}
위의 코드 에 서 는 주로
init(daemonize, pidFile, quiet, env);
초기 화 방법 을 보 세 요.void init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv)
throws NodeValidationException, UserException {
try {
Bootstrap.init(!daemonize, pidFile, quiet, initialEnv); //11、 Bootstrap init
} catch (BootstrapException | RuntimeException e) {
// format exceptions to the console in a special way
// to avoid 2MB stacktraces from guice, etc.
throw new StartupException(e);
}
}
init 방법
Bootstrap 의 정적 init 방법 은 다음 과 같 습 니 다.
static void init(
final boolean foreground,
final Path pidFile,
final boolean quiet,
final Environment initialEnv) throws BootstrapException, NodeValidationException, UserException {
// force the class initializer for BootstrapInfo to run before
// the security manager is installed
BootstrapInfo.init();
INSTANCE = new Bootstrap(); //12、 Bootstrap
final SecureSettings keystore = loadSecureSettings(initialEnv);//
final Environment environment = createEnvironment(foreground, pidFile, keystore, initialEnv.settings(), initialEnv.configFile()); //
try {
LogConfigurator.configure(environment); //13、log
} catch (IOException e) {
throw new BootstrapException(e);
}
if (environment.pidFile() != null) {
try {
PidFile.create(environment.pidFile(), true);
} catch (IOException e) {
throw new BootstrapException(e);
}
}
final boolean closeStandardStreams = (foreground == false) || quiet;
try {
if (closeStandardStreams) {
final Logger rootLogger = ESLoggerFactory.getRootLogger();
final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
if (maybeConsoleAppender != null) {
Loggers.removeAppender(rootLogger, maybeConsoleAppender);
}
closeSystOut();
}
// fail if somebody replaced the lucene jars
checkLucene(); //14、 Lucene
// install the default uncaught exception handler; must be done before security is initialized as we do not want to grant the runtime permission setDefaultUncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler(
new ElasticsearchUncaughtExceptionHandler(() -> Node.NODE_NAME_SETTING.get(environment.settings())));
INSTANCE.setup(true, environment); //15、 setup
try {
// any secure settings must be read during node construction
IOUtils.close(keystore);
} catch (IOException e) {
throw new BootstrapException(e);
}
INSTANCE.start(); //26、 start
if (closeStandardStreams) {
closeSysError();
}
} catch (NodeValidationException | RuntimeException e) {
// disable console logging, so user does not see the exception twice (jvm will show it already)
final Logger rootLogger = ESLoggerFactory.getRootLogger();
final Appender maybeConsoleAppender = Loggers.findAppender(rootLogger, ConsoleAppender.class);
if (foreground && maybeConsoleAppender != null) {
Loggers.removeAppender(rootLogger, maybeConsoleAppender);
}
Logger logger = Loggers.getLogger(Bootstrap.class);
if (INSTANCE.node != null) {
logger = Loggers.getLogger(Bootstrap.class, Node.NODE_NAME_SETTING.get(INSTANCE.node.settings()));
}
// HACK, it sucks to do this, but we will run users out of disk space otherwise
if (e instanceof CreationException) {
// guice: log the shortened exc to the log file
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintStream ps = null;
try {
ps = new PrintStream(os, false, "UTF-8");
} catch (UnsupportedEncodingException uee) {
assert false;
e.addSuppressed(uee);
}
new StartupException(e).printStackTrace(ps);
ps.flush();
try {
logger.error("Guice Exception: {}", os.toString("UTF-8"));
} catch (UnsupportedEncodingException uee) {
assert false;
e.addSuppressed(uee);
}
} else if (e instanceof NodeValidationException) {
logger.error("node validation exception
{}", e.getMessage());
} else {
// full exception
logger.error("Exception", e);
}
// re-enable it if appropriate, so they can see any logging during the shutdown process
if (foreground && maybeConsoleAppender != null) {
Loggers.addAppender(rootLogger, maybeConsoleAppender);
}
throw e;
}
}
이 방법 은 주로 다음 과 같다.
1. Bootstrap 인 스 턴 스 생 성
2. 보안 모듈 을 등록 하면 관련 설정 을 불 러 옵 니 다.
3. Elasticsearch 가 실행 되 는 필수 환경 과 관련 설정 을 만 듭 니 다. 예 를 들 어 config, scripts, plugins, modules, logs, lib, bin 등 설정 디 렉 터 리 를 실행 환경 에 불 러 옵 니 다.
4. 로그 설정 환경, 로그 컨 텍스트 생 성
5. PID 파일 이 존재 하 는 지 확인 하고 존재 하지 않 으 면 PID 파일 생 성
6. Lucene 버 전 검사
7. setup 방법 을 호출 합 니 다 (현재 환경 으로 노드 를 만 듭 니 다)
setup 방법
private void setup(boolean addShutdownHook, Environment environment) throws BootstrapException {
Settings settings = environment.settings();//
try {
spawner.spawnNativeControllers(environment);
} catch (IOException e) {
throw new BootstrapException(e);
}
initializeNatives(
environment.tmpFile(),
BootstrapSettings.MEMORY_LOCK_SETTING.get(settings),
BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings),
BootstrapSettings.CTRLHANDLER_SETTING.get(settings));
// initialize probes before the security manager is installed
initializeProbes();
if (addShutdownHook) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
IOUtils.close(node, spawner);
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configurator.shutdown(context);
} catch (IOException ex) {
throw new ElasticsearchException("failed to stop node", ex);
}
}
});
}
try {
// look for jar hell
final Logger logger = ESLoggerFactory.getLogger(JarHell.class);
JarHell.checkJarHell(logger::debug);
} catch (IOException | URISyntaxException e) {
throw new BootstrapException(e);
}
// Log ifconfig output before SecurityManager is installed
IfConfig.logIfNecessary();
// install SM after natives, shutdown hooks, etc.
try {
Security.configure(environment, BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(settings));
} catch (IOException | NoSuchAlgorithmException e) {
throw new BootstrapException(e);
}
node = new Node(environment) { //16、
@Override
protected void validateNodeBeforeAcceptingRequests(
final BootstrapContext context,
final BoundTransportAddress boundTransportAddress, List checks) throws NodeValidationException {
BootstrapChecks.check(context, boundTransportAddress, checks);
}
};
}
위의 코드 는 마지막 으로 Node 노드 의 생 성 입 니 다. 이 글 은 Node 의 생 성 을 말 하지 않 습 니 다. 다음 글 은 Node 노드 의 생 성과 ES 노드 를 본 격 적 으로 시작 하 는 것 을 잘 이야기 하 겠 습 니 다.
총결산
이 글 은 주로 대략적인 시작 절 차 를 직렬 로 연결 합 니 다. 편폭 이 비교적 많 기 때문에 두 편 으로 나 누 었 습 니 다. 먼저 세부 사항 을 잠 그 지 않 고 뒤의 절차 가 시작 되 는 글 을 다 쓴 후에 우 리 는 단일 한 버클 디 테 일 을 합 니 다.
관련 글
1. 슬 래 그 닭 은 왜 Elastic Search 소스 코드 를 봐 야 합 니까?
2. 슬 래 그 닭 의 Elastic Search 소스 분석 - 환경 구축
3. 슬 래 그 닭 의 Elastic Search 소스 코드 분석 - 시작 절차 (상)
4. 슬 래 그 닭 의 Elastic Search 소스 코드 분석 - 시작 절차 (하)
5. Elasticsearch 시리즈 글 (1): Elasticsearch 기본 단어 기 와 중간 단어 기 간 의 비교 및 사용 방법
6. Elasticsearch 시리즈 글 (2): 전문 검색엔진 Elasticsearch 클 러 스 터 구축 입문 강좌
7. Elasticsearch 시리즈 글 (3): ElasticSearch 클 러 스 터 모니터링
8. Elasticsearch 시리즈 글 (4): ElasticSearch 단일 노드 모니터링
9. Elasticsearch 시리즈 글 (5): ELK 실시 간 로그 분석 플랫폼 환경 구축
10. IDEA 원 격 Debug Elastic Search 에서
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
kafka connect e elasticsearch를 관찰할 수 있습니다.No menu lateral do dashboard tem a opção de connectors onde ele mostra todos os clusters do kafka connect conectados atu...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.