Janus Web Server performance: Difference between revisions

From m204wiki
Jump to navigation Jump to search
mNo edit summary
m (→‎Janus Web Server and RACF validation: add section re chunked encoding)
 
(3 intermediate revisions by 2 users not shown)
Line 508: Line 508:
passed when invoking the Online load module.
passed when invoking the Online load module.
The bits in <var>WEBAUDIT</var> are:
The bits in <var>WEBAUDIT</var> are:
<table>
<table class="thJustBold">
<tr><th>X'01'
<tr><th>X'01'
</th><td>Allow <var>NOAUDIT</var> and <var>NOAUDITW</var> keywords on <var>MSGCTL</var> command. A <code>MSGCTL msg_no NOADUT</code> would prevent ''msg_no'' from ever going to the audit trail, and a <code>MSGCTL msg_no NOAUDITW</code> would prevent ''msg_no'' from going to the audit trail if issued on a <var class="product">Janus Web Server</var> thread.
</th><td>Allow <var>NOAUDIT</var> and <var>NOAUDITW</var> keywords on <var>MSGCTL</var> command. A <code>MSGCTL msg_no NOADUT</code> would prevent ''msg_no'' from ever going to the audit trail, and a <code>MSGCTL msg_no NOAUDITW</code> would prevent ''msg_no'' from going to the audit trail if issued on a <var class="product">Janus Web Server</var> thread.
</td></tr>
</td></tr>
<tr><th>X'02'
<tr><th>X'02'
</th><td>Suppress APSY load since-last statistics for <var class="product">Janus Web Server</var> threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the <var>EVAL</var> since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
</th><td>Suppress APSY load since-last statistics for <var class="product">Janus Web Server</var> threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the <var>EVAL</var> since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
</td></tr>
</td></tr>
<tr><th>X'04'
<tr><th>X'04'
</th><td>Suppress APSY load since-last statistics for all threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the <var>EVAL</var> since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
</th><td>Suppress APSY load since-last statistics for all threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the <var>EVAL</var> since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
</td></tr>
</td></tr>
<tr><th>X'08'
<tr><th>X'08'
</th><td>Suppress <code>NO USERID</code> logout messages (M204.0353) for <var class="product">Janus Web Server</var> threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.
</th><td>Suppress <code>NO USERID</code> logout messages (M204.0353) for <var class="product">Janus Web Server</var> threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.
</td></tr>
</td></tr>
<tr><th>X'10'
<tr><th>X'10'
</th><td>Suppress <code>NO USERID</code> logout messages (M204.0353) for all threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.
</th><td>Suppress <code>NO USERID</code> logout messages (M204.0353) for all threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.
Line 530: Line 534:
It is '''not''', however a new capability or one that is only
It is '''not''', however a new capability or one that is only
available to <var class="product">Janus Web Server</var> customers.
available to <var class="product">Janus Web Server</var> customers.
Even without <var class="product">Janus Web Server</var>, it is possible to issue a <var>MSGCTL</var> command for
Even without <var class="product">Janus Web Server</var>, it is possible to issue a <var>MSGCTL</var> command for any message with the <var>AUDITRK</var> parameter.
any message with the <var>AUDITRK</var> parameter.
It is then possible to suppress <var>RK</var> messages from going to the audit
It is then possible to suppress <var>RK</var> messages from going to the audit
trail by making sure the X'20' bit is not set in SYSOPT.
trail by making sure the X'20' bit is not set in SYSOPT.
Line 544: Line 547:
for <var class="product">Janus Web Server</var> or other threads.
for <var class="product">Janus Web Server</var> or other threads.
Some good candidates for <var>MSGCTL NOAUDIT</var> or <var>NOAUDITW</var> are:
Some good candidates for <var>MSGCTL NOAUDIT</var> or <var>NOAUDITW</var> are:
<table>
<table class="thJustBold">
<tr><th>M204.0099 </th>
<tr><th>M204.0099 </th>
<td>MINIMUM SERVSIZE FOR THESE TABLES = ... </td></tr>
<td>MINIMUM SERVSIZE FOR THESE TABLES = ... </td></tr>
<tr><th>M204.0131 </th>
<tr><th>M204.0131 </th>
<td>(Checkpoint completed or timed out messages) </td></tr>
<td>(Checkpoint completed or timed out messages) </td></tr>
<tr><th>M204.0353 </th>
<tr><th>M204.0353 </th>
<td>(Login/logout message that is essentially a shortened
<td>(Login/logout message that is essentially a shortened
version of M204.0352 that also gets logged to the journal) </td></tr>
version of M204.0352 that also gets logged to the journal) </td></tr>
<tr><th>M204.0608 </th>
<tr><th>M204.0608 </th>
<td>FILE CLOSED: ... </td></tr>
<td>FILE CLOSED: ... </td></tr>
<tr><th>M204.0619 </th>
<tr><th>M204.0619 </th>
<td>GROUP FILE OPENED: ... </td></tr>
<td>GROUP FILE OPENED: ... </td></tr>
<tr><th>M204.0620 </th>
<tr><th>M204.0620 </th>
<td>FILE file OPENED (-- NO UPDATES ALLOWED) </td></tr>
<td>FILE file OPENED (-- NO UPDATES ALLOWED) </td></tr>
<tr><th>M204.0621 </th>
<tr><th>M204.0621 </th>
<td>(Informational message indicating recovery status of file being opened) </td></tr>
<td>(Informational message indicating recovery status of file being opened) </td></tr>
<tr><th>M204.0622 </th>
<tr><th>M204.0622 </th>
<td>(Informational message indicating the last update
<td>(Informational message indicating the last update
applied by the last roll-forward for a file being opened) </td></tr>
applied by the last roll-forward for a file being opened) </td></tr>
<tr><th>M204.0821 </th>
<tr><th>M204.0821 </th>
<td>GROUP FILE CLOSED: ... </td></tr>
<td>GROUP FILE CLOSED: ... </td></tr>
<tr><th>M204.0858 </th>
<tr><th>M204.0858 </th>
<td>GROUP group OPENED (-- NO UPDATES ALLOWED) </td></tr>
<td>GROUP group OPENED (-- NO UPDATES ALLOWED) </td></tr>
<tr><th>M204.1203 </th>
<tr><th>M204.1203 </th>
<td>FILE file WAS LAST UPDATED ON ...
<td>FILE file WAS LAST UPDATED ON ... </td></tr>
 
