Thursday 4 August 2016

Determining my IOPS need when planning Oracle RDS in AWS

When provisioning a database in AWS, an RDS database that is.  You must carefully look into your IOPS requirements.

Why,  well let me give you a hint  --> $$$$$$$

A classic line from AWS is – you pay for what you use – period!

So, the more IOPS you provision – the more that you will pay.

For example, in Sydney for a single AZ deployed database, you will pay:

Storage Rate
$0.138 per GB-month

Provisioned IOPS Rate
$0.11 per IOPS-Month

So, if I want 3000 IOPS, this is going to cost 3000x.11 per month.  or 330 bucks a month for guaranteed IOPS.  + my storage usage

How many IOPS do I need, well you could try this:  https://d0.awsstatic.com/whitepapers/determining-iops-needs-for-oracle-database-on-aws.pdf which is cool, but comes down to your writing some SQL:

CREATE TABLE peak_iops_measurement (capture_timestamp date,
total_read_io number, total_write_io number, total_io number,
total_read_bytes number, total_write_bytes number, total_bytes
number);


DECLARE
run_duration number := 3600;
capture_gap number := 5;
loop_count number :=run_duration/capture_gap;
rdio number;
wtio number;
prev_rdio number :=0;
Prev_wtio number :=0;
rdbt number;
wtbt number;
prev_rdbt number;
Prev_wtbt number;
BEGIN
FOR i in 1..loop_count LOOP
SELECT SUM(value) INTO rdio from gv$sysstat
WHERE name ='physical read total IO requests';
SELECT SUM(value) INTO wtio from gv$sysstat
WHERE name ='physical write total IO requests';
SELECT SUM(value)* 0.000008 INTO rdbt from gv$sysstat
WHERE name ='physical read total bytes';
SELECT SUM(value* 0.000008) INTO wtbt from gv$sysstat
WHERE name ='physical write total bytes';
IF i > 1 THEN
INSERT INTO peak_iops_measurement (capture_timestamp,
total_read_io, total_write_io, total_io, total_read_bytes,
total_write_bytes, total_bytes)
VALUES (sysdate,(rdio-prev_rdio)/5,(wtio-prev_wtio)/5,((rdioprev_rdio)/5)+((wtio-prev_wtio))/5,(rdbt-prev_rdbt)/5,(wtbtprev_wtbt)/5,((rdbt-prev_rdbt)/5)+((wtbt-prev_wtbt))/5);
END IF;
prev_rdio := rdio;
prev_wtio := wtio;
prev_rdbt := rdbt;
prev_wtbt := wtbt;
DBMS_LOCK.SLEEP(capture_gap);
END LOOP;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
/

This is cool, but you need to wait days…  It’ll sit there chugging too.

Of course, you could just use:

select METRIC_NAME,avg(AVERAGE) as "Value", max(average) as maxval
   from dba_hist_sysmetric_summary
   where METRIC_NAME in ('Physical Read Total IO Requests Per Sec','Physical Write Total IO Requests Per Sec')
   group by METRIC_NAME;

Which will give you something like:

METRIC_NAME                                                      Value                  MAXVAL                
---------------------------------------------------------------- ---------------------- ----------------------
Physical Write Total IO Requests Per Sec                         38.47016094280773108458390177353342428377 1616.23477993026      
Physical Read Total IO Requests Per Sec                          140.575645080103957442019099590723055935 2946.16113345313
      

Wow, that is pretty neat – pretty much exactly what I want.  Note that this is the total AVERAGES for ever.  If you want some more information, you could graph the details in the results based upon the snap_id:

Get the snapshot information:

select * from dba_hist_snapshot;
 

Get the statistics per snap:


   select
  snap_id,
  metric_name "Metric Name",
  metric_unit "Metric Unit",
  minval "Minimum Value",
  maxval "Maximum Value",
  average "Average Value"
from
  DBA_HIST_SYSMETRIC_SUMMARY
