Support Questions

Find answers, ask questions, and share your expertise

OPC UA Client performance with Eclipse Milo

avatar
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

avatar
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?