Support Questions
Find answers, ask questions, and share your expertise

OPC UA Client performance with Eclipse Milo

New Contributor

Hello Hortonworks Community!

I'm pretty new to OPC UA in general.

I recently implemeted a minimal test OPC UA Client with the SDK from the Eclipse Milo project. I'm currently doing some vague performance measuring. I'm connecting to a Kepware Server which isn't far away.

I'm getting about 1000000 values per 60 seconds with asynchronous reading and about 1500000 values with publish/subscribe.

Are these normal values? I'm asking because I'm so new to this, maybe I'm missing something critical to performance and I don't even know it.

If someone's interested, here's my code:

Publish/Subscribe (1.500.000 per 60 secs)

public class SubscriptionClient {

    private final AtomicLong clientHandles = new AtomicLong(1L);
    private static int counter = 0;

    private OpcUaClient createClient() throws Exception {
        EndpointDescription[] endpoints;
        endpoints = UaTcpStackClient
                .getEndpoints("theServerAdress")
                .get();
        EndpointDescription endpoint = endpoints[0];
        OpcUaClientConfig config = OpcUaClientConfig.builder()
                .setApplicationName(LocalizedText.english("MinimalClient"))
                .setApplicationUri("theURI")
                .setCertificate(null)
                .setKeyPair(null)
                .setEndpoint(endpoint)
                .setMaxResponseMessageSize(uint(50000))
                .setIdentityProvider(new AnonymousProvider())
                .setRequestTimeout(uint(5000))
                .build();
        return new OpcUaClient(config);
    }

    private void createSubscription(OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception {
        UaSubscription sub = client.getSubscriptionManager().createSubscription(10.0).get();
        UInteger clientHandle = uint(clientHandles.getAndIncrement());
        MonitoringParameters parameters = new MonitoringParameters(
                clientHandle,
                10.0,
                null,
                uint(10),
                true
        );
        
        BiConsumer<UaMonitoredItem, Integer> onItemCreated = (item, id) -> item.setValueConsumer(this::onSubscriptionValue);

        List<UaMonitoredItem> items = sub.createMonitoredItems(
                TimestampsToReturn.Both,
                createMonitoredItemCreateRequests(parameters),
                onItemCreated).get();

        for (UaMonitoredItem item: items) {
            if(item.getStatusCode().isGood()) {
                System.out.println("Item created for NodeId: " + item.getReadValueId().getNodeId());
            } else {
                System.out.println("Failed to create item for NodeId: " + item.getReadValueId().getNodeId() + item.getStatusCode());
            }
        }
        Thread.sleep(60000); //Runs for 60 seconds
        future.complete(client);
    }

    private void onSubscriptionValue(UaMonitoredItem item, DataValue value) {
        System.out.println("Subscription value recieved:");
        System.out.println("Item: " + item);
        System.out.println("Value: " + value);
        counter++;
        System.out.println("Counter is: " + counter);
    }

    public List<MonitoredItemCreateRequest> createMonitoredItemCreateRequests(MonitoringParameters parameters) throws IOException {
        List<String> ids = Files.readAllLines(Paths.get("C:\\Users\\user\\Downloads\\MiloTest\\src\\com\\company\\NodeIDs.txt"));
        List<ReadValueId> rvIDs = new ArrayList<>();

        for (String line: ids) {
            rvIDs.add(new ReadValueId(new NodeId(2, line.substring(7)), AttributeId.Value.uid(), null, QualifiedName.NULL_VALUE));
        }
        List<MonitoredItemCreateRequest> MICR = new ArrayList<>();
        for (ReadValueId ID: rvIDs) {
            MICR.add(new MonitoredItemCreateRequest(ID, MonitoringMode.Reporting, parameters));
        }
        return MICR;
    }

    public static void main(String[] args) throws Exception {
        CompletableFuture<OpcUaClient> future = new CompletableFuture<>();
        SubscriptionClient c = new SubscriptionClient();
        OpcUaClient client = c.createClient();
        client.connect().get();
        c.createSubscription(client, future);
    }
}

Async Read (1.000.000 per 60 secs)

public class MinimalClient {

