Java & GraalVM Native Image: 제조 앱에서 데이터베이스 연결성 향상
오늘날 제조 산업의 애플리케이션 환경은 엄격한 계층으로 나뉩니다. ERP 시스템을 사용하는 관리 수준에서 MES를 사용하는 계획 시스템, SCADA를 사용하는 감독 시스템, 그리고 최하단의 PLC와 필드 시스템으로 구현된 제어 시스템까지.
관리, 계획, 감독 시스템 대부분이 고수준 객체 지향 프로그래밍 언어로 구현되는 반면, 제어 시스템은 C가 지배적인 저수준 언어로 완전히 구현됩니다.
감독 수준에서 알려진 고수준 언어에서 제어 수준의 저수준 언어로의 급격한 변화는 여러 문제를 야기합니다. 완전히 다른 도구와 생태계가 필요합니다. 구현을 위해 완전히 다른 사고방식을 가진 개발자를 투입해야 합니다. 두 세계 또는 시스템 간의 인터페이스를 정의해야 합니다. 오직 제어 수준에서 감독 수준의 고수준 프로그래밍 언어를 계속 사용할 수 없기 때문입니다. 이제 이것이 바뀌었습니다. 예를 들어 PLC의 제어 수준에서 컨테이너 기술을 사용하면 Java 같은 프로그래밍 언어를 이 계층 수준에서 사용할 수 있어 엄격한 계층을 깰 수 있습니다.
Java는 널리 사용되는 고수준 객체 지향 프로그래밍 언어입니다. 활기찬 커뮤니티와 라이브러리 및 프레임워크 생태계를 가지고 있어 기존 도구와 솔루션을 활용해 애플리케이션을 더 빠르고 효율적으로 구축할 수 있습니다.
데이터베이스와 직접 통신해 애플리케이션 관련 정보를 검색 및 저장하고 웹 인터페이스에 표시하는 PLCnext에서 실행되는 애플리케이션 개발을 Java로 단순화하는 방법을 보여드리겠습니다. Java에서 가장 인기 있는 프레임워크 중 하나는 Hibernate입니다. 이는 Java 객체를 관계형 데이터베이스 테이블에 매핑하는 과정을 단순화해 데이터베이스 작업에 필요한 상용구 코드를 줄여줍니다. Hibernate는 높은 수준의 추상화를 제공해 개발자가 SQL 쿼리 대신 객체로 작업할 수 있게 합니다. 이는 더 빠른 개발 주기와 개발 노력 감소로 이어질 수 있습니다. Hibernate는 다양한 데이터베이스 벤더 간의 차이를 추상화해 상당한 코드 변경 없이 데이터베이스를 전환하기 쉽게 만듭니다. 이 글에서는 PLC에서 실행되는 소프트웨어를 데이터베이스에 연결하기 위한 Hibernate 통합을 설명합니다.
PLCnext에서의 현대적 Java 애플리케이션
현대적 Java 애플리케이션 구현을 시작하려면 Quarkus나 Spring Boot 같은 애플리케이션 프레임워크 사용을 권장합니다. 이 프레임워크들은 프로젝트 구성과 의존성 관리를 단순화합니다.
이 예제에서는 Quarkus의 'Using Hibernate ORM and Jakarta Persistence Guide'를 사용해 애플리케이션을 시작합니다. 소스 코드 예제는 GitHub 프로젝트 hibernate-orm-quickstart에서 찾을 수 있습니다.
애플리케이션 소스 코드 수정을 시작합니다. Java 클래스 Fruit.java를 Event.java로 변경하고 date 필드를 추가합니다.
Event.java 코드 예제:
... @Entity @Table(name = "Events") public class Event { @Id @GeneratedValue private Long id; private String title; @Column(name = "eventDate") private LocalDateTime date; ...
application.properties 파일에서 데이터베이스 URL과 자격 증명을 구성할 수 있습니다.
src/main/resources/application.properties 예제:
quarkus.datasource.db-kind=postgresql quarkus.datasource.username=myusername quarkus.datasource.password=mypassword quarkus.datasource.jdbc.url=jdbc:postgresql://myremotehost/mydatabase quarkus.datasource.jdbc.max-size=8 quarkus.datasource.jdbc.min-size=2 quarkus.hibernate-orm.database.generation=create ...
애플리케이션이 시작되면 필요한 경우 데이터베이스에 테이블이 생성되고 초기화됩니다. 시작 후 PLCnext에서 8080 포트에서 실행되는 웹 인터페이스로 데이터베이스와 상호작용할 수 있습니다:
이 모든 것이 중간 시스템 없이 제어 수준에서 일어난다는 점을 명심하세요.
GraalVM Native Image
많은 개발자는 여전히 Java가 소위 Java Runtime Environment를 필요로 하고 필요한 성능을 제공하지 않는다고 믿습니다. 이는 임베디드 애플리케이션에서는 더 이상 사실이 아닙니다. 이 예제에서는 GraalVM Native Image 기술을 사용해 Java 코드를 네이티브 애플리케이션으로 컴파일합니다. GraalVM의 네이티브 이미지 컴파일은 리소스가 제한된 임베디드 시스템과 같은 환경에서 Java 애플리케이션의 시작 시간과 메모리 소비 문제를 해결하는 매력적인 솔루션을 제공합니다. Java 애플리케이션을 네이티브 실행 파일로 사전 컴파일함으로써 GraalVM은 기존 Just-In-Time(JIT) 컴파일에 비해 시작 시간과 메모리 오버헤드를 크게 줄입니다.
MicroDoc의 GraalVM은 임베디드 장치용 바이너리 생성 기능이 독특합니다. 이 튜토리얼 작성 시점에 GraalVM은 32비트 및 64비트 ARM과 x86 프로세서를 지원합니다.
PLC AXC F 1152를 타겟으로 Java 애플리케이션을 사전 컴파일하려면 MicroDoc의 GraalVM을 사용하고 application.properties 파일에서 몇 가지 컴파일러 옵션을 구성할 수 있습니다.
... quarkus.native.additional-build-args=--target=linux-arm,-H:CompilerBackend=llvm,-H:+PreserveFramePointer,-Dllvm.bin.dir=/llvm/bin,--native-compiler-path=/arm-none-linux-gnueabihf-g++,-H:CAPCacheDir=/cap-cache/armv7a-linux-gnueabihf
교차 컴파일 및 디버깅 과정에 대한 자세한 내용은 다음 기사에서 확인할 수 있습니다: Building and debugging Java native images of MicroDoc GraalVM Embedded
애플리케이션을 빌드하려면 다음 명령만 사용하면 됩니다:
$ mvn -Pnative package
다음으로 PLCnext 시뮬레이터를 시작합니다. 시뮬레이터는 qemu 이미지로 제공됩니다. 시뮬레이터는 다음 줄로 우리를 맞이합니다:
PLCnext Linux 2023.0 sim-axcf1152 ttyAMA0 sim-axcf1152 login:
생성된 바이너리는 scp 명령으로 PLC에 복사할 수 있습니다. 이 명령은 PLC에 보안 셸을 열고 바이너리를 타겟 시스템으로 전송합니다. 다음 명령으로 애플리케이션을 시작할 수 있습니다:
$ ./application
PLCnext Cockpit 클라이언트로 현재 메모리와 스토리지 사용량도 확인할 수 있습니다:
그러나 단일 애플리케이션의 시작 시간과 메모리 소비가 OpenJDK 같은 Java Runtime Environment에서 실행할 때와 비교해 어떤지도 궁금합니다. 따라서 다음 표와 같이 두 값 모두 측정했습니다:
시작 시간(낮을수록 좋음), 메모리 사용량(낮을수록 좋음)
GraalVM Native Image: 0.413초, 87MB
OpenJDK: 13초, 128MB
GraalVM Native Image는 OpenJDK에 비해 시작 시간과 메모리 사용량 모두에서 현저히 향상된 성능을 제공해 효율적인 애플리케이션 배포를 위한 리소스 소비 최적화의 효과를 입증합니다.
요약
PLC 같은 제어 수준에서 Java를 사용하면 여러 이점이 있습니다. 첫째, 감독 수준과 제어 수준 사이에 기술적 단절이 없습니다. 동일한 인력이 애플리케이션을 구현하고 Java 생태계와 사용 가능한 도구의 이점을 누릴 수 있습니다. 둘째, GraalVM은 32비트 및 64비트 ARM과 x86 프로세서 같은 임베디드 장치에서 Java 코드를 네이티브 애플리케이션으로 컴파일할 수 있습니다. 따라서 개발자는 기본 아키텍처를 신경 쓰지 않고 고수준 객체 지향 언어로 애플리케이션을 구현할 수 있습니다. 셋째, Phoenix Contact의 PLCnext 컨테이너 지원 덕분에 동일한 하드웨어 구성 요소에서 PLC 인터페이스에 직접 접근할 수 있어 현재 제조 산업 애플리케이션의 엄격한 계층을 깰 수 있습니다.
참고:
Makers Blog는 Phoenix Contact에서 테스트하거나 검토하지 않은 커뮤니티 구성원의 애플리케이션과 사용자 스토리를 보여줍니다. 자신의 책임 하에 사용하세요.