Introduction
These days, I nearly always deploy ORDS in Standalone mode. Standalone mode allows you to run ORDS without deploying it within a container like Tomcat or Weblogic, thus simplifying your technology stack. Oracle fully supports ORDS running in standalone mode. This is possible because ORDS comes bundled with its own HTTP server, Jetty.
Given that you are no longer deploying ORDS in a container, there are a few things you need to do to make sure you obtain comparable results. In this post, I will review the steps I typically take when configuring a new ORDS Server running in Standalone mode.
Prerequisites
Set Environment Variables
When I work with ORDS on the command line, I typically set the following environment variables for my user profile. These cut down on typing and provide a consistent way to access the ORDS binary and config files.
# Set a varibale to the Home Directory for ORDS.
# You should see files like license.txt and index.html in this folder.
# This is also where the bin folder is located.
export ORDS_HOME=/opt/oracle/ords/
# Set a variable pointing to your ORDS Config files.
export ORDS_CONFIG=/etc/ords/config
# Add the ORDS binary to your Path.
export PATH=${ORDS_HOME}/bin:${PATH}
Enable Access Logs
Access logs are an essential part of securing your system and can also be helpful when troubleshooting issues.
You can enable access logs by running the following command:
ords --config $ORDS_CONFIG config set standalone.access.log /var/log/ords
ORDS: Release 23.2 Production on Mon Oct 02 22:28:36 2023
Copyright (c) 2010, 2023, Oracle.
Configuration:
/var/log/ords
The global setting named: standalone.access.log was set to: /var/log/ords
This command will add the following entry to the $ORDS_CONFIG/global/settings.xml
File: <entry key="standalone.access.log">/var/log/ords</entry>
. After you restart ORDS, access logs will created in the /var/log/orda
directory.
The resulting access log files will be named ords_YYYY_MM_DD.log
and will be rotated daily. The log format matches the NCSA Common Log Format.
10.0.0.79 - - [02/Oct/2023:17:35:47 +0000] "GET http://10.0.0.74:8080/ords/demo/test/ping HTTP/1.1" 200 94
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 475
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 42503
10.0.0.79 - - [02/Oct/2023:17:39:12 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 1517
10.0.0.79 - - [02/Oct/2023:17:39:14 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 102
10.0.0.79 - - [02/Oct/2023:17:39:50 +0000] "POST /ords/wwv_flow.ajax?p_context=app-builder/page-designer/9123695687705 HTTP/1.1" 200 780
10.0.0.79 - - [02/Oct/2023:17:40:46 +0000] "GET http://10.0.0.74:8080/ords/demo/test/ping HTTP/1.1" 200 94
Enable Response Compression
As I mentioned in my post, Building Performant REST Services with Oracle REST Data Services compressing response content can bring significant performance benefits. You can enable response compression by creating a file called jetty-compression.xml
in the folder $ORDS_CONFIG/global/standalone/etc
.
Example Content for the file jetty-compression.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="insertHandler">
<Arg>
<New id="GZipHanlder" class="org.eclipse.jetty.server.handler.gzip.GzipHandler">
<Set name="IncludedMimeTypes">
<Array type="java.lang.String">
<Item>text/html</Item>
<Item>text/xml</Item>
<Item>text/css</Item>
<Item>text/javascript</Item>
<Item>application/javascript</Item>
<Item>application/json</Item>
</Array>
</Set>
<Set name="minGzipSize">128</Set>
</New>
</Arg>
</Call>
</Configure>
IncludedMimeTypes
is used to control what types of files should be zipped.minGzipSize
is used to control how many bytes the response must be before it is zipped.
Assign JVM Memory
I advise that you explicitly set the size of the JVM ORDS runs to take advantage of the available memory on the ORDS Server. For example, if an ORDS server has 4 GB of RAM, I typically assign 2 GB to the ORDS JVM.
You can set the JVM size by populating the environment variable _JAVA_OPTIONS
in your ORDS startup script. The following example sets the JVM to 2 GB.
export _JAVA_OPTIONS="-Xms2048M -Xmx2048M"
ORDS Startup & Shutdown Scripts
You will need to create a startup and a shutdown script so you can set specific values before you start ORDS and so that you can run ORDS in the background.
I use an exact copy of Tim Hall's startup and shutdown scripts in this post. I am including them here for completeness. I have also changed the paths in these scripts to match those used in the rest of my post.
After creating the below scripts, you should make them executable as follows:
chmod u+x ~/scripts/*.sh
Startup Script
Create a file called ~/scripts/start_ords.sh with the following content (change paths as necessary):
#!/bin/bash
export PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
export JAVA_HOME=/u01/java/latest
export ORDS_HOME=/opt/oracle/ords/
export ORDS_CONFIG=/etc/ords/config
LOGFILE=/etc/ords/logs/ords-`date +"%Y""%m""%d"`.log
export _JAVA_OPTIONS="-Xms2048M -Xmx2048M"
nohup ${ORDS_HOME}/bin/ords --config ${ORDS_CONFIG} serve >> $LOGFILE 2>&1 &
echo "View log file with : tail -f $LOGFILE"
You can then start ORDS using the following command:
~/scripts/start_ords.sh
Shutdown Script
#!/bin/bash
export PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
kill `ps -ef | grep [o]rds.war | awk '{print $2}'`
You can then stop ORDS using the following command:
~/scripts/stop_ords.sh
Run ORDS as a Service
As an alternative to creating startup and shutdown scripts for ORDS, I often create a Linux Service to control ORDS startup and shutdown. The steps below were inspired by the blog post Run ORDS as a systemd Service by Christopher Ruepprich with changes to accommodate later versions of ORDS.
Steps
sudo vi /etc/systemd/system/ords.service
[Unit]
Description=ORDS Service
[Service]
SyslogIdentifier=ords
User=root
Restart=always
RestartSec=30
TimeoutStartSec=30
TimeoutStopSec=30
EnvironmentFile=/etc/ords/scripts/ords_exports.sh
ExecStart=/usr/bin/bash -c '${ORDS_HOME}/bin/ords --config ${ORDS_CONFIG} serve'
ExecStop=kill `ps -ef | grep [o]rds.war | awk '{print $2}'`
[Install]
WantedBy=multi-user.target
The file /etc/ords/scripts/ords_exports.sh looks like this:
PATH=/usr/sbin:/usr/local/bin:/usr/bin:/usr/local/sbin:$PATH
JAVA_HOME=/u01/java/latest
ORDS_HOME=/opt/oracle/ords
ORDS_CONFIG=/etc/ords/config
_JAVA_OPTIONS="-Xms1536M -Xmx1536M"
You can then start/stop ORDS with these commands:
sudo systemctl start ords
sudo systemctl stop ords
sudo systemctl restart ords
Finally, you can view the ORDS Log files as follows:
journalctl -f -u ords.service
Running ORDS Behind a Load Balancer
Usually, when I deploy ORDS, I deploy it behind a Load Balancer. The Load Balancer handles receiving HTTPS requests over SSL/TLS and routes requests to one or more ORDS servers (preferably more) running over HTTP. In this scenario, SSL Termination is happening in ORDS.
If you do terminate SSL at the Load Balancer, then there are two alternate configurations that you need to make. Configuration 1 works fine with an OCI Load Balancer but not other Load Balancers (e.g., HA Proxy). If Configuration 1 does not work for you, then try Configuration 2.
Configuration 1
# Allow access from example.com
ords --config $ORDS_CONFIG config set security.externalSessionTrustedOrigins https://example.com
# Verify HTTP Header Contains X-Forwarded-Proto: https
ords --config $ORDS_CONFIG config set security.httpsHeaderCheck "X-Forwarded-Proto: https"
<entry key="security.externalSessionTrustedOrigins">https://example.com</entry>
<entry key="security.httpsHeaderCheck">X-Forwarded-Proto: https</entry>
Configuration 2
# Allow access from example.com
ords --config $ORDS_CONFIG config set security.externalSessionTrustedOrigins https://example.com
# Force HTTPS
ords --config $ORDS_CONFIG config set security.forceHTTPS true
This will result in two new settings being added to $ORDS_CONFIG/global/settings.xml
.
<entry key="security.externalSessionTrustedOrigins">https://example.com</entry>
<entry key="security.forceHTTPS">true</entry>
Other Items
While not specific to running ORDS in Standalone mode, you should consider the following when firing up a new ORDS server.
Size the ORDS Connection Pool
ORDS uses a database connection pool to connect to the Oracle Database. You must size this correctly when configuring a new ORDS instance. I won't go into how to size the database pool in this post, but you should set the below settings based on your determination of the pool size:
jdbc.InitialLimit - Determines how many DB connections ORDS creates when you first start ORDS.
jdbc.MinLimit - Determines how many DB connections ORDS should keep open even when no activity exists.
jdbc.MaxLimit - Determines the maximum number of DB connections ORDS is allowed to create.
The following ORDS config commands set these values in the $ORDS_CONFIG/global/settings.xml
file.
ords --config $ORDS_CONFIG config set jdbc.InitialLimit 15
ords --config $ORDS_CONFIG config set jdbc.MinLimit 15
ords --config $ORDS_CONFIG config set jdbc.MaxLimit 25
Entries in $ORDS_CONFIG/global/settings.xml
<entry key="jdbc.InitialLimit">15</entry>
<entry key="jdbc.MaxLimit">25</entry>
<entry key="jdbc.MinLimit">15</entry>
Initial = Min = Max
Thanks to Connor McDonald for his comment on this post. In his comment, he refers to this very detailed presentation from Toon Koppelaars on connection pools and introduces an interesting approach to connection pool sizing. His comment in full (with some edits from Grammarly) is this:
The TL;DR rationale from the presentation for that recommendation is:
unused pool sessions are idle; they do nothing and consume minimal resources because the last thing pool-based apps do is free their resources when they give back a connection. If they don't, you have an app bug, not a connection pool config issue.
the max size setting (by definition) is what you are prepared to let your server handle without undue stress, so why would you pick a minimum/initial less than that? To do so means your apps incur the cost of creating a connection pseudo-randomly. That makes response times variable.
Enable Metadata Caching
When a client calls an ORDS REST Service, ORDS must first fetch the REST service definition from the ORDS Metadata and then execute the code contained in the REST service definition.
With Metadata Caching turned on, ORDS can get the REST Service definition from a cached version on the ORDS server, eliminating a round trip to the database.
You can enable Metadata Caching by adding the following properties to the $CONFIG_HOME/global/settings.xml
file.
ords --config $ORDS_CONFIG config set cache.metadata.enabled true
ords --config $ORDS_CONFIG config set cache.metadata.timeout 1m
Property | Description |
cache.metadata.enabled | Enable or disable metadata caching. |
cache.metadata.timeout | Specify how long the metadata remains in the cache before the cache is refreshed from ORDS Metadata in the database. |
Conclusion
Running ORDS in Standalone mode is fully supported by Oracle and allows you to remove Tomcat or Weblogic Containers from your ORDS stack. Following the suggestions in this post will enable you to achieve this while maintaining the features and performance these containers provided in the past.
Special Thanks
Thanks to Richard Soule for his comment regarding placing the log files on a separate disk partition. This way, if the logs fill the partition, ORDS will keep running.
Thanks to Jeff Smith for his comment on LinkedIn: "As for default memory allocation for the JVM, it depends on version of Java but basically comes down to the % of the physical memory on the device/machine."
Thanks to the suggestion from Alain LACOUR on LinkedIn: "Beyond creating start and stop scripts I would even recommend to run ORDS standalone as a service so it can start by itself and stop properly when the server is restarted for any reason."
๐ Read More
- ๐ ORDS Posts