    static int counter = 0;

    private OpcUaClient createClient() throws Exception {
        EndpointDescription[] endpoints;
        endpoints = UaTcpStackClient
                .getEndpoints("theServerAdress")
                .get();
        EndpointDescription endpoint = endpoints[0];
        OpcUaClientConfig config = OpcUaClientConfig.builder()
                .setApplicationName(LocalizedText.english("MinimalClient"))
                .setApplicationUri("theURI")
                .setCertificate(null)
                .setKeyPair(null)
                .setEndpoint(endpoint)
                .setMaxResponseMessageSize(uint(50000))
                .setIdentityProvider(new AnonymousProvider())
                .setRequestTimeout(uint(5000))
                .build();
        return new OpcUaClient(config);
    }

    public CompletableFuture<List<DataValue>> readValuesAsync (List<NodeId> nodes, OpcUaClient client) {
        return  client.readValues(10, TimestampsToReturn.Neither, nodes);
    }

    public static void main(String[] args) throws Exception {

        CompletableFuture<OpcUaClient> future = new CompletableFuture<>();

        MinimalClient c = new MinimalClient();
        OpcUaClient client = c.createClient();
        List<String> ids = Files.readAllLines(Paths.get("C:\\Users\\user\\Downloads\\MiloTest\\src\\com\\company\\NodeIDs.txt"));
        List<NodeId> nodes = new ArrayList<NodeId>();

        for (String line: ids) {
            nodes.add(new NodeId(2, line.substring(7)));
        }

        client.connect().get();
        client.getAddressSpace();
	
        while (counter<=1000000) { //I know this is a weird way of measuring performance, this takes 											60 seconds
            long startTime = System.currentTimeMillis();
            c.readValuesAsync(nodes, client).thenAccept( dataValues -> {
                System.out.println(dataValues.get(4000));
                counter += 20000; //I'm reading 20000 tags per read
                future.complete(client);
            }).get();
            long endTime = System.currentTimeMillis();
            long elapsedTime = endTime - startTime;
            System.out.println("ASYNCHRONOUS:    " + elapsedTime);
        }
    }
}

I'm excited to hear from you!

1 REPLY 1

New Contributor

when am using Publish/Subscribe since am having multiple tags am not able to makeout which data belongs to which tag.also the time stamp sent is which format.

Value: DataValue{value=Variant{value=6}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=131771547482760936, javaDate=Fri Jul 27 14:15:48 IST 2018}, serverTime=DateTime{utcTime=131771547482760936, javaDate=Fri Jul 27 14:15:48 IST 2018}}

while using the Async read code.Am able to make out to which tag data belongs to but am not getting the timestamp.

[DataValue{value=Variant{value=2}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601},

serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}},

DataValue{value=Variant{value=15}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601},

serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}},

DataValue{value=Variant{value=9}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601},

serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}}]

Any idea on why am facing this issue!!

,

I am trying to run the above code am getting data successfully but in Publish/Subscribe code i have defined multiple node id but when the data comes am not able to make out to which node id the data belongs to.

Value: DataValue{value=Variant{value=1}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=131771534829970042, javaDate=Fri Jul 27 13:54:42 IST 2018}, serverTime=DateTime{utcTime=131771534829970042, javaDate=Fri Jul 27 13:54:42 IST 2018}}

for the Async Read am not getting the timestamp

[DataValue{value=Variant{value=5}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601},

serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}}, DataValue{value=Variant{value=13}, status=StatusCode{name=Good, value=0x00000000, quality=good},

sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}, serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}},

DataValue{value=Variant{value=10}, status=StatusCode{name=Good, value=0x00000000, quality=good}, sourceTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601},

serverTime=DateTime{utcTime=0, javaDate=Mon Jan 01 05:30:00 IST 1601}}]

Any idea why am facing this issue?

; ;