https://issues.rudder.io/https://issues.rudder.io/themes/rudder7/favicon/favicon.ico?17096450182018-05-13T19:45:31ZIssue TrackerRudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915432018-05-13T19:45:31ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>Work in progess here: <a class="external" href="https://github.com/fanf/rudder/commit/77cc2de9f83e5c401c6d1fb5c87c896dcbd55d63">https://github.com/fanf/rudder/commit/77cc2de9f83e5c401c6d1fb5c87c896dcbd55d63</a></p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915442018-05-13T20:02:44ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>So, I explored two alternatives to see what could float.</p>
<p>1/ The first one is just a variation of JSON, and would allow to perhaps keep just one table. In place of JSON details, I used a new data type:</p>
<p>```<br />CREATE TYPE Compliance AS (<br /> ruleId text<br />, directiveId text<br />, complianceLevel int[]<br />);</p>
<p>CREATE TABLE nodeComplianceComposite (<br /> nodeId text NOT NULL CHECK (nodeId <> '')<br />, runTimestamp timestamp with time zone NOT NULL<br />, details Compliance[] NOT NULL<br />, PRIMARY KEY (nodeId, runTimestamp)<br />);<br />```<br />So here, we have an array of [ruleId, directiveId, [compliance level in an int[]] for details. It's much more compact than JSON, and the perf are in the domain of "not amazing but we will be able to do something". <br />But there is some caveat:</p>
<p>- JDBC does not know about array of custom type. So we need to expand the custom type (with `unnest`) to make data go throught JDBC driver. That's cumbersome and remove a lot of the appealing simplicity of the solution. <br />- I wasn't able to unnest a data with a custom data in it, meaning I was forced to used a int[] where a `ComplianceLevel` data type would have been better. <br />- Everything in SQL request, even with postgresql private functions, cries "don't do things like that". Any request grows quickly quite complicated, with a lot of subqueries.</p>
<p>2/ The second solution just used a ol'normalized table, with everything expanded:</p>
<p>```<br />CREATE TABLE nodecompliancedata (<br /> nodeId text NOT NULL CHECK (nodeId <> '')<br />, runTimestamp timestamp with time zone NOT NULL<br />, ruleId text NOT NULL CHECK (nodeId <> '')<br />, directiveId text NOT NULL CHECK (nodeId <> '')<br />, pending int DEFAULT 0<br />, success int DEFAULT 0<br />, repaired int DEFAULT 0<br />, error int DEFAULT 0<br />, unexpected int DEFAULT 0<br />, missing int DEFAULT 0<br />, noAnswer int DEFAULT 0<br />, notApplicable int DEFAULT 0<br />, reportsDisabled int DEFAULT 0<br />, compliant int DEFAULT 0<br />, auditNotApplicable int DEFAULT 0<br />, nonCompliant int DEFAULT 0<br />, auditError int DEFAULT 0<br />, badPolicyMode int DEFAULT 0<br />, PRIMARY KEY (nodeId, runTimestamp, ruleId, directiveId)<br />);<br />```</p>
<p>That not pretty, and any query/update is an horror in the number of fields. Plus, we are going to have a lot of lines - again. Update for one node compliance are slower, to. <br />On the bright side, that format is very well suited to be able to do the whole calculus postgre-side, and so we just get back in Rudder 30 Compliance level. That's quick, even in a slow network. And the whole query is quite fast (in the order of 100 ~ 400 ms for 100 runs on 100 nodes).</p>
<p>With that solution, we will also need for sure a dedicated table for that. We could keep the other (current) nodecompliance one to get detailled information of for a given node/run (ie to "zoom in" to understand some compliance reported in the aggregation graphe).</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915782018-05-14T08:37:09ZVincent MEMBRÉvme@rudder.io
<ul></ul><p>First remark, in both ideas, I think you can remove the directiveId since we only filter on Rules for compliance graph (this would reduce the amount of array to n Rules instead of n Rules * x directives)</p>
<p>In first solution, where we would replace current details with a more efficient one, you lose the details of the compliance which goes to component and value ( Rule > Directive > Component > value ), so i don't think we should choose that solution.</p>
<p>I would be ok to do this if this was a another column ( "details" would still be a huge json, and we would have a new column "summary" which contains only the compliance level with an array of type Compliance.</p>
<p>But as you said above, this solution has quite some drawbacks and may not be very interesting.</p>
<p>Second solution is fine to be, but I would not make a column for each compliance level but either an array of int like in solution one, or keeping a text containing the json array of compliance we could directly sent to the interface.</p>
<p>So i would say a table like this:</p>
<p>```<br />CREATE TABLE nodecompliancedata (<br />nodeId text NOT NULL CHECK (nodeId <> '')<br />, runTimestamp timestamp with time zone NOT NULL<br />, ruleId text NOT NULL CHECK (nodeId <> '')<br />, compliance int[] or text<br />, PRIMARY KEY (nodeId, runTimestamp, ruleId, directiveId)<br />);<br />```</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915792018-05-14T08:44:12ZVincent MEMBRÉvme@rudder.io
<ul></ul><p>One other question, should we have a batch that initialize the table by translating data from nodeCompliance to that new table</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915802018-05-14T09:01:56ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>Vincent MEMBRÉ wrote:</p>
<blockquote>
<p>First remark, in both ideas, I think you can remove the directiveId since we only filter on Rules for compliance graph (this would reduce the amount of array to n Rules instead of n Rules * x directives)</p>
</blockquote>
<p>I don't think so. Wanting a report on a specific directive seems something everybody would like to have, because for most people, especially with technique from technique editor, a unit of "work" is the directive. Rule is a little too big in most cases. <br />As you said, there is a tradeoff, and we are growing the table by a heuge factor. So I'm interested by feedbacks here (@Benoit ?)</p>
<blockquote>
<p>In first solution, where we would replace current details with a more efficient one, you lose the details of the compliance which goes to component and value ( Rule > Directive > Component > value ), so i don't think we should choose that solution.</p>
<p>I would be ok to do this if this was a another column ( "details" would still be a huge json, and we would have a new column "summary" which contains only the compliance level with an array of type Compliance.</p>
</blockquote>
<p>Do you see a reason to keep that level of details? In the general case and in reporting plugin case? For now, I'm not I know appart for the specific case where someone want to look at the details of a past compliance result (for debug most likely). But perhaps you see use case in reporting plugin ? Again, Benoit I welcome feedbacks here :)</p>
<blockquote>
<p>But as you said above, this solution has quite some drawbacks and may not be very interesting.</p>
<p>Second solution is fine to be, but I would not make a column for each compliance level but either an array of int like in solution one, or keeping a text containing the json array of compliance we could directly sent to the interface.</p>
<p>So i would say a table like this: [...]</p>
</blockquote>
<p>I did that at first (the array), but I thought that it will becomes quite hard to add/remove a field at some point without messing up things (quite easy to switch the order of elements for ex). <br />Moreover, it becomes harder to run aggregate function on the array. It may possible to do it (either via native postgres function or unnest(array)), but the it's just more tedious. <br />I also though to use a custom data type (as long as it's not in a array, it should be ok for jdbc driver).</p>
<p>But in fact, in each cases, I'm not sure of the gain compared to plain old standard columns. OK, that's a lot of columns, but internally that doesn't change anything for postgres (it's really just the same thing for custom data type, and almost the same thing for array, but with less optimisation because of the dynamic lenght that we don't even use). So why not sticking with SQL conventionnal way?</p>
<p>The text / json solution is not possible, because it forbids any postgres-side processing before at least 9.4, so not before centos8.</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=915952018-05-15T07:43:23ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>With some more discussion on the subject, we will:</p>
<p>- try to minimize change in 4.1 (of course)<br />- keep nodecompliance table as it is, with the same logic and all, <br />- create a new table, nodecomplianceSOMETHING (data? levels?) with the interesting data in it, <br />- create a dedicated cleaner for that table appart from the other compliance one, so that people are able to keep 100 days of nodecomplianceSOMETHING but only 1 of details.</p>
<p>For now, we don't aggregate anything.</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916142018-05-15T18:27:42ZNicolas CHARLESnicolas.charles@rudder.io
<ul></ul><p>I'm a bit concerned by the size of the entry you mention: 100-500kB per node per run<br />It seems too big; postgresql compress these entries (in the table size, it appears as TOAST, and should not be very big). If compression cannot really compress the compliance, then we have a real issue: this table is significantly larger than ruddersysevents (which is around 150kB/node/directive), and we should fix this</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916152018-05-15T19:03:22ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>Nicolas CHARLES wrote:</p>
<blockquote>
<p>I'm a bit concerned by the size of the entry you mention: 100-500kB per node per run<br />It seems too big; postgresql compress these entries (in the table size, it appears as TOAST, and should not be very big).</p>
</blockquote>
<p>It's not the size on disk, it's the size that goes throught the network and arrive as text to Rudder to be parsed as JSON. I don't know the size on disk (but we already know it's big).</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916162018-05-15T19:22:11ZNicolas CHARLESnicolas.charles@rudder.io
<ul></ul><p>François ARMAND wrote:</p>
<blockquote>
<p>Nicolas CHARLES wrote:</p>
<blockquote>
<p>I'm a bit concerned by the size of the entry you mention: 100-500kB per node per run<br />It seems too big; postgresql compress these entries (in the table size, it appears as TOAST, and should not be very big).</p>
</blockquote>
<p>It's not the size on disk, it's the size that goes throught the network and arrive as text to Rudder to be parsed as JSON. I don't know the size on disk (but we already know it's big).</p>
</blockquote>
<p>Ha, yes, the data over network is awfully large<br />poor man solution: we could reduce the text size of the json<br />Excerpt from an existing entry<br /><pre>
"rules":[
{
"ruleId":"hasPolicyServer-root",
"serial":13,
"compliance":{
"success":87.5,
"notApplicable":12.5
},
"numberReports":8,
"directives":[
{
"directiveId":"common-root",
"compliance":{
"success":87.5,
"notApplicable":12.5
},
"numberReports":8,
"components":[
{
"componentName":"Log system for reports",
"compliance":{
"success":100.0
},
"numberReports":1,
"values":[
{
"value":"None",
"compliance":{
"success":100.0
},
"numberReports":1,
"unexpanded":"None",
"messages":[
{
"message":"Logging system for report centralization is already correctly configured",
"type":"Success"
}
]
}
]
},
{
"componentName":"CRON Daemon",
"compliance":{
"success":100.0
},
"numberReports":1,
"values":[
{
"value":"None",
"compliance":{
"success":100.0
},
"numberReports":1,
"unexpanded":"None",
"messages":[
{
"message":"Cron daemon status was correct",
"type":"Success"
}
]
}
</pre><br />None of the keys in the json need to be so long, and we do not need spacing (well at least computer wouldn't need them) - i suspect they make up for more than 80% of the data sent</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916172018-05-15T20:09:10ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>For reference, on network compression for pgsql: <a class="external" href="https://stackoverflow.com/questions/38384731/efficiently-retrieving-large-data-objects-from-a-postgresql-database">https://stackoverflow.com/questions/38384731/efficiently-retrieving-large-data-objects-from-a-postgresql-database</a></p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916402018-05-16T13:03:04ZFrançois ARMANDfrancois.armand@rudder.io
<ul></ul><p>Some quantification of the table:</p>
<p>- (3 uuids + date + 14 int) * 20 runs by hours * 24 hours = 60kB per day. <br />- for 100 nodes * 15 rules with 10 directives = 900MB <br />- for 1 month = 26GB</p>
<p>If we aggregate by hour, with need ~1.3GB by month. And by day, 55MB per month.</p>
<p>If we had decided to not keep directive level (only rule granularity), all numbers would be divised by 10 (so 90MB per day for 100 nodes, 2.6GB for a month).</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916742018-05-17T20:10:27ZFrançois ARMANDfrancois.armand@rudder.io
<ul><li><strong>Status</strong> changed from <i>In progress</i> to <i>Pending technical review</i></li><li><strong>Assignee</strong> changed from <i>François ARMAND</i> to <i>Vincent MEMBRÉ</i></li><li><strong>Pull Request</strong> set to <i>https://github.com/Normation/rudder/pull/1934</i></li></ul><p>PR <a class="external" href="https://github.com/Normation/rudder/pull/1934">https://github.com/Normation/rudder/pull/1934</a></p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916882018-05-18T07:35:35ZRudder Quality Assistant
<ul><li><strong>Assignee</strong> changed from <i>Vincent MEMBRÉ</i> to <i>François ARMAND</i></li></ul> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=916892018-05-18T07:39:33ZFrançois ARMANDfrancois.armand@rudder.io
<ul><li><strong>Status</strong> changed from <i>Pending technical review</i> to <i>Pending release</i></li></ul><p>Applied in changeset <a class="changeset" title="Fixes #12621: Explore alternative format for compliance table" href="https://issues.rudder.io/projects/rudder/repository/rudder/revisions/beb105c9b4558002347a4326624caf02b8e20c85">rudder|beb105c9b4558002347a4326624caf02b8e20c85</a>.</p> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=927402018-05-29T08:16:07ZBenoît PECCATTEbenoit.peccatte@rudder.io
<ul><li><strong>Status</strong> changed from <i>Pending release</i> to <i>Released</i></li></ul><p>This bug has been fixed in Rudder 4.1.12, 4.2.6 and 4.3.1 which were released today.</p>
<ul>
<li>4.1.12: <a href="http://www.rudder-project.org/pipermail/rudder-announce/2018-May/000272.html" class="external">Announce</a> <a href="http://www.rudder-project.org/changelog-4.1#4.1.12" class="external">Changelog</a></li>
<li>4.2.6: <a href="http://www.rudder-project.org/pipermail/rudder-announce/2018-May/000273.html" class="external">Announce</a> <a href="http://www.rudder-project.org/changelog-4.2#4.2.6" class="external">Changelog</a></li>
<li>4.3.1: <a href="http://www.rudder-project.org/pipermail/rudder-announce/2018-May/000271.html" class="external">Announce</a> <a href="http://www.rudder-project.org/changelog-4.3#4.3.1" class="external">Changelog</a></li>
<li>Download: <a class="external" href="https://www.rudder-project.org/site/get-rudder/downloads/">https://www.rudder-project.org/site/get-rudder/downloads/</a></li>
</ul> Rudder - Architecture #12621: Explore alternative format for compliance tablehttps://issues.rudder.io/issues/12621?journal_id=1025222018-12-19T11:07:14ZNicolas CHARLESnicolas.charles@rudder.io
<ul><li><strong>Related to</strong> <i><a class="issue tracker-1 status-5 priority-16 priority-default closed parent" href="/issues/14007">Bug #14007</a>: Indexes on nodecompliancelevels table are not valid and table ArchivedReportsExecution is never used</i> added</li></ul>