<tr><th>M204.1238 </th>
<tr><th>M204.1238 </th>
<td>(Informational message indicating the time the file was last recovered.) </td></tr>
<td>(Informational message indicating the time the file was last recovered.) </td></tr>
Line 653: Line 667:
the RACF call load for login-protected web pages can get very high.
the RACF call load for login-protected web pages can get very high.
Since these calls often involve synchronous I/Os that stop the <var class="product">Model 204</var>
Since these calls often involve synchronous I/Os that stop the <var class="product">Model 204</var>
main task, they are generally not very good for <var class="product">Model 204</var> performance.
maintask, they are generally not very good for <var class="product">Model 204</var> performance.
However, if you set the <var>[[WEBOPT parameter|WEBOPT]]</var> system parameter to <code>X'01'</code>,
However, if you set the <var>[[WEBOPT parameter|WEBOPT]]</var> system parameter to <code>X'01'</code>,
these calls are done in a subtask,
these calls are done in a subtask,
Line 660: Line 674:
The <var>WEBOPT</var> parameter is a standard <var class="product">Model 204</var> bitmask-type parameter.
The <var>WEBOPT</var> parameter is a standard <var class="product">Model 204</var> bitmask-type parameter.
The <code>X'01'</code> setting causes RACF calls to be performed in a special RACF subtask.
The <code>X'01'</code> setting causes RACF calls to be performed in a special RACF subtask.
 
==Janus Web Server and chunked encoding==
Janus Web support for HTTP 1.1 chunked encoding is available. As of Model&nbsp;204 version 7.6, the Janus Web Server handles <i>inbound</i> chunked HTTP requests. It does not send chunked output, because it always knows the exact length of the entire response.
 
For more information about chunked encoding, see http://en.wikipedia.org/wiki/Chunked_transfer_encoding.
 
