| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="generator" content="Asciidoctor 2.0.26"> |
| <meta name="author" content="Jon Haddad"> |
| <title>cassandra-easy-stress</title> |
| <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> |
| <style> |
| /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ |
| /* Uncomment the following line when using as a custom stylesheet */ |
| /* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */ |
| html{font-family:sans-serif;-webkit-text-size-adjust:100%} |
| a{background:none} |
| a:focus{outline:thin dotted} |
| a:active,a:hover{outline:0} |
| h1{font-size:2em;margin:.67em 0} |
| b,strong{font-weight:bold} |
| abbr{font-size:.9em} |
| abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none} |
| dfn{font-style:italic} |
| hr{height:0} |
| mark{background:#ff0;color:#000} |
| code,kbd,pre,samp{font-family:monospace;font-size:1em} |
| pre{white-space:pre-wrap} |
| q{quotes:"\201C" "\201D" "\2018" "\2019"} |
| small{font-size:80%} |
| sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} |
| sup{top:-.5em} |
| sub{bottom:-.25em} |
| img{border:0} |
| svg:not(:root){overflow:hidden} |
| figure{margin:0} |
| audio,video{display:inline-block} |
| audio:not([controls]){display:none;height:0} |
| fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} |
| legend{border:0;padding:0} |
| button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} |
| button,input{line-height:normal} |
| button,select{text-transform:none} |
| button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} |
| button[disabled],html input[disabled]{cursor:default} |
| input[type=checkbox],input[type=radio]{padding:0} |
| button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} |
| textarea{overflow:auto;vertical-align:top} |
| table{border-collapse:collapse;border-spacing:0} |
| *,::before,::after{box-sizing:border-box} |
| html,body{font-size:100%} |
| body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} |
| a:hover{cursor:pointer} |
| img,object,embed{max-width:100%;height:auto} |
| object,embed{height:100%} |
| img{-ms-interpolation-mode:bicubic} |
| .left{float:left!important} |
| .right{float:right!important} |
| .text-left{text-align:left!important} |
| .text-right{text-align:right!important} |
| .text-center{text-align:center!important} |
| .text-justify{text-align:justify!important} |
| .hide{display:none} |
| img,object,svg{display:inline-block;vertical-align:middle} |
| textarea{height:auto;min-height:50px} |
| select{width:100%} |
| .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} |
| div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0} |
| a{color:#2156a5;text-decoration:underline;line-height:inherit} |
| a:hover,a:focus{color:#1d4b8f} |
| a img{border:0} |
| p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} |
| p aside{font-size:.875em;line-height:1.35;font-style:italic} |
| h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} |
| h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} |
| h1{font-size:2.125em} |
| h2{font-size:1.6875em} |
| h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} |
| h4,h5{font-size:1.125em} |
| h6{font-size:1em} |
| hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em} |
| em,i{font-style:italic;line-height:inherit} |
| strong,b{font-weight:bold;line-height:inherit} |
| small{font-size:60%;line-height:inherit} |
| code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} |
| ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} |
| ul,ol{margin-left:1.5em} |
| ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0} |
| ul.circle{list-style-type:circle} |
| ul.disc{list-style-type:disc} |
| ul.square{list-style-type:square} |
| ul.circle ul:not([class]),ul.disc ul:not([class]),ul.square ul:not([class]){list-style:inherit} |
| ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} |
| dl dt{margin-bottom:.3125em;font-weight:bold} |
| dl dd{margin-bottom:1.25em} |
| blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} |
| blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} |
| @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} |
| h1{font-size:2.75em} |
| h2{font-size:2.3125em} |
| h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} |
| h4{font-size:1.4375em}} |
| table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal} |
| table thead,table tfoot{background:#f7f8f7} |
| table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} |
| table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} |
| table tr.even,table tr.alt{background:#f8f8f7} |
| table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6} |
| h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} |
| h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} |
| .center{margin-left:auto;margin-right:auto} |
| .stretch{width:100%} |
| .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} |
| .clearfix::after,.float-group::after{clear:both} |
| :not(pre).nobreak{word-wrap:normal} |
| :not(pre).nowrap{white-space:nowrap} |
| :not(pre).pre-wrap{white-space:pre-wrap} |
| :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} |
| pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} |
| pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} |
| pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} |
| em em{font-style:normal} |
| strong strong{font-weight:400} |
| .keyseq{color:rgba(51,51,51,.8)} |
| kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} |
| .keyseq kbd:first-child{margin-left:0} |
| .keyseq kbd:last-child{margin-right:0} |
| .menuseq,.menuref{color:#000} |
| .menuseq b:not(.caret),.menuref{font-weight:inherit} |
| .menuseq{word-spacing:-.02em} |
| .menuseq b.caret{font-size:1.25em;line-height:.8} |
| .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} |
| b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} |
| b.button::before{content:"[";padding:0 3px 0 2px} |
| b.button::after{content:"]";padding:0 2px 0 3px} |
| p a>code:hover{color:rgba(0,0,0,.9)} |
| #header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} |
| #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} |
| #header::after,#content::after,#footnotes::after,#footer::after{clear:both} |
| #content{margin-top:1.25em} |
| #content::before{content:none} |
| #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} |
| #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} |
| #header>h1:only-child{border-bottom:1px solid #dddddf;padding-bottom:8px} |
| #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} |
| #header .details span:first-child{margin-left:-.125em} |
| #header .details span.email a{color:rgba(0,0,0,.85)} |
| #header .details br{display:none} |
| #header .details br+span::before{content:"\00a0\2013\00a0"} |
| #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} |
| #header .details br+span#revremark::before{content:"\00a0|\00a0"} |
| #header #revnumber{text-transform:capitalize} |
| #header #revnumber::after{content:"\00a0"} |
| #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} |
| #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} |
| #toc>ul{margin-left:.125em} |
| #toc ul.sectlevel0>li>a{font-style:italic} |
| #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} |
| #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} |
| #toc li{line-height:1.3334;margin-top:.3334em} |
| #toc a{text-decoration:none} |
| #toc a:active{text-decoration:underline} |
| #toctitle{color:#7a2518;font-size:1.2em} |
| @media screen and (min-width:768px){#toctitle{font-size:1.375em} |
| body.toc2{padding-left:15em;padding-right:0} |
| body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} |
| #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} |
| #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} |
| #toc.toc2>ul{font-size:.9em;margin-bottom:0} |
| #toc.toc2 ul ul{margin-left:0;padding-left:1em} |
| #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} |
| body.toc2.toc-right{padding-left:0;padding-right:15em} |
| body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} |
| @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} |
| #toc.toc2{width:20em} |
| #toc.toc2 #toctitle{font-size:1.375em} |
| #toc.toc2>ul{font-size:.95em} |
| #toc.toc2 ul ul{padding-left:1.25em} |
| body.toc2.toc-right{padding-left:0;padding-right:20em}} |
| #content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px} |
| #content #toc>:first-child{margin-top:0} |
| #content #toc>:last-child{margin-bottom:0} |
| #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em} |
| #footer-text{color:hsla(0,0%,100%,.8);line-height:1.44} |
| #content{margin-bottom:.625em} |
| .sect1{padding-bottom:.625em} |
| @media screen and (min-width:768px){#content{margin-bottom:1.25em} |
| .sect1{padding-bottom:1.25em}} |
| .sect1:last-child{padding-bottom:0} |
| .sect1+.sect1{border-top:1px solid #e7e7e9} |
| #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} |
| #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} |
| #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} |
| #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} |
| #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} |
| details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} |
| details{margin-left:1.25rem} |
| details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent} |
| details>summary::-webkit-details-marker{display:none} |
| details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)} |
| details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)} |
| details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem} |
| .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} |
| table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} |
| .paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} |
| .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} |
| .admonitionblock>table td.icon{text-align:center;width:80px} |
| .admonitionblock>table td.icon img{max-width:none} |
| .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} |
| .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere} |
| .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} |
| .exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px} |
| .sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px} |
| .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} |
| .exampleblock>.content>:first-child,.sidebarblock>.content>:first-child{margin-top:0} |
| .exampleblock>.content>:last-child,.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} |
| .literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em} |
| @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}} |
| @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}} |
| .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} |
| .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} |
| .listingblock>.content{position:relative} |
| .listingblock pre>code{display:block} |
| .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} |
| .listingblock:hover code[data-lang]::before{display:block} |
| .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} |
| .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} |
| .listingblock pre.highlightjs{padding:0} |
| .listingblock pre.highlightjs>code{padding:1em;border-radius:4px} |
| .listingblock pre.prettyprint{border-width:0} |
| .prettyprint{background:#f7f7f8} |
| pre.prettyprint .linenums{line-height:1.45;margin-left:2em} |
| pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0} |
| pre.prettyprint li code[data-lang]::before{opacity:1} |
| pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none} |
| table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none} |
| table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} |
| table.linenotable td.code{padding-left:.75em} |
| table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} |
| pre.pygments span.linenos{display:inline-block;margin-right:.75em} |
| .quoteblock{margin:0 1em 1.25em 1.5em;display:table} |
| .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} |
| .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} |
| .quoteblock blockquote{margin:0;padding:0;border:0} |
| .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} |
| .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} |
| .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} |
| .verseblock{margin:0 1em 1.25em} |
| .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} |
| .verseblock pre strong{font-weight:400} |
| .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} |
| .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} |
| .quoteblock .attribution br,.verseblock .attribution br{display:none} |
| .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} |
| .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} |
| .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} |
| .quoteblock.abstract{margin:0 1em 1.25em;display:block} |
| .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} |
| .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} |
| .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} |
| .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} |
| .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0} |
| p.tableblock:last-child{margin-bottom:0} |
| td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere} |
| td.tableblock>.content>:last-child{margin-bottom:-1.25em} |
| table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} |
| table.grid-all>*>tr>*{border-width:1px} |
| table.grid-cols>*>tr>*{border-width:0 1px} |
| table.grid-rows>*>tr>*{border-width:1px 0} |
| table.frame-all{border-width:1px} |
| table.frame-ends{border-width:1px 0} |
| table.frame-sides{border-width:0 1px} |
| table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0} |
| table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0} |
| table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0} |
| table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0} |
| table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7} |
| th.halign-left,td.halign-left{text-align:left} |
| th.halign-right,td.halign-right{text-align:right} |
| th.halign-center,td.halign-center{text-align:center} |
| th.valign-top,td.valign-top{vertical-align:top} |
| th.valign-bottom,td.valign-bottom{vertical-align:bottom} |
| th.valign-middle,td.valign-middle{vertical-align:middle} |
| table thead th,table tfoot th{font-weight:bold} |
| tbody tr th{background:#f7f8f7} |
| tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} |
| p.tableblock>code:only-child{background:none;padding:0} |
| p.tableblock{font-size:1em} |
| ol{margin-left:1.75em} |
| ul li ol{margin-left:1.5em} |
| dl dd{margin-left:1.125em} |
| dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} |
| li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} |
| ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} |
| ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} |
| ul.unstyled,ol.unstyled{margin-left:0} |
| li>p:empty:only-child::before{content:"";display:inline-block} |
| ul.checklist>li>p:first-child{margin-left:-1em} |
| ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} |
| ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em} |
| ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} |
| ul.inline>li{margin-left:1.25em} |
| .unstyled dl dt{font-weight:400;font-style:normal} |
| ol.arabic{list-style-type:decimal} |
| ol.decimal{list-style-type:decimal-leading-zero} |
| ol.loweralpha{list-style-type:lower-alpha} |
| ol.upperalpha{list-style-type:upper-alpha} |
| ol.lowerroman{list-style-type:lower-roman} |
| ol.upperroman{list-style-type:upper-roman} |
| ol.lowergreek{list-style-type:lower-greek} |
| .hdlist>table,.colist>table{border:0;background:none} |
| .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} |
| td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} |
| td.hdlist1{font-weight:bold;padding-bottom:1.25em} |
| td.hdlist2{word-wrap:anywhere} |
| .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} |
| .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} |
| .colist td:not([class]):first-child img{max-width:none} |
| .colist td:not([class]):last-child{padding:.25em 0} |
| .thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd} |
| .imageblock.left{margin:.25em .625em 1.25em 0} |
| .imageblock.right{margin:.25em 0 1.25em .625em} |
| .imageblock>.title{margin-bottom:0} |
| .imageblock.thumb,.imageblock.th{border-width:6px} |
| .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} |
| .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} |
| .image.left{margin-right:.625em} |
| .image.right{margin-left:.625em} |
| a.image{text-decoration:none;display:inline-block} |
| a.image object{pointer-events:none} |
| sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} |
| sup.footnote a,sup.footnoteref a{text-decoration:none} |
| sup.footnote a:active,sup.footnoteref a:active,#footnotes .footnote a:first-of-type:active{text-decoration:underline} |
| #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} |
| #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} |
| #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} |
| #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} |
| #footnotes .footnote:last-of-type{margin-bottom:0} |
| #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} |
| div.unbreakable{page-break-inside:avoid} |
| .big{font-size:larger} |
| .small{font-size:smaller} |
| .underline{text-decoration:underline} |
| .overline{text-decoration:overline} |
| .line-through{text-decoration:line-through} |
| .aqua{color:#00bfbf} |
| .aqua-background{background:#00fafa} |
| .black{color:#000} |
| .black-background{background:#000} |
| .blue{color:#0000bf} |
| .blue-background{background:#0000fa} |
| .fuchsia{color:#bf00bf} |
| .fuchsia-background{background:#fa00fa} |
| .gray{color:#606060} |
| .gray-background{background:#7d7d7d} |
| .green{color:#006000} |
| .green-background{background:#007d00} |
| .lime{color:#00bf00} |
| .lime-background{background:#00fa00} |
| .maroon{color:#600000} |
| .maroon-background{background:#7d0000} |
| .navy{color:#000060} |
| .navy-background{background:#00007d} |
| .olive{color:#606000} |
| .olive-background{background:#7d7d00} |
| .purple{color:#600060} |
| .purple-background{background:#7d007d} |
| .red{color:#bf0000} |
| .red-background{background:#fa0000} |
| .silver{color:#909090} |
| .silver-background{background:#bcbcbc} |
| .teal{color:#006060} |
| .teal-background{background:#007d7d} |
| .white{color:#bfbfbf} |
| .white-background{background:#fafafa} |
| .yellow{color:#bfbf00} |
| .yellow-background{background:#fafa00} |
| span.icon>.fa{cursor:default} |
| a span.icon>.fa{cursor:inherit} |
| .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} |
| .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} |
| .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} |
| .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} |
| .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} |
| .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} |
| .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} |
| .conum[data-value] *{color:#fff!important} |
| .conum[data-value]+b{display:none} |
| .conum[data-value]::after{content:attr(data-value)} |
| pre .conum[data-value]{position:relative;top:-.125em} |
| b.conum *{color:inherit!important} |
| .conum:not([data-value]):empty{display:none} |
| dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} |
| h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em} |
| p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} |
| p,blockquote,dt,td.content,td.hdlist1,span.alt,summary{font-size:1.0625rem} |
| p{margin-bottom:1.25rem} |
| .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} |
| .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc} |
| .print-only{display:none!important} |
| @page{margin:1.25cm .75cm} |
| @media print{*{box-shadow:none!important;text-shadow:none!important} |
| html{font-size:80%} |
| a{color:inherit!important;text-decoration:underline!important} |
| a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} |
| a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} |
| abbr[title]{border-bottom:1px dotted} |
| abbr[title]::after{content:" (" attr(title) ")"} |
| pre,blockquote,tr,img,object,svg{page-break-inside:avoid} |
| thead{display:table-header-group} |
| svg{max-width:100%} |
| p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} |
| h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} |
| #header,#content,#footnotes,#footer{max-width:none} |
| #toc,.sidebarblock,.exampleblock>.content{background:none!important} |
| #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} |
| body.book #header{text-align:center} |
| body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} |
| body.book #header .details{border:0!important;display:block;padding:0!important} |
| body.book #header .details span:first-child{margin-left:0!important} |
| body.book #header .details br{display:block} |
| body.book #header .details br+span::before{content:none!important} |
| body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} |
| body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} |
| .listingblock code[data-lang]::before{display:block} |
| #footer{padding:0 .9375em} |
| .hide-on-print{display:none!important} |
| .print-only{display:block!important} |
| .hide-for-print{display:none!important} |
| .show-for-print{display:inherit!important}} |
| @media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem} |
| .sect1{padding:0!important} |
| .sect1+.sect1{border:0} |
| #footer{background:none} |
| #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} |
| @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} |
| </style> |
| </head> |
| <body class="article toc2 toc-left"> |
| <div id="header"> |
| <h1>cassandra-easy-stress</h1> |
| <div class="details"> |
| <span id="author" class="author">Jon Haddad</span><br> |
| <span id="email" class="email"><a href="mailto:jon@rustyrazorblade.com">jon@rustyrazorblade.com</a></span><br> |
| <span id="revdate">Anthony Grasso <anthony@thelastpickle.com></span> |
| </div> |
| <div id="toc" class="toc2"> |
| <div id="toctitle">Table of Contents</div> |
| <ul class="sectlevel1"> |
| <li><a href="#_quickstart_example">Quickstart Example</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_installation">Installation</a></li> |
| <li><a href="#_building_using_the_stress_tool_from_source">Building / Using the Stress Tool from Source</a></li> |
| <li><a href="#_run_your_first_stress_workload">Run Your First Stress Workload</a></li> |
| </ul> |
| </li> |
| <li><a href="#_usage">Usage</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_general_help">General Help</a></li> |
| <li><a href="#_listing_all_workloads">Listing All Workloads</a></li> |
| <li><a href="#_getting_information_about_a_workload">Getting information about a workload</a></li> |
| <li><a href="#_running_a_customized_stress_workload">Running a Customized Stress Workload</a></li> |
| <li><a href="#_running_a_stress_test_for_a_given_duration_instead_of_a_number_of_operations">Running a stress test for a given duration instead of a number of operations</a></li> |
| <li><a href="#_logging">Logging</a></li> |
| <li><a href="#_exporting_metrics">Exporting Metrics</a></li> |
| <li><a href="#_capturing_client_latencies_to_apache_parquet">Capturing Client Latencies to Apache Parquet</a></li> |
| <li><a href="#_workload_restrictions">Workload Restrictions</a></li> |
| </ul> |
| </li> |
| <li><a href="#_developer_docs">Developer Docs</a> |
| <ul class="sectlevel2"> |
| <li><a href="#_building_the_documentation">Building the documentation</a></li> |
| <li><a href="#_writing_a_custom_workload">Writing a Custom Workload</a></li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div id="content"> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>cassandra-easy-stress is a workload-centric stress tool for Apache Cassandra, written in Kotlin. |
| Workloads are easy to write and because they are written in code. You |
| have the ultimate flexibility to build whatever you want without having to learn and |
| operate around the restrictions of a configuration DSL. Workloads can be tweaked via command line |
| parameters to make them fit your environment more closely.</p> |
| </div> |
| <div class="paragraph"> |
| <p>One of the goals of cassandra-easy-stress is to provide enough pre-designed |
| workloads <em>out of the box,</em> so it’s unnecessary to code up a workload for |
| most use cases. For instance, it’s very common to have a key value |
| workload, and want to test that. cassandra-easy-stress allows you to customize a |
| pre-configured key-value workload, using simple parameters to modify the |
| workload to fit your needs. Several workloads are included, such as:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>Time Series</p> |
| </li> |
| <li> |
| <p>Key / Value</p> |
| </li> |
| <li> |
| <p>Materialized Views</p> |
| </li> |
| <li> |
| <p>Collections (maps)</p> |
| </li> |
| <li> |
| <p>Counters</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The tool is flexible enough to design workloads which leverage multiple |
| (thousands) of tables, hitting them as needed. Statistics are |
| automatically captured by the Dropwizard metrics library.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_quickstart_example">Quickstart Example</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The goal of this project is to be testing common workloads (time series, key value) against a Cassandra cluster in 15 minutes or less.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_installation">Installation</h3> |
| <div class="sect3"> |
| <h4 id="_installing_a_package">Installing a Package</h4> |
| <div class="paragraph"> |
| <p><strong>Note</strong>: Installing from packages has not been migrated since I (Jon Haddad) began maintaining my own fork. I’ll be updating this section soon.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_building_using_the_stress_tool_from_source">Building / Using the Stress Tool from Source</h3> |
| <div class="paragraph"> |
| <p>This is currently the only way to use the latest version of cassandra-easy-stress. I’m working on getting the packages updated.</p> |
| </div> |
| <div class="paragraph"> |
| <p>First you’ll need to clone and build the repo. You can grab the source here and build via the included gradle script:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ git clone https://github.com/apache/cassandra-easy-stress.git |
| $ cd cassandra-easy-stress |
| $ ./gradlew shadowJar</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can now run the stress tool via the <code>bin/cassandra-easy-stress</code> script. This is not the same script you’ll be running if you’ve installed from a package or the tarball.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can also create a zip, tar, or deb package by doing the following:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ ./gradlew distZip |
| $ ./gradlew distTar |
| $ ./gradlew deb</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_run_your_first_stress_workload">Run Your First Stress Workload</h3> |
| <div class="paragraph"> |
| <p>Assuming you have either a CCM cluster or are running a single node |
| locally, you can run this quickstart.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Either add the <code>bin</code> directory to your PATH or from within cassandra-easy-stress |
| run the following command to execute 10,000 queries:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ bin/cassandra-easy-stress run KeyValue -n 10000</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You’ll see the output of the keyspaces and tables that are created as well as some statistical information regarding the workload:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight nowrap"><code class="language-bash" data-lang="bash">Creating cassandra_easy_stress: |
| CREATE KEYSPACE |
| IF NOT EXISTS cassandra_easy_stress |
| WITH replication = {'class': 'SimpleStrategy', 'replication_factor':3 } |
| |
| Executing 10000 operations with consistency level LOCAL_ONE and serial consistency level LOCAL_SERIAL |
| Connected to Cassandra cluster. |
| Creating Tables |
| CREATE TABLE IF NOT EXISTS keyvalue ( |
| key text PRIMARY KEY, |
| value text |
| ) WITH caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} AND default_time_to_live = 0 |
| Preparing queries |
| Initializing metrics |
| Stepping rate limiter by 500.0 to 5000.0 |
| Connecting to Cassandra cluster ... |
| Creating generator random |
| 1 threads prepared. |
| Prepopulating data with 0 records per thread (1) |
| Prometheus metrics are available at http://localhost:9500/ |
| Starting main runner |
| [Thread 0]: Running the profile for 10000 iterations... |
| Writes Reads Deletes Errors |
| Count Latency (p99) 1min (req/s) | Count Latency (p99) 1min (req/s) | Count Latency (p99) 1min (req/s) | Count 1min (errors/s) |
| 865 51.99 0 | 800 51.71 0 | 0 0 0 | 0 0 |
| 1614 50.96 273.6 | 1550 50.98 257 | 0 0 0 | 0 0 |
| 2345 50.48 273.6 | 2319 49.42 257 | 0 0 0 | 0 0 |
| 3632 50.17 271.55 | 3532 45.52 256.62 | 0 0 0 | 0 0 |
| 5050 37.23 288.89 | 4950 31.06 274.54 | 0 0 0 | 0 0 |
| 5050 37.23 288.89 | 4950 31.06 274.54 | 0 0 0 | 0 0 |
| 5050 37.23 288.89 | 4950 31.06 274.54 | 0 0 0 | 0 0 |
| Stress complete, 1.</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If you’ve made it this far, congrats! You’ve run your first workload.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_usage">Usage</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>You’ll probably want to do a bit more than simply run a few thousand queries against a KeyValue table with default settings. The nice part about cassandra-easy-stress is that it not only comes with a variety of workloads that you can run to test your cluster, but that it allows you to change many of the parameters. In the quickstart example we used the <code>-n</code> flag to change the total number of operations <code>cassandra-easy-stress</code> will execute against the database. There are many more options available, this section will cover some of them.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="_general_help">General Help</h3> |
| <div class="paragraph"> |
| <p><code>cassandra-easy-stress</code> will display the help if the <code>cassandra-easy-stress</code> command is run without any arguments or if the <code>--help</code> flag is passed:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ bin/cassandra-easy-stress |
| Usage: cassandra-easy-stress [options] [command] [command options] |
| Options: |
| --help, -h |
| Shows this help. |
| Default: false |
| Commands: |
| run Run a cassandra-easy-stress profile |
| Usage: run [options] |
| Options: |
| --cl |
| Consistency level for reads/writes (Defaults to LOCAL_ONE, set |
| custom default with CASSANDRA_EASY_STRESS_CONSISTENCY_LEVEL). |
| Default: LOCAL_ONE |
| --compaction |
| Compaction option to use. Double quotes will auto convert to |
| single for convenience. A shorthand is also available: stcs, lcs, |
| twcs. See the full documentation for all possibilities. |
| Default: <empty string> |
| --compression |
| Compression option to pass to CREATE TABLE. Example: |
| {'class':'ZstdCompressor'} |
| Default: <empty string> |
| --concurrency, -c |
| DEPRECATED. Concurrent queries allowed. Increase for larger |
| clusters. This flag is deprecated and does nothing. |
| Default: 100 |
| --coordinatoronly, --co |
| Coordinator only mode. This will cause cassandra-easy-stress to |
| round robin between nodes without tokens. Requires using |
| -Djoin_ring=false in cassandra-env.sh. When using this option you |
| must only provide a coordinator to --host. |
| Default: false |
| --cql |
| Additional CQL to run after the schema is created. Use for DDL |
| modifications such as creating indexes. |
| Default: [] |
| --csv |
| Write metrics to this file in CSV format. |
| Default: <empty string> |
| --dc |
| The data center to which requests should be sent |
| Default: datacenter1 |
| --deleterate, --deletes |
| Deletion Rate, 0-1. Workloads may have their own defaults. |
| Default is dependent on workload. |
| --drop |
| Drop the keyspace before starting. |
| Default: false |
| --duration, -d |
| Duration of the stress test. Expressed in format 1d 3h 15m |
| Default: 0 |
| --field. |
| Override a field's data generator. Example usage: |
| --field.tablename.fieldname='book(100,200)' |
| Syntax: --field.key=value |
| Default: {} |
| --hdr |
| Print HDR Histograms using this prefix |
| Default: <empty string> |
| -h, --help |
| Show this help |
| --host |
| Default: 127.0.0.1 |
| --id |
| Identifier for this run, will be used in partition keys. Make |
| unique for when starting concurrent runners. |
| Default: 001 |
| --iterations, -i, -n |
| Number of operations to run. |
| Default: 0 |
| --keycache |
| Key cache setting |
| Default: ALL |
| --keyspace |
| Keyspace to use. Automatically created. Use replication option |
| to adjust options. |
| Default: cassandra_easy_stress |
| --max-connections |
| Sets the number of max connections per host |
| Default: 8 |
| --max-requests |
| Sets the max requests per connection |
| Default: 32768 |
| --maxrlat |
| Max Read Latency |
| --maxwlat |
| |
| --no-schema |
| Skips schema creation |
| Default: false |
| --paginate |
| Paginate through the entire partition before completing |
| Default: false |
| --paging |
| Override the driver's default page size. |
| --parquet |
| Capture client latency metrics to a Apache Parquet file at the |
| specified path. If the file is a directory, the file will be |
| named rawlog.parquet within that directory |
| Default: <empty string> |
| --partitiongenerator, --pg |
| Method of generating partition keys. Supports random, normal |
| (gaussian), and sequence. |
| Default: random |
| --partitions, -p |
| Max value of integer component of first partition key. |
| Default: 1000000 |
| --password, -P |
| Default: cassandra |
| --populate |
| Pre-population the DB with N rows before starting load test. |
| Default: 0 |
| --port |
| Override the cql port. Defaults to 9042. |
| Default: 9042 |
| --prometheusport |
| Override the default prometheus port. |
| Set the |
| default with CASSANDRA_EASY_STRESS_PROM_PORT, or set to 0 to |
| disable. |
| Default: 9500 |
| --queue |
| Queue Depth. 2x the rate by default. |
| Default: 10000 |
| --rate |
| Throughput rate, accepts human numbers |
| Default: 5000 |
| --readrate, --reads, -r |
| Read Rate, 0-1. Workloads may have their own defaults. Default |
| is dependent on workload. |
| --replication |
| Replication options |
| Default: {'class': 'SimpleStrategy', 'replication_factor':3 } |
| --rowcache |
| Row cache setting |
| Default: NONE |
| --scl |
| Serial consistency level |
| Default: LOCAL_SERIAL |
| --ssl |
| Enable SSL |
| Default: false |
| --threads, -t |
| Threads to run |
| Default: 1 |
| --ttl |
| Table level TTL, 0 to disable. |
| Default: 0 |
| --username, -U |
| Default: cassandra |
| --workload., -w. |
| Override workload specific parameters. |
| Syntax: --workload.key=value |
| Default: {} |
| |
| info Get details of a specific workload. |
| Usage: info |
| |
| list List all workloads. |
| Usage: list |
| |
| fields null |
| Usage: fields |
| |
| server Start MCP server for tool integration |
| Usage: server [options] |
| Options: |
| -p, --port |
| Port to listen on |
| Default: 9000</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_listing_all_workloads">Listing All Workloads</h3> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ bin/cassandra-easy-stress list |
| Available Workloads: |
| |
| AllowFiltering |
| BasicTimeSeries |
| CountersWide |
| CreateDrop |
| DSESearch |
| KeyValue |
| LWT |
| Locking |
| Maps |
| MaterializedViews |
| RandomPartitionAccess |
| RangeScan |
| SAI |
| Sets |
| TxnCounter |
| UdtTimeSeries |
| |
| You can run any of these workloads by running cassandra-easy-stress run WORKLOAD.</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_getting_information_about_a_workload">Getting information about a workload</h3> |
| <div class="paragraph"> |
| <p>It’s possible to get (some) information about a workload by using the info command. This area is a bit lacking at the moment. It currently only provides the schema and default read rate.</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ bin/cassandra-easy-stress info KeyValue |
| CREATE TABLE IF NOT EXISTS keyvalue ( |
| key text PRIMARY KEY, |
| value text |
| ) |
| Default read rate: 0.5 (override with -r) |
| |
| No dynamic workload parameters.</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_running_a_customized_stress_workload">Running a Customized Stress Workload</h3> |
| <div class="paragraph"> |
| <p>Whenever possible we try to use human friendly numbers. Typing out <code>-n 1000000000</code> is error prone and hard to read, <code>-n 1B</code> is much easier.</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <caption class="title">Table 1. Table Human Friendly Values</caption> |
| <colgroup> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| <col style="width: 25%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Suffix</th> |
| <th class="tableblock halign-left valign-top">Implication</th> |
| <th class="tableblock halign-left valign-top">Example</th> |
| <th class="tableblock halign-left valign-top">Equivalent</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">k</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Thousand</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1k</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1,000</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">m</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Million</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1m</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1,000,000</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">b</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Billion</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1b</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">1,000,000,000</p></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="_running_a_stress_test_for_a_given_duration_instead_of_a_number_of_operations">Running a stress test for a given duration instead of a number of operations</h3> |
| <div class="paragraph"> |
| <p>You might need to run a stress test for a given duration instead of providing a number of operations, especially in case of multithreaded stress runs. This is done by providing the duration in a human readable format with the <code>-d</code> argument. The minimum duration is 1 minute. |
| For example, running a test for 1 hours and 30 minutes will be done as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ cassandra-easy-stress run KeyValue -d "1h 30m"</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To run a test for 1 days, 3 hours and 15 minutes (why not?), run cassandra-easy-stress as follows:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ cassandra-easy-stress run KeyValue -d "1d 3h 15m"</code></pre> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_partition_keys">Partition Keys</h4> |
| <div class="paragraph"> |
| <p>A very useful feature is controlling how many partitions are read and written to for a given stress test. Doing a billion operations across a billion partitions is going to have a much different performance profile than writing to one hundred partitions, especially when mixed with different compaction settings. Using <code>-p</code> we can control how many partition keys a stress test will leverage. The keys are randomly chosen at the moment.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_read_rate">Read Rate</h4> |
| <div class="paragraph"> |
| <p>It’s possible to specify the read rate of a test as a double. For example, if you want to use 1% reads, you’d specify <code>-r .01</code>. The sum of the read rate and delete rate must be less than or equal to 1.0.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_delete_rate">Delete Rate</h4> |
| <div class="paragraph"> |
| <p>It’s possible to specify the delete rate of a test as a double. For example, if you want to use 1% deletes, you’d specify <code>--deleterate .01</code>. The sum of the read rate and delete rate must be less than or equal to 1.0.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_compaction">Compaction</h4> |
| <div class="paragraph"> |
| <p>It’s possible to change the compaction strategy used with the <code>--compaction flag</code>. At the moment this changes the compaction strategy of every table in the test. This will be addressed in the future to be more flexible.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>--compaction</code> flag can accept a raw string along these lines:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>--compaction "{'class':'LeveledCompactionStrategy'}"</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Alternatively, a shortcut format exists as of version 2.0:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>--compaction lcs</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The following shorthand formats are available:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <caption class="title">Table 2. Table Compaction ShortHand</caption> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Syntax</p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Expansion</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">stcs</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'SizeTieredCompactionStrategy'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">stcs,4,32</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'SizeTieredCompactionStrategy', 'min_threshold':4, 'max_threshold':32}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lcs</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'LeveledCompactionStrategy'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lcs,160</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'LeveledCompactionStrategy', 'sstable_size_in_mb':'160'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">lcs,160,10</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'LeveledCompactionStrategy', 'sstable_size_in_mb':'160', 'fanout_size':10}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">twcs</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'TimeWindowCompactionStrategy'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">twcs,1,days</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'TimeWindowCompactionStrategy', 'compaction_window_size':'1', 'compaction_window_unit':'DAYS'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ucs</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'UnifiedCompactionStrategy'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ucs,L4</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'UnifiedCompactionStrategy', 'scaling_parameters':'L4'}</code></p> |
| </div></div></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">ucs,L4,L10</p></td> |
| <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> |
| <p><code>{'class':'UnifiedCompactionStrategy', 'scaling_parameters':'L4,L10'}</code></p> |
| </div></div></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="_compression">Compression</h4> |
| <div class="paragraph"> |
| <p>It’s possible to change the compression options used. At the moment this changes the compression options of every table in the test. This will be addressed in the future to be more flexible.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_customizing_fields">Customizing Fields</h4> |
| <div class="paragraph"> |
| <p>To some extent, workloads can be customized by leveraging the <code>--fields</code> |
| flag. For instance, if we look at the KeyValue workload, we have a table |
| called <code>keyvalue</code> which has a <code>value</code> field.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To customize the data we use for this field, we provide a generator at |
| the command line. By default, the <code>value</code> field will use 100-200 |
| characters of random text. What if we’re storing blobs of text instead? |
| Ideally we’d like to tweak this workload to be closer to our production |
| use case. Let’s use random sections from various books:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ cassandra-easy-stress run KeyValue --field.keyvalue.value='book(20,40)`</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Instead of using random strings of garbage, the KeyValue workload will |
| now use 20-40 words extracted from books.</p> |
| </div> |
| <div class="paragraph"> |
| <p>There are other generators available, such as names, gaussian numbers, |
| and cities. Not every generator applies to every type. It’s up to the |
| workload to specify which fields can be used this way.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_logging">Logging</h3> |
| <div class="paragraph"> |
| <p><code>cassandra-easy-stress</code> uses the <a href="https://logging.apache.org/">Log4J 2</a> logging framework.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You can find the default log4j config in <a href="https://github.com/apache/cassandra-easy-stress/blob/main/src/main/resources/log4j2.yaml" class="bare">https://github.com/apache/cassandra-easy-stress/blob/main/src/main/resources/log4j2.yaml</a> [<code>conf</code>, window="_blank"]. This should be suitable for most use cases.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To use your own logging configuration, simply set the shell variable <code>CASSANDRA_EASY_STRESS_LOG4J</code> to the path of the new logging configuration before running <code>cassandra-easy-stress</code> to point to the config file of your choice.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For more information on how to configure Log4J 2 please see the <a href="https://logging.apache.org/log4j/2.x/manual/configuration.html">configuration</a> documentation.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_debian_package">Debian Package</h4> |
| <div class="paragraph"> |
| <p>The Debian package installs a basic configuration file to <code>/etc/cassandra-easy-stress/log4j2.yaml</code>.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_exporting_metrics">Exporting Metrics</h3> |
| <div class="paragraph"> |
| <p>cassandra-easy-stress automatically runs an HTTP server exporting metrics in Prometheus format on port 9501.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_capturing_client_latencies_to_apache_parquet">Capturing Client Latencies to Apache Parquet</h3> |
| <div class="paragraph"> |
| <p>You can capture detailed client latency metrics to an Apache Parquet file using the <code>--parquet</code> flag followed by a path to a file or directory:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ bin/cassandra-easy-stress run KeyValue --duration 5m --parquet rawlog.parquet</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This writes operation metrics including operation type, success/failure status, start time, and duration to a Parquet file that can be analyzed later with data analysis tools like Pandas, Spark, DuckDB, or visualization tools that support the Parquet format.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If a directory is provided instead of a file, cassandra-easy-stress will automatically create an appropriately named file in that directory.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="_parquet_schema_reference">Parquet Schema Reference</h4> |
| <div class="paragraph"> |
| <p>Each row in the Parquet file represents a single operation with the following columns:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <caption class="title">Table 3. Table Parquet Schema</caption> |
| <colgroup> |
| <col style="width: 33.3333%;"> |
| <col style="width: 33.3333%;"> |
| <col style="width: 33.3334%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top">Column</th> |
| <th class="tableblock halign-left valign-top">Type</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>operation</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>binary (UTF8)</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Operation type (e.g. <code>Insert</code>, <code>Select</code>) — derived from the statement class name</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>success</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>boolean</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Whether the operation completed successfully</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>failure_reason</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>binary (UTF8)</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Exception class name if the operation failed (empty string on success)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>failure_stacktrace</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>binary (UTF8)</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Full stacktrace if the operation failed (empty string on success)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>request_start_time_ms</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>int64</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Epoch milliseconds when the client intended to send the request</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>request_duration_ns</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>int64</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Total elapsed time in nanoseconds from request creation to response (includes queue time)</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>service_start_time_ms</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>int64</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Epoch milliseconds when the request was actually sent to the database</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>service_duration_ns</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><code>int64</code></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Actual database processing time in nanoseconds (excludes queue time)</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <div class="title">Note</div> |
| </td> |
| <td class="content"> |
| Every operation is captured (not sampled), so file sizes grow proportionally with the number of operations. |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_analyzing_parquet_files_with_duckdb">Analyzing Parquet Files with DuckDB</h4> |
| <div class="paragraph"> |
| <p>The Parquet files created by cassandra-easy-stress can be easily analyzed using DuckDB, a lightweight analytical database engine. Here are some example queries to get you started:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-sql" data-lang="sql">-- Show summary statistics for operation latencies for every minute |
| SELECT date_trunc('minute', epoch_ms(request_start_time_ms)) as minute, |
| COUNT(*) as count, |
| AVG(request_duration_ns / 1000 / 1000) as avg, |
| MIN(request_duration_ns / 1000 / 1000) as min, |
| MAX(request_duration_ns / 1000 / 1000) as max, |
| APPROX_QUANTILE(request_duration_ns / 1000 / 1000, .5) as p50, |
| APPROX_QUANTILE(request_duration_ns / 1000 / 1000, .9) as p90, |
| APPROX_QUANTILE(request_duration_ns / 1000 / 1000, .99) as p99, |
| COUNT(CASE WHEN failure_reason != '' THEN 1 END) AS errors, |
| COUNT(CASE WHEN failure_reason = 'ReadTimeoutException' THEN 1 END) AS read_timeouts, |
| COUNT(CASE WHEN failure_reason = 'WriteTimeoutException' THEN 1 END) AS write_timeouts, |
| FROM read_parquet('rawlog.parquet') |
| GROUP BY minute |
| ORDER BY minute; |
| |
| ┌─────────────────────┬────────┬─────────────────────┬──────────┬────────────────────┬─────────────────────┬─────────────────────┬────────────────────┬────────┬───────────────┬────────────────┐ |
| │ minute │ count │ avg │ min │ max │ p50 │ p90 │ p99 │ errors │ read_timeouts │ write_timeouts │ |
| │ timestamp │ int64 │ double │ double │ double │ double │ double │ double │ int64 │ int64 │ int64 │ |
| ├─────────────────────┼────────┼─────────────────────┼──────────┼────────────────────┼─────────────────────┼─────────────────────┼────────────────────┼────────┼───────────────┼────────────────┤ |
| │ 2025-05-23 22:45:00 │ 141911 │ 18.891404855317813 │ 0.088042 │ 1305.993875 │ 0.23617621307864622 │ 0.5454138286498701 │ 755.160273634975 │ 0 │ 0 │ 0 │ |
| │ 2025-05-23 22:46:00 │ 300081 │ 0.26154326542833034 │ 0.091458 │ 16.620042 │ 0.2198726495794396 │ 0.28866495065114356 │ 1.0759477146627234 │ 0 │ 0 │ 0 │ |
| │ 2025-05-23 22:47:00 │ 300075 │ 0.29655502679997087 │ 0.089208 │ 19.247875 │ 0.2241928371244093 │ 0.3096208807374364 │ 1.8582042492087465 │ 0 │ 0 │ 0 │ |
| │ 2025-05-23 22:48:00 │ 298543 │ 0.6524298801211285 │ 0.093666 │ 198.99904199999997 │ 0.22677466153454573 │ 0.33573102120265713 │ 9.839418314581492 │ 0 │ 0 │ 0 │ |
| │ 2025-05-23 22:49:00 │ 300053 │ 0.30696147925533085 │ 0.100167 │ 64.216666 │ 0.2249157848195121 │ 0.3072763658664282 │ 1.6342296967730887 │ 0 │ 0 │ 0 │ |
| │ 2025-05-23 22:50:00 │ 24765 │ 0.4530204902079576 │ 0.12675 │ 39.548167 │ 0.2259263537252715 │ 0.30608390597020046 │ 7.7139616210838575 │ 0 │ 0 │ 0 │ |
| └─────────────────────┴────────┴─────────────────────┴──────────┴────────────────────┴─────────────────────┴─────────────────────┴────────────────────┴────────┴───────────────┴────────────────┘ |
| |
| |
| -- Show error counts |
| SELECT failure_reason, count(*) |
| FROM read_parquet('rawlog.parquet') |
| WHERE failure_reason != '' |
| GROUP BY failure_reason;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>You can also use DuckDB through its various clients including Python, R, Java, and JDBC.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="_understanding_request_time_vs_service_time">Understanding Request Time vs Service Time</h4> |
| <div class="paragraph"> |
| <p>When analyzing latency data from the Parquet files, it’s important to understand the distinction between two key metrics:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Service Time</strong>: This is the actual time it takes for the database to process a request and return a response once the request is received by the database. It measures only the execution time of the operation.</p> |
| </li> |
| <li> |
| <p><strong>Request Time</strong>: This is the total time from when the client intended to make the request until receiving the response. It includes the service time plus any queue time or delays that might have occurred before the request was actually sent to the database.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The difference between these metrics is critical for understanding coordinated omission, a common problem in performance testing where the test client doesn’t accurately capture the full latency that would be experienced by real users when the system is under load.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, if your database is overloaded and can only process 100 operations per second, but your test is trying to send 200 operations per second:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>A naïve benchmark would only measure the service time of the operations that actually got processed, missing the fact that half the operations were delayed.</p> |
| </li> |
| <li> |
| <p>A properly instrumented benchmark (like cassandra-easy-stress) captures the request time, which includes how long operations had to wait in a queue.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>When using the Parquet files for analysis, you can examine both metrics to get a more complete picture of your system’s performance under load:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-sql" data-lang="sql">-- Compare average service time vs request time by operation type |
| SELECT |
| operation, |
| AVG(service_duration_ns / 1000 / 1000) as avg_service_time_ms, |
| AVG(request_duration_ns / 1000 / 1000) as avg_request_time_ms, |
| AVG(request_duration_ns - service_duration_ns) / 1000 / 1000 as avg_queue_time_ms |
| FROM read_parquet('rawlog.parquet') |
| GROUP BY operation;</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>A significant difference between average request time and average service time indicates queuing or scheduling delays in your system, which can be an early warning sign of performance bottlenecks.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_workload_restrictions">Workload Restrictions</h3> |
| <div class="paragraph"> |
| <p>The <code>BasicTimeSeries</code> workload only supports Cassandra versions 3.0 and above. This is because range deletes are used by this workload during runtime. Range deletes are only support in Cassandra versions 3.0. An exception will is thrown if this workload is used and a Cassandra version less than 3.0 is detected during runtime.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="_developer_docs">Developer Docs</h2> |
| <div class="sectionbody"> |
| <div class="sect2"> |
| <h3 id="_building_the_documentation">Building the documentation</h3> |
| <div class="paragraph"> |
| <p>First generate the command examples with the following shell script:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code class="language-bash" data-lang="bash">$ manual/generate_examples.sh</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>There’s a docker service to build the HTML manual:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlight"><code>$ docker-compose up docs</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="_writing_a_custom_workload">Writing a Custom Workload</h3> |
| <div class="paragraph"> |
| <p><code>cassandra-easy-stress</code> is a work in progress. Writing a stress workload isn’t documented yet as it is still changing.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div id="footer"> |
| <div id="footer-text"> |
| Last updated 2026-03-07 10:33:40 UTC |
| </div> |
| </div> |
| </body> |
| </html> |