인포테이블 작업
인포테이블은 캐시의 단일 객체로 메모리에 저장됩니다. 따라서 ThingWorx 8.5 이상에서 인포테이블 직접 조작은 지원되지 않습니다. 그럴 경우 예기치 않은 동작 및 성능 문제가 발생할 수 있습니다. 사물에서 인포테이블 속성을 검색할 때 원래 객체를 다시 나타내는 프록시 객체가 작성됩니다. 직접 변경은 로컬 복사본에만 적용되지만, 함수 호출은 원래 객체를 업데이트합니다. 모든 데이터가 업데이트될 때까지 변경 사항이 프록시되지 않도록 객체의 전체 복제본이 필요한 경우 리소스의 복제 옵션을 사용합니다. 단일 행 인포테이블에 대한 아래 예에서는 래퍼 객체를 사용하지만, 여러 행 인포테이블의 경우 행이 변경될 때마다 업데이트하는 것을 원치 않으므로 전체 복제 옵션을 사용합니다.
다음은 로컬 프록시 객체를 만듭니다. 메소드 호출은 원래 객체를 업데이트하고 캐시에 저장합니다.
Things["data1"]는 "data1" 사물을 이름으로 검색합니다.
Things["data1"].info는 "data1" 사물에서 "info" 인포테이블을 검색합니다.
var myinfo = Things["data1"].info
다음은 변경 사항이 원래 객체에 다시 프록시되지 않는 전체 복제를 만듭니다.
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
ThingWorx 8.5 이상에서는 속성 데이터가 이전 릴리즈와는 다르게 처리됩니다. 이제 모든 데이터가 캐시 계층에 저장되므로 고가용성 클러스터링 환경에서 로컬로 또는 원격으로 사용할 수 있습니다. 이전 환경에서는 저장된 데이터가 직접 수정되었지만 캐시 계층에서는 데이터가 변경될 때 캐시로 들어오고 나가야 합니다. 클러스터링 환경에서는 캐시가 분산됩니다. 따라서 추가 네트워크 지연 시간 및 유선 직렬화로 인해 각 요청에 대한 시간이 추가됩니다.
속성에 많은 양의 데이터를 인포테이블로 저장하는 것은 이제 비용이 많이 들며 클러스터링된 환경에서는 시스템 충돌을 일으킬 수 있습니다. 이제 데이터가 변경되면 인포테이블 전체를 읽고 속성에 기록합니다. 클러스터링된 환경에서는 전체 객체도 직렬화 및 역직렬화되고 유선을 통해 전송됩니다. 대형 인포테이블을 단일 속성에 저장하지 않고 데이터베이스로 이동해야 합니다. 이를 사용자 정의 테이블로 변환하거나 데이터 테이블에 배치할 수 있습니다.
클러스터링된 환경에서는 Apache Ignite가 사용됩니다. 대형 객체를 푸시하면 Ignite가 응답하지 않을 수 있습니다. Ignite는 쓰기 및 백업을 대기열에 넣습니다. 큰 값이 푸시되면 값을 처리하는 데 시간이 걸리고 처리가 백업될 수 있습니다. 백업이 큰 경우 Ignite 시스템 스레드가 차단되기 시작하며 Ignite는 노드가 응답하지 않는 것으로 간주하고 노드를 종료할 수 있습니다. 이로 인해 데이터가 점점 더 오래될 수 있습니다.
클러스터링된 환경에서 원활하게 작동하려면 속성에 저장되는 데이터의 크기를 줄이도록 응용 프로그램을 변경해야 할 수 있습니다. 이는 대개 수천 개의 행이 있는 인포테이블로 인해 발생합니다.
예: 인포테이블 정렬
이 예에서는 캐싱 레이어가 추가되기 전에 작업했습니다. 메모리에서 테이블을 직접 업데이트했습니다.
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
me.yourInfoTable.Sort(sort);
하지만 이제 다음과 같이 수행해야 합니다.
로컬 인포테이블을 생성하고 변경한 다음 사물 인포테이블 속성에 다시 지정합니다.
이렇게 하면 캐시에서 객체를 가져오고 복사본을 만듭니다. 그러면 설정이 완료될 때까지 원래 속성에 영향을 주지 않고 복사본을 변경할 수 있습니다.
그렇지 않은 경우 인포테이블에 연결할 때마다 전체 객체가 캐시에 다시 기록되어 성능 저하가 발생합니다.
var localInfoTable = me.yourInfoTable;
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
localInfoTable.Sort(sort);
me.yourInfoTable = localInfoTable;
예: 단일 행 인포테이블에 대한 필드 값 업데이트
잘못된 방법:
이 스크립트의 각 줄은 캐시에서 전체 인포테이블을 가져오고, 한 값을 변경한 다음 다시 캐시에 저장합니다. 매번 전체 인포테이블을 처리하므로 캐시까지 왕복하는 데 시간이 걸립니다. 이 경우 캐시를 6번 호출하여 원격 시스템에서 실제로 스크립트가 느려질 수 있습니다.
Things["data1"].info.v1 = 1;
Things["data1"].info.v2 = 2;
Things["data1"].info.v3 = 3;
올바른 방법:
이 예에서는 캐시에서 인포테이블의 복제본을 가져오고 모든 데이터를 로컬로 업데이트한 다음 캐시에 인포테이블을 다시 배치합니다. 캐시 호출을 단 두 번으로 줄입니다.
var myinfo = Things["data1"].info
myinfo.v1 = 1
myinfo.v2 = 2
myinfo.v3 = 3
Things["data1"].info = myinfo
예: 단일 행 인포테이블에서 필드 값 업데이트
아래 예에서는 인포테이블이 로컬 변수에 지정되는 경우 해당 인포테이블이 복제본임을 보여줍니다. 원본 객체에 대한 변경 사항은 복제된 값에 표시되지 않습니다.
// creates a clone of InfoTable
var myinfo = Things["data1"].info;
// sets value of v1 to 5 in local InfoTable
myinfo.v1 = 5;
// change the orignal data1's v1 field value to 4, will not update the local value, it is still 5
Things["data1"].info.v1 = 4;
// assigning local info table to data2 so its v1 will have a value of 5
Things["data2"].info = myinfo;
예: 여러 행 인포테이블을 사용하여 동작 변경
아래에서 인포테이블의 복제본이 여전히 프록시 객체임을 알 수 있습니다. 프록시 객체에서 호출되는 메소드는 주 객체에 적용됩니다. 다음은 프록시와 일치하지만 ThingWorx 8.4 동작과 다릅니다. ThingWorx 8.4에서 me.p2 = prop2인 경우 원본 객체에 대한 참조를 해제합니다. 이 경우 동일한 객체 프록시로 처리되므로 ThingWorx 9에서는 수행되지 않습니다.
// An InfoTable local object for the "v1" field
var newEntry = new Object();
newEntry.v1 = 1;
// creates a proxy object from local object prop1 -> me.p1
var prop1 = me.p1;
prop1.v1=4;
// creates a proxy object from local object prop2 -> me.p2
var prop2 = me.p2;
prop2.v1=5;
// updates the me.p1 object, this breaks the proxy between prop1 -> me.p1
me.p1=prop2;
// prop2 reference is unchanged, still proxied
me.p2=prop2;
// this will not change me.p1 since the reference was broken when the object assignement to prop2 was done
prop1.AddRow(newEntry);
// this will update me.p2, the object reference is the same
prop2.AddRow(newEntry);
예: 여러 행 인포테이블 빌드
이 예에서는 인포테이블에 행을 추가하려고 합니다.
잘못된 방법:
데이터베이스 AddRow에서 메소드를 사용하고 있기 때문에 올바른 것처럼 보이지만 실제로는 루프의 모든 이터레이션에 대해 원래 객체에 해당 변경을 프록시합니다. 따라서 루프의 모든 이터레이션에 대한 캐시에 인포테이블이 기록되어 바람직하지 않습니다.
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
올바른 방법:
이 예에서는 원래 객체에 다시 지정할 때까지 아무런 영향을 주지 않고 조작할 수 있도록 객체를 복제했습니다.
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
다음 예제도 적용됩니다. 프록시 객체 메소드를 사용하지 않기 때문에 해당 객체가 지정될 때까지 원래 객체가 변경되지 않습니다.
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2* 10;
row.v3 = i * 3* 100;
myinfo.rows[i] = row;
}
Things["data1"].info = myinfo;
도움이 되셨나요?