==Keep-Alive support==
==Keep-Alive support==
<var class="product">Sirius Mods</var> version 6.8 introduced the <var class="product">Janus Web Server</var> port definition
<var class="product">Sirius Mods</var> version 6.8 introduced the <var class="product">Janus Web Server</var> port definition
parameter <var>[[KEEPALIVE]]</var>, which
parameter <var>[[KEEPALIVE (JANUS DEFINE parameter)|KEEPALIVE]]</var>, which
tells <var class="product">Janus Web Server</var> to keep an HTTP connection open for a certain number of
tells <var class="product">Janus Web Server</var> to keep an HTTP connection open for a certain number of
seconds to allow a client (often a browser) to send another request on
seconds to allow a client (often a browser) to send another request on
Line 708: Line 727:
This means that it is quite conceivable that a port might have many more
This means that it is quite conceivable that a port might have many more
connections held open at a time then there are sdaemon threads in the Online.
connections held open at a time then there are sdaemon threads in the Online.
Because of this, the former restriction that the thread limit for a <var>[[JANUS DEFINE#type|WEBSERV]]</var>
Because of this, the former restriction that the thread limit for a <var>[[JANUS DEFINE#type|WEBSERV]]</var> port could not exceed that number of sdaemon threads in an Online is
port could not exceed that number of sdaemon threads in an Online is
dropped as of <var class="product">Sirius Mods</var> version 6.8. </li>
dropped as of <var class="product">Sirius Mods</var> version 6.8.
 
<li>The keep-alive facility only preserves a TCP/IP
<li>The keep-alive facility only preserves a TCP/IP connection.
connection.
It does not preserve any application context.
It does not preserve any application context.
Other mechanisms, such as persistent session support via <var>[[$Web_Form_Done]]</var> or
Other mechanisms, such as persistent session support via <var>[[$Web_Form_Done]]</var> or
Line 718: Line 736:
there is a need to maintain application context between HTTP requests.
there is a need to maintain application context between HTTP requests.
However, there is no reason that keep-alives couldn't be used to improve
However, there is no reason that keep-alives couldn't be used to improve
the performance of web applications that maintain context between requests.
the performance of web applications that maintain context between requests. </li>
 
<li>While the keep-alive mechanism is useful for browser-to-web server requests,
<li>While the keep-alive mechanism is useful for browser-to-web server requests,
especially when embedded content such as style sheets or images are served from
especially when embedded content such as style sheets or images are served from
Line 725: Line 744:
In an environment where one server is sending requests to another, there
In an environment where one server is sending requests to another, there
could be a steady stream of requests from one server, and so one IP address,
could be a steady stream of requests from one server, and so one IP address,
to another.
to another. In such an environment, keep-alives could be a huge win &mdash; a single
In such an environment, keep-alives could be a huge win &mdash; a single
or a handful of TCP/IP connections could be used to service all the requests
or a handful of TCP/IP connections could be used to service all the requests
between the servers, eliminating thousands of server-to-server connection
between the servers, eliminating thousands of server-to-server connection establishments.
establishments.
<p>
<p>
Unfortunately, taking advantage of this is dependent on the ability of
Unfortunately, taking advantage of this is dependent on the ability of
Line 737: Line 754:
of keep-alives might be significantly reduced.
of keep-alives might be significantly reduced.
Since a given thread might never issue more than a single HTTP request,
Since a given thread might never issue more than a single HTTP request,
and since it could not use another thread's connection, each HTTP request would end up being a new TCP/IP connection.  </p>
and since it could not use another thread's connection, each HTTP request would end up being a new TCP/IP connection.  </p> </li>
 
<li>Because the potential benefits of using keep-alives in a server-to-server
<li>Because the potential benefits of using keep-alives in a server-to-server
application are so great, it is worth investigating the extent to which
application are so great, it is worth investigating the extent to which
any server that communicates with a <var class="product">Janus Web Server</var> can take advantage of keep-alives.
any server that communicates with a <var class="product">Janus Web Server</var> can take advantage of keep-alives. If both sides of the server-to-server application are <var class="product">Model 204</var>, then the use of the <var>KEEPALIVE</var> setting on a <var class="product">[[Janus Sockets]]</var> port is likely to provide
If both sides of the server-to-server application are <var class="product">Model 204</var>, then the
tremendous benefit &mdash; <var class="product">Janus Sockets</var> client requests easily share connections to the same web server. </li>
use of the <var>KEEPALIVE</var> setting on a <var class="product">[[Janus Sockets]]</var> port is likely to provide
 
tremendous benefit &mdash; <var class="product">Janus Sockets</var> client requests easily share connections
to the same web server.
<li>The lack of support for keep-alives in <var class="product">Janus Web Server</var> before <var class="product">Sirius Mods</var> version 6.8 was
<li>The lack of support for keep-alives in <var class="product">Janus Web Server</var> before <var class="product">Sirius Mods</var> version 6.8 was
probably one of the biggest stumbling blocks preventing <var class="product">Janus Web Server</var> from reporting
probably one of the biggest stumbling blocks preventing <var class="product">Janus Web Server</var> from reporting that it is an
that it is an
HTTP 1.1 web server &mdash; HTTP 1.1 web servers are expected to support keep-alives.
HTTP 1.1 web server &mdash; HTTP 1.1 web servers are expected to support
keep-alives.
With this support in place, the <var>[[HTTPVERSION]]</var> port definition parameter
With this support in place, the <var>[[HTTPVERSION]]</var> port definition parameter
can probably be safely set to <code>1.1</code>, enabling <var class="product">Janus Web Server</var> applications to
can probably be safely set to <code>1.1</code>, enabling <var class="product">Janus Web Server</var> applications to take advantage of other HTTP 1.1 features. </li>
take advantage of other HTTP 1.1 features.
</ul>
</ul>


[[Category:Janus Web Server]]
[[Category:Janus Web Server]]

Latest revision as of 23:05, 8 April 2016

Janus Web Server and APSY subsystems

Janus Web Server makes it easy to write "quick-and-dirty" applications. It is simple to specify a JANUS WEB ON rule to open a set of files associated with a URL with appropriate privileges and then INCLUDE a procedure that contains the User Language code to perform application processing. Unfortunately, an INCLUDE'd procedure is compiled every time it is invoked and the Model 204 compiler (like most compilers) is not written for efficiency so can incur a tremendous overhead. Because of this, frequently invoked Janus Web Server applications, just as frequently invoked 3270 applications, should be implemented as pre-compiled APSY procedures.

The are some considerations for implementing Janus Web Server applications as pre-compiled APSY procedures that are different from considerations for 3270 applications. Most of these arise from the fact that Janus Web Server applications are context-less, that is start from "scratch" with each page request. What this means from an APSY perspective is that for URL or page requests to use pre-compiled APSY procedures, each URL must enter and exit the APSY subsystem for each request. This is different from 3270 applications where users enter a subsystem and then stay inside the subsystem for long periods of time, sometimes the entire work day. This means that while the overhead of entering and leaving a subsystem is of little concern with 3270 applications, it must be considered carefully for Janus Web Server applications, since this overhead can overwhelm or at least significantly diminish the benefit of using a pre-compiled APSY procedure.

Overhead of entering/exiting APSY subsystem

The first factor to consider is the Model 204 internal overhead in entering a subsystem. Fortunately, this overhead is generally quite low and can, for most purpose, be ignored. Three slight exceptions to this are:

  • Entering an APSY subsystem causes the logical (not physical) opening of all required subsystem files and/or groups. Similarly, exiting the subsystem causes the closing of these same files and/or groups.

    Because, APSY holds down enqueues on required files and/or groups, the overhead associated with each open and close is fairly small. In fact, the greatest overhead for these opens and closes is logging the file opening and closing messages to the journal. This overhead can be greatly reduced by using the WEBAUDIT system parameter and the MSGCTL NOAUDIT or NOAUDITW settings, as documented below in "Janus Web Server audit trail reduction".

    By eliminating the logging of file open and close messages to the journal, the per-file/group overhead of entering and exiting a subsystem can be reduced to a point where it is virtually irrelevant, unless a subsystem has a tremendous number of required files or groups. This suggests that it is a good idea to try to keep to a reasonable number the quantity of required files or groups in a subsystem being used for Janus Web Server applications. One way of accomplishing this is by separating portions of Janus Web Server applications into different APSY subsystems based on the files or groups they require. Procedures that require access to the same set of files or groups can be placed into a subsystem that only opens those files or groups upon entry.

  • The names of active subsystems are linearly scanned every time a subsystem is invoked. This linear scan can become significant if the number of APSY subsystems becomes quite large (greater than 500, as a rough rule of thumb).

    It might be tempting when writing Janus Web Server applications to have one subsystem per URL. While there is nothing wrong with this per se, it is important to keep the active subsystem scan in mind if one expects to end up with a very large number of these subsystems. The difficulty of providing consistent and/or meaningful names for all these subsystems, given the fact that subsystem names are limited to ten characters, likely precludes such a strategy for large numbers of subsystems, anyway.

  • Before a non-public subsystem is entered, a CCASYS procedure is loaded and evaluated to determine which SCLASS, if any, the user belongs in. This CCASYS procedure performs at least one Find (against CCASYS, of course) and might process one or more records in a For Each Record loop.

    While this overhead is not huge, it is best to avoid it in Janus Web Server applications, if possible, by either of the following:

    • Place code that processes public URLs into a public subsystem, and place code that processes protected URLs into separate subsystems.
    • Protect URLs using JANUS WEB ALLOW rules instead of APSY security.

    Even if a non-public subsystem is unavoidable, some of the journal logging associated with the processing of the CCASYS procedures (APSY load since-last statistics, CCASYS OPENED/CLOSED messages) can be eliminated, as explained in "Janus Web Server audit trail reduction".

A more important source of overhead in entering and exiting an APSY subsystem is the cost of running the APSY login procedure. These login procedures are used for several reasons:

  • To set table sizes for the other procedures in the subsystem. Other user parameters might also be set in a login procedure, but table sizes are the most common thing for login procedures to set.
  • To set globals that are used for dummy string substitutions. This makes it possible to run the same procedures against production or test files by setting the globals to values appropriate for the environment.
  • To transfer to the first procedure that is to perform application processing. In a Janus Web Server application, this procedure might vary depending on the URL. In a 3270 application, the first procedure to be invoked in a subsystem is often a procedure that produces a menu.

Yet all these are purely infrastructure functions and have nothing to do with actual application processing. This is true for 3270 applications as well as Janus Web Server applications, but once again, the overheads tend to be a much more significant percentage of overall overhead for web applications, because they are incurred for each web page. For this reason, extra efforts should be made to avoid as much of this overhead as possible for Janus Web Server applications.

Avoiding table size and parameter setting

Updating user parameter values via RESET command is generally not a tremendously expensive operation. Setting table sizes can be somewhat more expensive, especially if running in an Online with different server sizes, where some of the table size changes can force a switch to a larger server.

For an APSY subsystem, however, the biggest cost of resetting parameter values or setting table sizes is that these operations cannot be performed inside pre-compiled procedures. This means that they incur not only the actual cost of the RESET or UTABLE operation, but also the cost of compiling a "stub" procedure that sets the communications global to the name of a pre-compiled procedure. For this reason, it is recommended that all parameter settings for a Janus Web Server subsystem be done outside the subsystem. There are several ways of accomplishing this, listed in order of desirability:

  • As much as possible, parameter values and table sizes should be set for the sdaemon threads in the CCAIN stream.

    This can be made slightly tricky by the fact that the sdaemon threads can be used for functions other than running Janus Web Server applications. These functions can include doing $Comm* processing or running as Janus Open Server or Janus Specialty Data Store threads.

    In a mostly Janus Web Server environment, there is little cost to oversizing user tables, so most or all applications can run without changing table sizes. That is because the main cost of having large default table sizes is the cost of server swapping large, but unused, tables for inactive threads. Janus Web Server's strategy of reusing the most recently used sdaemon thread keeps server swapping of inactive threads (or any threads for that matter) to a minimum, since in a busy system, an inactive thread is generally used for a new request before it is swapped out.

    This benefit of Janus Web Server's thread allocation strategy can be diminished by the use of a LOGCLOSET, especially a LOGCLOSET with a value greater than the typical server residency time of an inactive user.

  • Parameter values or table sizes that are specific to Janus Web Server applications, or to Janus Web Server applications running on a specific port, can be set in the CMD clause in a port definition.

    If only a few user parameters or a few table sizes (but not both) need to be set, the RESET or UTABLE command can simply be placed after the CMD keyword in the JANUS DEFINE command.

    If both user parameters and table sizes need to be set, or the RESET or UTABLE command would exceed 255 characters in length, port-wide settings could still be accomplished in a procedure that is invoked via an INCLUDE command in the CMD clause (along with an OPEN clause to indicate where the INCLUDE'd procedure resides). An INCLUDE'd procedure is somewhat more convenient and can be changed "on-the-fly" in emergencies, but it does incur slightly more overhead, as it involves a procedure dictionary lookup and reading of the procedure pages for every connection to the Janus Web Server port.

  • Parameter values or table sizes that are specific to particular URLs can be set in the CMD clause in the JANUS WEB ON rule for those URLs.

    Because JANUS WEB ON rules allow multiple commands to be specified in a CMD clause, these commands can both reset user parameter values and set table sizes before invoking the application code. For example, this rule sets the QTBL length, changes MCPU and invokes the COMPLEXSYS subsystem:

    JANUS WEB WEBPORT ON /COMPLEX/* - CMD 'UTABLE LQTBL 16000' AND - 'RESET MCPU 10000' AND - 'COMPLEXSYS *'

    This is more efficient than putting the UTABLE and RESET commands inside of COMPLEXSYS, because it doesn't require the reading of a procedure containing these commands, and it doesn't force the compilation of a "stub" procedure to transfer to pre-compiled code. If there are too many parameters and table sizes to be set in the CMD clause, some of the benefits of this approach could still be achieved by putting an INCLUDE command in the CMD clause as in the following:

    JANUS WEB WEBPORT ON /COMPLEX/* - OPEN FILE COMPPROC - CMD 'INCLUDE COMPSET' AND - 'COMPLEXSYS *'

    However, the cost of an extra OPEN and the reading of the procedure dictionary might eat up most of the benefit of simply putting the RESET and UTABLE commands in the subsystem login procedure.

By using the described techniques, it should be possible to avoid the overhead of having a non-pre-compiled login procedure that is invoked for every page that is processed by an APSY subsystem. That is, for Janus Web Server APSY subsystems, the login procedure should be pre-compiled.

Avoiding setting dummy string globals

By avoiding the setting of user parameters and table sizes in an APSY login procedure, it is possible to avoid the use of a non-pre-compiled APSY login procedure. The question then arises: Is it possible to avoid the use of a login procedure altogether?

An apparent roadblock to avoiding a login procedure is the use of dummy string file and group names in file/group related statements such as Find, Store, and Frn. For these statements to compile correctly, globals must be set on the thread compiling the procedure. While it is theoretically possible to force compilation of procedures "ahead of time" on a thread where the appropriate globals are set and so avoid setting the globals for all threads, this is generally difficult to manage, especially in multiple SCLASS subsystems where each procedure would have to be compiled once for each SCLASS.

Because of this, most subsystems are written so that the dummy string globals are set in the login procedure for every user that enters the subsystem. Outside of the overhead of setting these globals, fairly minor though it may be, every time a user enters the subsystem (whether or not the user will actually compile anything), this technique has the unfortunate side-effect of requiring a login procedure and therefore an extra APSY load and compilation, since the globals must be set before the application procedures containing the dummy strings are compiled.

The $functions $Setg_Sys and $Setg_Subsys were written largely to get around these problems. These $functions make it possible to set subsystem-wide or system-wide globals that are returned by $Getg or are used in dummy string substitution. Because the scope of these globals applies to all users or all users in a subsystem, there is no need to set corresponding globals in an APSY login procedure. Instead, the globals can either be set as part of the CCAIN input stream for User 0, or perhaps more logically, in subsystem initialization procedures.

For example, a subsystem initialization procedure might contain code like :

Begin %rc is float %name is string len 8 %name = 'ORD' with $substr($date(1), 1, 4) %rc = $setg_subsys('ORDYR', %name) %rc = $setg_subsys('CUST', 'PRODCUST') End

$Setg_Sys, $Setg_Subsys, and related functions $Delg_Sys, $Delg_Subsys, $Setg_Sys_List, and $Setg_Subsys_List are available to all Janus Web Server customers as well as to owners of some other Sirius Software products. These functions are useful to web and non-web applications.

Avoiding an APSY login procedure

If one can avoid the need to set parameters, table sizes, and global variables inside a subsystem, the only function that an APSY login procedure would serve would be to transfer to the procedure that is to perform application processing. Because this transfer involves an APSY load and procedure evaluation for every subsystem invocation (which means for every web page for a Janus Web Server subsystem), it would seem a good idea to avoid this processing if possible.

One simple way to accomplish this is by putting all the application processing into the login procedure. Unfortunately, this can get to be unwieldy as the number of web applications grows beyond a handful. Ultimately, the login procedure will have to transfer to other procedures to perform some processing, or new subsystems will have to be written to handle some URLs. Adding subsystems itself can become unwieldy because of the limitations in subsystem names: that is, the subsystem name must be a single name, ten characters or less, that is unique over the whole Online. For all these reasons, the way APSY is generally used with Janus Web Server is that a single subsystem will contain multiple pre-compiled procedures that perform related processing for URLs in the same path.

For example, this is a typical JANUS WEB ON rule that invokes a subsystem called MAINT:

JANUS WEB WEBPORT ON /MAINT/* CMD 'MAINT *'

Any URL that begins with /maint/ would invoke the MAINT subsystem with the rest of the URL as the command line variable for the subsystem. Suppose the subsystems communications global is NEXT, its command line variable is CMD, and the pre-compile prefix is MNTP. MAINT's login procedure could be as simple as

Begin %rc is float %rc = $setg('NEXT', 'MNTP-' with $getg('CMD')) End

With the invoking of this setup, a request for URL /maint/cust1 leads to the invoking of this login procedure, and then the immediate transfer to procedure MNTP-CUST1. While this procedure is certainly small and simple, there is a certain overhead associated with loading and evaluating even such a simple pre-compiled procedure that would be nice to avoid, if possible. For this reason, the WEBRUN pseudo-command was written,

The WEBRUN pseudo command avoids the necessity of a routing login procedure. Only available in JANUS WEB ON rules, WEBRUN can be used to invoke a specific procedure in a specific subsystem. For example, the previous JANUS WEB ON rule can be rewritten as

JANUS WEB WEBPORT ON /MAINT/* CMD 'WEBRUN MAINT MNTP-*'

With this rule, a request for URL maint/cust1 results in the subsystem procedure MNTP-CUST1 being run, completely bypassing the APSY login procedure. In fact, the APSY login procedure would not even have to exist! WEBRUN also provides the "bonus" of setting the communications global to the exit value before running the indicated procedure. This eliminates the need for a procedure invoked via WEBRUN to set the communications global, unless it wishes to transfer to another procedure.

Both WEBRUN and the simple-minded routing login procedure may seem a bit incomplete because they do not make sure that the target procedure actually exists, making it possible for a manually typed URL to cause routing to a non-existent procedure. This is not as big a problem as it might appear. If the subsystem has an error procedure, that procedure would be given control, and the error messages would be retrievable via $Fsterr and $Errmsg. If the subsystem has no error procedure, the subsystem would be exited, and the error could be trapped by a JANUS WEB ON NODONE rule. Failing that, the worst that would happen is that the user would see some "raw" Model 204 error messages: far from ideal, but not a reason to abandon the approach.

Janus Web Server and APSY miscellany

Many APSY subsystems are written so that the APSY is always exited through an "exit procedure." This exit procedure might save some environmental data in a work file or set table sizes to what they were before the subsystem was entered.

Because such an exit procedure would be run for every page handled by a Janus Web Server APSY application, it is best to avoid use of exit procedures for Janus Web Server applications. Certainly, there is no need to set parameters and table sizes back to their initial values, because this will be done anyway as part of normal Janus Web Server processing. Any user profile data that needs to be saved is best saved when it is changed rather than at subsystem exit.

This is different from a 3270 application where it is often simpler and more efficient to save user profile information on exit from a subsystem, since this exit will often happen more rarely than changes in the user profile information.

Most APSY subsystems have error procedures that receive control when an unusual error occurs inside the subsystem. Often these error procedures are more or less copies of error procedures in other subsystems. While there is nothing wrong with having an error procedure for a subsystem that handles Janus Web Server applications, they can also be avoided. What is required is that the AUTODONE feature of Janus Web Server be disabled, most simply by specifying NOAUTODONE on the port definition or, alternatively, in the JANUS WEB ON rule for the URLs that invoke a subsystem. This is useful even if there is a subsystem error procedure, because it deals with the case where a subsystem is not started or not available for some reason. With the use of a NOAUTODONE, subsystem errors or unavailability produce a fairly reasonable error screen generated automatically by Janus Web Server.

If more customized error pages are desired, these can be produced by specifying a JANUS WEB ON NODONE rule that indicates a page to be served or procedure to be run if an application did not do an explicit $Web_Done and NOAUTODONE is in effect. The JANUS WEB ON NODONE rule acts much as an error procedure that applies to all applications on a port, not just to a specific subsystem.

Janus Web Server audit trail reduction

The connectionless nature of the web protocols places some extraordinary demands on the Model 204 audit trail and/or journal relative to the demands of a comparable 3270 application for a comparable number of users and a comparable level of activity. These extraordinary demands include:

  • Logging of messages and statistics associated with Model 204 logons and logoffs

    This logging is much more frequent, since every page is basically a logon and logoff. This is true even for public URLs, which still result in a logon and logoff for the WEBUSER userid. Held logins resulting from the LOGCLOSET port definition parameter can reduce some of this traffic.

  • Logging of messages associated with resetting table sizes. With 3270 applications, users tend to enter a subsystem which sets the server table size and then stay in the subsystem for a fairly long period of time without resetting table sizes. This is not the case with Janus Web Server applications, where each page might require a table size reset if the default table sizes for sdaemons are not sufficient to run the Janus Web Server applications. Of course, this can be avoided if the default table sizes for the sdaemon threads are set high enough, but this can have its own negative impact on performance.
  • Logging of file open and close messages, especially those associated with entry and exit to and from an APSY subsystem

    When a user enters a subsystem, one or more file open messages are sent to the audit trail for each required subsystem file. Similarly a file close message is issued for each subsystem file when a user exits the subsystem.

    With 3270 applications, users tend to enter a subsystem and stay in the subsystem for a fairly long period of time so the ratio of file open and close messages to work done is usually relatively low. This is not the case with Janus Web Server applications, where each page might be associated with an entry to and exit from an APSY subsystem so that every request for a page might produce several file open and file close messages. Even for non-APSY subsystem related requests, at least one file open and close is likely to be performed as a result of the JANUS WEB ON rule associated with the request.

    Held logins resulting from the LOGCLOSET parameter on a port definition will not affect the number of file open and close messages associated with a web request since even for held logins, all files are closed at the end of a request.

  • Logging of APSY since-last statistics

    Since every web request associated with an APSY subsystem requires passing through one or more APSY procedures, each page will result in the logging of one or more APSY-load or compile since-last stats entries and one or more evaluation entries. Often 3270 applications will handle several screens in a single procedure, so only log one APSY-load or compilation and evaluation since-last stat entry for several screens.

  • Logging of web thread "terminal" output to the audit trail when $Web_Off is set

    The port default is NOAUDTERM, which suppresses this output (except for compiler messages, which should be useful).

All this extra logging associated with Janus Web Server applications has two negative impacts:

  1. It increases the quantity of data logged to the journal, which increases the journal I/O rates, increases the amount of disk space required for the journal, and can even increase Model 204 recovery times because of the extra time required to scan a larger journal.
  2. It makes problem analysis and diagnosis more difficult because of all the "noise" messages in the journal that make it more difficult to pick out the pertinent messages.

For these reasons it is important to at least consider taking some measures to reduce the quantity of useless or barely useful information logged to the audit trail when implementing Janus Web Server applications. There are a few simple things that can one can do:

  • Use the NOAUDTERM parameter unless there's a very good reason not to.

    Even then, specify NOAUDTERM on the port definition and specify AUDTERM only on the web rules where auditing of terminal output is required. Generally, any "terminal" message sent to the audit trail is also logged to the audit trail as a MS, AD or ER journal entry, so the logging of terminal output is pointless replication of these messages.

  • Make sure TRACE settings on the port definition are not copied from development and/or test Onlines into production.

    While having debugging turned on might be useful in development or test Onlines, it is generally unnecessary in production and simply produces volumes of useless data that get sent to the audit trail. Debugging can be turned on selectively and dynamically for an IP address with the JANUS TRACE command should debugging information need to be collected in a production region.

Beyond these simple things, Janus Web Server provides the WEBAUDIT system parameter to help further reduce the quantity of useless audit trail data associated with Janus Web Server applications. The WEBAUDIT parameter is a collection of bits that, when set, reduce the quantity of data sent to the Model 204 journal or make it possible to reduce this quantity. The default for WEBAUDIT is 0 and it can only be changed on the User 0 parameters in the CCAIN stream or the system parameters passed when invoking the Online load module. The bits in WEBAUDIT are:

X'01' Allow NOAUDIT and NOAUDITW keywords on MSGCTL command. A MSGCTL msg_no NOADUT would prevent msg_no from ever going to the audit trail, and a MSGCTL msg_no NOAUDITW would prevent msg_no from going to the audit trail if issued on a Janus Web Server thread.
X'02' Suppress APSY load since-last statistics for Janus Web Server threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the EVAL since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
X'04' Suppress APSY load since-last statistics for all threads. The resource usage associated with the APSY load such as CPU, DKPRs, disk I/O's, etc. will be included in the EVAL since-last statistics for the request. Since APSY load resource utilization is typically extremely minor relative to request evaluation, APSY load since-last statistics tend to be fairly useless.
X'08' Suppress NO USERID logout messages (M204.0353) for Janus Web Server threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.
X'10' Suppress NO USERID logout messages (M204.0353) for all threads. These messages are sometimes issued before a user logon even though there is no userid logged on the thread and so are singularly useless.

The MSGCTL NOAUDIT enhancement should be used with caution. Preventing certain messages from going to the journal could make diagnosing certain problems more difficult. It is not, however a new capability or one that is only available to Janus Web Server customers. Even without Janus Web Server, it is possible to issue a MSGCTL command for any message with the AUDITRK parameter. It is then possible to suppress RK messages from going to the audit trail by making sure the X'20' bit is not set in SYSOPT. The one unfortunate side-effect of this technique is that it also suppresses RK messages that one might actually want to go to the audit trail, but this can be overcome by MSGCTL'ing these messages to NOAUDITRK. Thanks to Warren Kring for this technique.

In any case, MSGCTL NOAUDIT and MSGCTL NOAUDITW provide a neater and more fine-grained way of reducing audit trail messages for Janus Web Server or other threads. Some good candidates for MSGCTL NOAUDIT or NOAUDITW are:

M204.0099 MINIMUM SERVSIZE FOR THESE TABLES = ...
M204.0131 (Checkpoint completed or timed out messages)
M204.0353 (Login/logout message that is essentially a shortened version of M204.0352 that also gets logged to the journal)
M204.0608 FILE CLOSED: ...
M204.0619 GROUP FILE OPENED: ...
M204.0620 FILE file OPENED (-- NO UPDATES ALLOWED)
M204.0621 (Informational message indicating recovery status of file being opened)
M204.0622 (Informational message indicating the last update applied by the last roll-forward for a file being opened)
M204.0821 GROUP FILE CLOSED: ...
M204.0858 GROUP group OPENED (-- NO UPDATES ALLOWED)
M204.1203 FILE file WAS LAST UPDATED ON ...
M204.1238 (Informational message indicating the time the file was last recovered.)

Janus Web Server and MP/204

Two of the biggest concerns in any MP/204 environment are maximizing the quantity of "offloadable," that is, non-maintask-only, code and minimizing resource conflicts. Janus Web Server has been highly optimized for the MP/204 environment.

First, all $Web functions except for $Web_Save_Recset and $Web_Restore_Recset (and its synonym $Web_Rest_Recset) are capable of running in an offload subtask. Furthermore, there is no resource enqueuing overhead associated with this capability.

Second, the Print statement has been enhanced so that it is capable of running in an offload subtask on a Janus Web Server thread. This latter is also accomplished with no resource enqueuing overhead, but it can be a little tricky in certain situations. This is because, the "parallel/serial" decision is made by Model 204 at the time a procedure is compiled. The Janus Web Server parallel Print statement feature makes its decision as to whether a Print statement should run in parallel based on the thread type. If a Print statement is compiled on a web thread, it is assumed that it can run in parallel, otherwise it is assumed to be maintask only. But a pre-compiled request that is to run mostly on web threads can be compiled on a non-web thread, and vice-versa. Even more complicated, a request or shared subroutine or INCLUDE'd procedure might run on both web threads and non-web threads.

The cost of compiling a Print statement as "parallel" when it is to be mostly executed on non-web threads is that the execution of the Print statement might cause a task switch from a subtask to the maintask. While for a single Print statement, this might not be significant, a series of Print statements in a loop (as often appears in BATCH2 jobs) could cause a huge amount of switching between maintask and offload subtask, and this could be a source of tremendous extra CPU utilization and/or execution time for a request.

On the other hand, the cost of compiling a Print statement as "serial" when it is to be mostly executed on web threads is that the loops containing the Print statement will run entirely on the maintask. Since most Janus Web Server applications are generally liberally sprinkled with Print statements, compiling Print statements as "serial" would ensure that most, if not all of a Janus Web Server application will be forced to the Model 204 maintask.

SIRIUS PRINT statement syntax

A SIRIUS PRINT compiler directive is provided with Janus Web Server to explicitly control the cases where a Print statement might be compiled on a non-web thread and executed on a web thread, or vice versa. The syntax of this statement is:

SIRIUS PRINT {MP | NOMP}

The SIRIUS PRINT statement is a compiler directive, so it does not cause quads to be compiled, and it is not affected by the looping or conditional statement structure of a program. For example, this Print statement will be compiled as being capable of being run in parallel simply because a SIRIUS PRINT MP preceded it in the compiled request:

If $web_ipaddr ne '' Then SIRIUS PRINT MP Else Print 'Report header' End If

A more correct way of structuring the above code might be

If $web_ipaddr eq '' Then SIRIUS PRINT NOMP Print 'Report header' SIRIUS PRINT MP End If

SIRIUS PRINT statements should not be required in anything but APSY pre-compiled requests since all other requests run on the thread on which they were compiled, in which case the Janus Web Server defaults should work fine.

Janus Web Server and RACF validation

In cases where Janus Web Server is deployed and RACF handles login validation, the RACF call load for login-protected web pages can get very high. Since these calls often involve synchronous I/Os that stop the Model 204 maintask, they are generally not very good for Model 204 performance. However, if you set the WEBOPT system parameter to X'01', these calls are done in a subtask, reducing their impact on Online performance dramatically.

The WEBOPT parameter is a standard Model 204 bitmask-type parameter. The X'01' setting causes RACF calls to be performed in a special RACF subtask.

Janus Web Server and chunked encoding

Janus Web support for HTTP 1.1 chunked encoding is available. As of Model 204 version 7.6, the Janus Web Server handles inbound chunked HTTP requests. It does not send chunked output, because it always knows the exact length of the entire response.

For more information about chunked encoding, see http://en.wikipedia.org/wiki/Chunked_transfer_encoding.

Keep-Alive support

Sirius Mods version 6.8 introduced the Janus Web Server port definition parameter KEEPALIVE, which tells Janus Web Server to keep an HTTP connection open for a certain number of seconds to allow a client (often a browser) to send another request on the same connection. This can reduce network traffic and, more significantly, HTTP request latency. Both of these benefits are magnified for SSL connections, where each HTTP request requires a TCP/IP and SSL connection-establishment handshake.

The KEEPALIVE parameter must be followed by a single number between 1 and 32767 that indicates the number of seconds a TCP/IP connection is to be held open after an HTTP request on that connection. For the connection to be held open, the client/browser must indicate that it supports HTTP keep-alives. Most modern browsers support and take advantage of keep-alives.

A keep-alive TCP/IP connection uses a Janus Web thread, so it is counted against both the maximum connections for a port and against a site's licensed thread limits. Because of the latter, it is probably impractical for a site with a low (10 thread) licensed Janus Web connection limit to take advantage of keep-alives unless Janus Web Server is used exclusively to communicate with a handful of servers (that act as clients to Janus Web Server). For sites with higher licensed limits, it's probably a good idea to increase the connection limit for any port that is to take advantage of keep-alives.

For a very rough estimate of how many more threads might be required on a port, simply multiply the maximum requests per second by the KEEPALIVE time. So, if at the busiest time of day, 10 requests come in per second on a port, and KEEPALIVE is set to 10, increasing the thread limit for the port by 10*10 or 100 should ensure that no requests are rejected because all available threads are held by keep-alive sessions. Of course, this is probably a gross overestimate of the real requirement, since one would assume that many of the requests would be coming from the same client, so would be transmitted over an existing keep-alive connection rather than sent over a new connection (otherwise, there'd be little benefit to using keep-alives).

Notes:

  • A keep-alive connection does not use a server or sdaemon thread while between requests. This means that it is quite conceivable that a port might have many more connections held open at a time then there are sdaemon threads in the Online. Because of this, the former restriction that the thread limit for a WEBSERV port could not exceed that number of sdaemon threads in an Online is dropped as of Sirius Mods version 6.8.
  • The keep-alive facility only preserves a TCP/IP connection. It does not preserve any application context. Other mechanisms, such as persistent session support via $Web_Form_Done or session context maintained via $Session* functions, are required if there is a need to maintain application context between HTTP requests. However, there is no reason that keep-alives couldn't be used to improve the performance of web applications that maintain context between requests.
  • While the keep-alive mechanism is useful for browser-to-web server requests, especially when embedded content such as style sheets or images are served from the same web server as the HTML pages, keep-alives can be even more useful for server-to-server HTTP requests. In an environment where one server is sending requests to another, there could be a steady stream of requests from one server, and so one IP address, to another. In such an environment, keep-alives could be a huge win — a single or a handful of TCP/IP connections could be used to service all the requests between the servers, eliminating thousands of server-to-server connection establishments.

    Unfortunately, taking advantage of this is dependent on the ability of threads on the server to act as a client to reuse other threads' TCP/IP connections. That is, a server typically has many threads running at a time. If these threads cannot reuse each other's TCP/IP connections, then the benefit of keep-alives might be significantly reduced. Since a given thread might never issue more than a single HTTP request, and since it could not use another thread's connection, each HTTP request would end up being a new TCP/IP connection.

  • Because the potential benefits of using keep-alives in a server-to-server application are so great, it is worth investigating the extent to which any server that communicates with a Janus Web Server can take advantage of keep-alives. If both sides of the server-to-server application are Model 204, then the use of the KEEPALIVE setting on a Janus Sockets port is likely to provide tremendous benefit — Janus Sockets client requests easily share connections to the same web server.
  • The lack of support for keep-alives in Janus Web Server before Sirius Mods version 6.8 was probably one of the biggest stumbling blocks preventing Janus Web Server from reporting that it is an HTTP 1.1 web server — HTTP 1.1 web servers are expected to support keep-alives. With this support in place, the HTTPVERSION port definition parameter can probably be safely set to 1.1, enabling Janus Web Server applications to take advantage of other HTTP 1.1 features.