where
       snap_id
        

For a totally RAD summary:

select t1.snap_id, t2.METRIC_NAME,t2.average, t2.metric_unit, t1.begin_interval_time
   from dba_hist_sysmetric_summary t2, dba_hist_snapshot t1
   where t2.METRIC_NAME in ('Physical Read Total IO Requests Per Sec','Physical Write Total IO Requests Per Sec')
   and t2.snap_id=t1.snap_id
   order by t2.snap_id desc;

 

image

Now, a much better view

 

select t2.maxval+t3.maxval ,t2.average + t3.average, t1.begin_interval_time
   from dba_hist_sysmetric_summary t2, dba_hist_snapshot t1, dba_hist_sysmetric_summary t3
   where t2.METRIC_NAME in ('Physical Read Total IO Requests Per Sec')
   and t3.METRIC_NAME = 'Physical Write Total IO Requests Per Sec'
   and t2.snap_id=t3.snap_id
   and t2.instance_number= t2.instance_number
   and t2.begin_time= t3.begin_time
   and t2.snap_id=t1.snap_id
   order by t2.snap_id desc;

Which produces the following

image

I would not use MAX, but trendline analysis.  These guys would probably be okay with 1500, but I’d make it 2000 IOPS.

1 comment:

Ganesh Singh said...

Hi Shannon,

I am getting below error while executing the block. I am running it as sysdba and table is also created in sys schema. Please review the code.

SQL> DECLARE
run_duration number := 3600;
capture_gap number := 5;
2 loop_count number :=run_duration/capture_gap;
rdio number;
wtio number;
3 4 5 6 7 prev_rdio number :=0;
Prev_wtio number :=0;
8 9 rdbt number;
wtbt number;
10 11 prev_rdbt number;
Prev_wtbt number;
12 13 BEGIN
14 FOR i in 1..loop_count LOOP
SELECT SUM(value) INTO rdio from gv$sysstat
15 16 WHERE name ='physical read total IO requests';
SELECT SUM(value) INTO wtio from gv$sysstat
17 18 WHERE name ='physical write total IO requests';
SELECT SUM(value)* 0.000008 INTO rdbt from gv$sysstat
19 20 WHERE name ='physical read total bytes';
21 SELECT SUM(value* 0.000008) INTO wtbt from gv$sysstat
WHERE name ='physical write total bytes';
22 23 IF i > 1 THEN
24 INSERT INTO peak_iops_measurement (capture_timestamp,
total_read_io, total_write_io, total_io, total_read_bytes,
total_write_bytes, total_bytes)
25 26 27 VALUES (sysdate,(rdio-prev_rdio)/5,(wtio-prev_wtio)/5,((rdioprev_rdio)/5)+((wtio-prev_wtio))/5,(rdbt-prev_rdbt)/5,(wtbtprev_wtbt)/5,((rdbt-prev_rdbt)/5)+((wtbt-prev_wtbt))/5);
END IF;
28 prev_rdio := rdio;
29 prev_wtio := wtio;
30 31 prev_rdbt := rdbt;
prev_wtbt := wtbt;
32 33 DBMS_LOCK.SLEEP(capture_gap);
END LOOP;
COMMIT;
EXCEPTION
34 35 WHEN OTHERS THEN
36 37 38 ROLLBACK;
39 END;
/ 40
VALUES (sysdate,(rdio-prev_rdio)/5,(wtio-prev_wtio)/5,((rdioprev_rdio)/5)+((wtio-prev_wtio))/5,(rdbt-prev_rdbt)/5,(wtbtprev_wtbt)/5,((rdbt-prev_rdbt)/5)+((wtbt-prev_wtbt))/5);
*
ERROR at line 27:
ORA-06550: line 27, column 116:
PL/SQL: ORA-00984: column not allowed here
ORA-06550: line 24, column 1:
PL/SQL: SQL Statement ignored