1 | import { FaastModule } from "../index";
|
2 | import { AwsOptions } from "./aws/aws-faast";
|
3 | import { GoogleOptions } from "./google/google-faast";
|
4 | import { FunctionStats, CommonOptions } from "./provider";
|
5 | import { PropertiesExcept, AnyFunction } from "./types";
|
6 | /**
|
7 | * A line item in the cost estimate, including the resource usage metric
|
8 | * measured and its pricing.
|
9 | * @public
|
10 | */
|
11 | export declare class CostMetric {
|
12 | /** The name of the cost metric, e.g. `functionCallDuration` */
|
13 | readonly name: string;
|
14 | /** The price in USD per unit measured. */
|
15 | readonly pricing: number;
|
16 | /** The name of the units that pricing is measured in for this metric. */
|
17 | readonly unit: string;
|
18 | /** The measured value of the cost metric, in units. */
|
19 | readonly measured: number;
|
20 | /**
|
21 | * The plural form of the unit name. By default the plural form will be the
|
22 | * name of the unit with "s" appended at the end, unless the last letter is
|
23 | * capitalized, in which case there is no plural form (e.g. "GB").
|
24 | */
|
25 | readonly unitPlural?: string;
|
26 | /**
|
27 | * An optional comment, usually providing a link to the provider's pricing
|
28 | * page and other data.
|
29 | */
|
30 | readonly comment?: string;
|
31 | /**
|
32 | * True if this cost metric is only for informational purposes (e.g. AWS's
|
33 | * `logIngestion`) and does not contribute cost.
|
34 | */
|
35 | readonly informationalOnly?: boolean;
|
36 | /** @internal */
|
37 | constructor(arg: PropertiesExcept<CostMetric, AnyFunction>);
|
38 | /**
|
39 | * The cost contribution of this cost metric. Equal to
|
40 | * { CostMetric.pricing} * { CostMetric.measured}.
|
41 | */
|
42 | cost(): number;
|
43 | /**
|
44 | * Return a string with the cost estimate for this metric, omitting
|
45 | * comments.
|
46 | */
|
47 | describeCostOnly(): string;
|
48 | /** Describe this cost metric, including comments. */
|
49 | toString(): string;
|
50 | }
|
51 | /**
|
52 | * A summary of the costs incurred by a faast.js module at a point in time.
|
53 | * Output of {@link FaastModule.costSnapshot}.
|
54 | * @remarks
|
55 | * Cost information provided by faast.js is an estimate. It is derived from
|
56 | * internal faast.js measurements and not by consulting data provided by your
|
57 | * cloud provider.
|
58 | *
|
59 | * **Faast.js does not guarantee the accuracy of cost estimates.**
|
60 | *
|
61 | * **Use at your own risk.**
|
62 | *
|
63 | * Example using AWS:
|
64 | * ```typescript
|
65 | * const faastModule = await faast("aws", m);
|
66 | * try {
|
67 | * // Invoke faastModule.functions.*
|
68 | * } finally {
|
69 | * await faastModule.cleanup();
|
70 | * console.log(`Cost estimate:`);
|
71 | * console.log(`${await faastModule.costSnapshot()}`);
|
72 | * }
|
73 | * ```
|
74 | *
|
75 | * AWS example output:
|
76 | * ```text
|
77 | * Cost estimate:
|
78 | * functionCallDuration $0.00002813/second 0.6 second $0.00001688 68.4% [1]
|
79 | * sqs $0.00000040/request 9 requests $0.00000360 14.6% [2]
|
80 | * sns $0.00000050/request 5 requests $0.00000250 10.1% [3]
|
81 | * functionCallRequests $0.00000020/request 5 requests $0.00000100 4.1% [4]
|
82 | * outboundDataTransfer $0.09000000/GB 0.00000769 GB $0.00000069 2.8% [5]
|
83 | * logIngestion $0.50000000/GB 0 GB $0 0.0% [6]
|
84 | * ---------------------------------------------------------------------------------------
|
85 | * $0.00002467 (USD)
|
86 | *
|
87 | * * Estimated using highest pricing tier for each service. Limitations apply.
|
88 | * ** Does not account for free tier.
|
89 | * [1]: https://aws.amazon.com/lambda/pricing (rate = 0.00001667/(GB*second) * 1.6875 GB = 0.00002813/second)
|
90 | * [2]: https://aws.amazon.com/sqs/pricing
|
91 | * [3]: https://aws.amazon.com/sns/pricing
|
92 | * [4]: https://aws.amazon.com/lambda/pricing
|
93 | * [5]: https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer
|
94 | * [6]: https://aws.amazon.com/cloudwatch/pricing/ - Log ingestion costs not currently included.
|
95 | * ```
|
96 | *
|
97 | * A cost snapshot contains several {@link CostMetric} values. Each `CostMetric`
|
98 | * summarizes one component of the overall cost of executing the functions so
|
99 | * far. Some cost metrics are common to all faast providers, and other metrics
|
100 | * are provider-specific. The common metrics are:
|
101 | *
|
102 | * - `functionCallDuration`: the estimated billed CPU time (rounded to the next
|
103 | * 100ms) consumed by completed cloud function calls. This is the metric that
|
104 | * usually dominates cost.
|
105 | *
|
106 | * - `functionCallRequests`: the number of invocation requests made. Most
|
107 | * providers charge for each invocation.
|
108 | *
|
109 | * Provider-specific metrics vary. For example, AWS has the following additional
|
110 | * metrics:
|
111 | *
|
112 | * - `sqs`: AWS Simple Queueing Service. This metric captures the number of
|
113 | * queue requests made to insert and retrieve queued results (each 64kb chunk
|
114 | * is counted as an additional request). SQS is used even if
|
115 | * {@link CommonOptions.mode} is not set to `"queue"`, because it is necessary
|
116 | * for monitoring cloud function invocations.
|
117 | *
|
118 | * - `sns`: AWS Simple Notification Service. SNS is used to invoke Lambda
|
119 | * functions when {@link CommonOptions.mode} is `"queue"`.
|
120 | *
|
121 | * - `outboundDataTransfer`: an estimate of the network data transferred out
|
122 | * from the cloud provider for this faast.js module. This estimate only counts
|
123 | * data returned from cloud function invocations and infrastructure that
|
124 | * faast.js sets up. It does not count any outbound data sent by your cloud
|
125 | * functions that are not known to faast.js. Note that if you run faast.js on
|
126 | * EC2 in the same region (see {@link AwsOptions.region}), then the data
|
127 | * transfer costs will be zero (however, the cost snapshot will not include
|
128 | * EC2 costs). Also note that if your cloud function transfers data from/to S3
|
129 | * buckets in the same region, there is no cost as long as that data is not
|
130 | * returned from the function.
|
131 | *
|
132 | * - `logIngestion`: this cost metric is always zero for AWS. It is present to
|
133 | * remind the user that AWS charges for log data ingested by CloudWatch Logs
|
134 | * that are not measured by faast.js. Log entries may arrive significantly
|
135 | * after function execution completes, and there is no way for faast.js to
|
136 | * know exactly how long to wait, therefore it does not attempt to measure
|
137 | * this cost. In practice, if your cloud functions do not perform extensive
|
138 | * logging on all invocations, log ingestion costs from faast.js are likely to
|
139 | * be low or fall within the free tier.
|
140 | *
|
141 | * For Google, extra metrics include `outboundDataTransfer` similar to AWS, and
|
142 | * `pubsub`, which combines costs that are split into `sns` and `sqs` on AWS.
|
143 | *
|
144 | * The Local provider has no extra metrics.
|
145 | *
|
146 | * Prices are retrieved dynamically from AWS and Google and cached locally.
|
147 | * Cached prices expire after 24h. For each cost metric, faast.js uses the
|
148 | * highest price tier to compute estimated pricing.
|
149 | *
|
150 | * Cost estimates do not take free tiers into account.
|
151 | * @public
|
152 | */
|
153 | export declare class CostSnapshot {
|
154 | /** The {@link Provider}, e.g. "aws" or "google" */
|
155 | readonly provider: string;
|
156 | /**
|
157 | * The options used to initialize the faast.js module where this cost
|
158 | * snapshot was generated.
|
159 | */
|
160 | readonly options: CommonOptions | AwsOptions | GoogleOptions;
|
161 | /** The function statistics that were used to compute prices. */
|
162 | readonly stats: FunctionStats;
|
163 | /**
|
164 | * The cost metric components for this cost snapshot. See
|
165 | * {@link CostMetric}.
|
166 | */
|
167 | readonly costMetrics: CostMetric[];
|
168 | /** @internal */
|
169 | constructor(
|
170 | /** The {@link Provider}, e.g. "aws" or "google" */
|
171 | provider: string,
|
172 | /**
|
173 | * The options used to initialize the faast.js module where this cost
|
174 | * snapshot was generated.
|
175 | */
|
176 | options: CommonOptions | AwsOptions | GoogleOptions, stats: FunctionStats, costMetrics?: CostMetric[]);
|
177 | /** Sum of cost metrics. */
|
178 | total(): number;
|
179 | /** A summary of all cost metrics and prices in this cost snapshot. */
|
180 | toString(): string;
|
181 | /**
|
182 | * Comma separated value output for a cost snapshot.
|
183 | * @remarks
|
184 | * The format is "metric,unit,pricing,measured,cost,percentage,comment".
|
185 | *
|
186 | * Example output:
|
187 | * ```text
|
188 | * metric,unit,pricing,measured,cost,percentage,comment
|
189 | * functionCallDuration,second,0.00002813,0.60000000,0.00001688,64.1% ,"https://aws.amazon.com/lambda/pricing (rate = 0.00001667/(GB*second) * 1.6875 GB = 0.00002813/second)"
|
190 | * functionCallRequests,request,0.00000020,5,0.00000100,3.8% ,"https://aws.amazon.com/lambda/pricing"
|
191 | * outboundDataTransfer,GB,0.09000000,0.00000844,0.00000076,2.9% ,"https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer"
|
192 | * sqs,request,0.00000040,13,0.00000520,19.7% ,"https://aws.amazon.com/sqs/pricing"
|
193 | * sns,request,0.00000050,5,0.00000250,9.5% ,"https://aws.amazon.com/sns/pricing"
|
194 | * logIngestion,GB,0.50000000,0,0,0.0% ,"https://aws.amazon.com/cloudwatch/pricing/ - Log ingestion costs not currently included."
|
195 | * ```
|
196 | */
|
197 | csv(): string;
|
198 | /** @internal */
|
199 | push(metric: CostMetric): void;
|
200 | /**
|
201 | * Find a specific cost metric by name.
|
202 | * @returns a {if found, otherwise `undefined`.
CostMetric} |
203 | */
|
204 | find(name: string): CostMetric | undefined;
|
205 | }
|
206 | /**
|
207 | * Analyze the cost of a workload across many provider configurations.
|
208 | * @public
|
209 | */
|
210 | export declare namespace CostAnalyzer {
|
211 | /**
|
212 | * An input to {@link CostAnalyzer.analyze}, specifying one
|
213 | * configuration of faast.js to run against a workload. See
|
214 | * {@link AwsOptions} and {@link GoogleOptions}.
|
215 | * @public
|
216 | */
|
217 | type Configuration = {
|
218 | provider: "aws";
|
219 | options: AwsOptions;
|
220 | } | {
|
221 | provider: "google";
|
222 | options: GoogleOptions;
|
223 | };
|
224 | /**
|
225 | * Default AWS cost analyzer configurations include all memory sizes for AWS
|
226 | * Lambda.
|
227 | * @remarks
|
228 | * The default AWS cost analyzer configurations include every memory size
|
229 | * from 128MB to 3008MB in 64MB increments. Each configuration has the
|
230 | * following settings:
|
231 | *
|
232 | * ```typescript
|
233 | * {
|
234 | * provider: "aws",
|
235 | * options: {
|
236 | * mode: "https",
|
237 | * memorySize,
|
238 | * timeout: 300,
|
239 | * gc: "off",
|
240 | * childProcess: true
|
241 | * }
|
242 | * }
|
243 | * ```
|
244 | *
|
245 | * Use `Array.map` to change or `Array.filter` to remove some of these
|
246 | * configurations. For example:
|
247 | *
|
248 | * ```typescript
|
249 | * const configsWithAtLeast1GB = awsConfigurations.filter(c => c.memorySize > 1024)
|
250 | * const shorterTimeout = awsConfigurations.map(c => ({...c, timeout: 60 }));
|
251 | * ```
|
252 | * @public
|
253 | */
|
254 | const awsConfigurations: Configuration[];
|
255 | /**
|
256 | * Default Google Cloud Functions cost analyzer configurations include all
|
257 | * available memory sizes.
|
258 | * @remarks
|
259 | * Each google cost analyzer configuration follows this template:
|
260 | *
|
261 | * ```typescript
|
262 | * {
|
263 | * provider: "google",
|
264 | * options: {
|
265 | * mode: "https",
|
266 | * memorySize,
|
267 | * timeout: 300,
|
268 | * gc: "off",
|
269 | * childProcess: true
|
270 | * }
|
271 | * }
|
272 | * ```
|
273 | *
|
274 | * where `memorySize` is in `[128, 256, 512, 1024, 2048]`.
|
275 | * @public
|
276 | */
|
277 | const googleConfigurations: Configuration[];
|
278 | /**
|
279 | * User-defined custom metrics for a workload. These are automatically
|
280 | * summarized in the output; see {@link CostAnalyzer.Workload}.
|
281 | * @public
|
282 | */
|
283 | type WorkloadAttribute<A extends string> = {
|
284 | [attr in A]: number;
|
285 | };
|
286 | /**
|
287 | * A user-defined cost analyzer workload for {@link CostAnalyzer.analyze}.
|
288 | * @public
|
289 | * Example:
|
290 | */
|
291 | interface Workload<T extends object, A extends string> {
|
292 | /**
|
293 | * The imported module that contains the cloud functions to test.
|
294 | */
|
295 | funcs: T;
|
296 | /**
|
297 | * A function that executes cloud functions on
|
298 | * `faastModule.functions.*`. The work function should return `void` if
|
299 | * there are no custom workload attributes. Otherwise, it should return
|
300 | * a {@link CostAnalyzer.WorkloadAttribute} object which maps
|
301 | * user-defined attribute names to numerical values for the workload.
|
302 | * For example, this might measure bandwidth or some other metric not
|
303 | * tracked by faast.js, but are relevant for evaluating the
|
304 | * cost-performance tradeoff of the configurations analyzed by the cost
|
305 | * analyzer.
|
306 | */
|
307 | work: (faastModule: FaastModule<T>) => Promise<WorkloadAttribute<A> | void>;
|
308 | /**
|
309 | * An array of configurations to run the work function against (see
|
310 | * {@link CostAnalyzer.Configuration}). For example, each entry in the
|
311 | * array may specify a provider, memory size, and other options.
|
312 | * Default: {@link CostAnalyzer.awsConfigurations}.
|
313 | */
|
314 | configurations?: Configuration[];
|
315 | /**
|
316 | * Combine {@link CostAnalyzer.WorkloadAttribute} instances returned
|
317 | * from multiple workload executions (caused by value of
|
318 | * {@link CostAnalyzer.Workload.repetitions}). The default is a function
|
319 | * that takes the average of each attribute.
|
320 | */
|
321 | summarize?: (summaries: WorkloadAttribute<A>[]) => WorkloadAttribute<A>;
|
322 | /**
|
323 | * Format an attribute value for console output. This is displayed by
|
324 | * the cost analyzer when all of the repetitions for a configuration
|
325 | * have completed. The default returns
|
326 | * `${attribute}:${value.toFixed(1)}`.
|
327 | */
|
328 | format?: (attr: A, value: number) => string;
|
329 | /**
|
330 | * Format an attribute value for CSV. The default returns
|
331 | * `value.toFixed(1)`.
|
332 | */
|
333 | formatCSV?: (attr: A, value: number) => string;
|
334 | /**
|
335 | * If true, do not output live results to the console. Can be useful for
|
336 | * running the cost analyzer as part of automated tests. Default: false.
|
337 | */
|
338 | silent?: boolean;
|
339 | /**
|
340 | * The number of repetitions to run the workload for each cost analyzer
|
341 | * configuration. Higher repetitions help reduce the jitter in the
|
342 | * results. Repetitions execute in the same FaastModule instance.
|
343 | * Default: 10.
|
344 | */
|
345 | repetitions?: number;
|
346 | /**
|
347 | * The amount of concurrency to allow. Concurrency can arise from
|
348 | * multiple repetitions of the same configuration, or concurrenct
|
349 | * executions of different configurations. This concurrency limit
|
350 | * throttles the total number of concurrent workload executions across
|
351 | * both of these sources of concurrency. Default: 64.
|
352 | */
|
353 | concurrency?: number;
|
354 | }
|
355 | /**
|
356 | * A cost estimate result for a specific cost analyzer configuration.
|
357 | * @public
|
358 | */
|
359 | interface Estimate<A extends string> {
|
360 | /**
|
361 | * The cost snapshot for the cost analysis of the specific (workload,
|
362 | * configuration) combination. See {@link CostSnapshot}.
|
363 | */
|
364 | costSnapshot: CostSnapshot;
|
365 | /**
|
366 | * The worload configuration that was analyzed. See
|
367 | * {@link CostAnalyzer.Configuration}.
|
368 | */
|
369 | config: Configuration;
|
370 | /**
|
371 | * Additional workload metrics returned from the work function. See
|
372 | * {@link CostAnalyzer.WorkloadAttribute}.
|
373 | */
|
374 | extraMetrics: WorkloadAttribute<A>;
|
375 | }
|
376 | /**
|
377 | * Estimate the cost of a workload using multiple configurations and
|
378 | * providers.
|
379 | * @param userWorkload - a {@link CostAnalyzer.Workload} object specifying
|
380 | * the workload to run and additional parameters.
|
381 | * @returns A promise for a {@link CostAnalyzer.Result}
|
382 | * @public
|
383 | * @remarks
|
384 | * It can be deceptively difficult to set optimal parameters for AWS Lambda
|
385 | * and similar services. On the surface there appears to be only one
|
386 | * parameter: memory size. Choosing more memory also gives more CPU
|
387 | * performance, but it's unclear how much. It's also unclear where single
|
388 | * core performance stops getting better. The workload cost analyzer solves
|
389 | * these problems by making it easy to run cost experiments.
|
390 | * ```text
|
391 | * (AWS)
|
392 | * ┌───────┐
|
393 | * ┌────▶│ 128MB │
|
394 | * │ └───────┘
|
395 | * │ ┌───────┐
|
396 | * ┌─────────────────┐ ├────▶│ 256MB │
|
397 | * ┌──────────────┐ │ │ │ └───────┘
|
398 | * │ workload │───▶│ │ │ ...
|
399 | * └──────────────┘ │ │ │ ┌───────┐
|
400 | * │ cost analyzer │─────┼────▶│3008MB │
|
401 | * ┌──────────────┐ │ │ │ └───────┘
|
402 | * │configurations│───▶│ │ │
|
403 | * └──────────────┘ │ │ │ (Google)
|
404 | * └─────────────────┘ │ ┌───────┐
|
405 | * ├────▶│ 128MB │
|
406 | * │ └───────┘
|
407 | * │ ┌───────┐
|
408 | * └────▶│ 256MB │
|
409 | * └───────┘
|
410 | * ```
|
411 | * `costAnalyzer` is the entry point. It automatically runs this workload
|
412 | * against multiple configurations in parallel. Then it uses faast.js' cost
|
413 | * snapshot mechanism to automatically determine the price of running the
|
414 | * workload with each configuration.
|
415 | *
|
416 | * Example:
|
417 | *
|
418 | * ```typescript
|
419 | * // functions.ts
|
420 | * export function randomNumbers(n: number) {
|
421 | * let sum = 0;
|
422 | * for (let i = 0; i < n; i++) {
|
423 | * sum += Math.random();
|
424 | * }
|
425 | * return sum;
|
426 | * }
|
427 | *
|
428 | * // cost-analyzer-example.ts
|
429 | * import { writeFileSync } from "fs";
|
430 | * import { CostAnalyzer, FaastModule } from "faastjs";
|
431 | * import * as funcs from "./functions";
|
432 | *
|
433 | * async function work(faastModule: FaastModule<typeof funcs>) {
|
434 | * await faastModule.functions.randomNumbers(100000000);
|
435 | * }
|
436 | *
|
437 | * async function main() {
|
438 | * const results = await CostAnalyzer.analyze({ funcs, work });
|
439 | * writeFileSync("cost.csv", results.csv());
|
440 | * }
|
441 | *
|
442 | * main();
|
443 | * ```
|
444 | *
|
445 | * Example output (this is printed to `console.log` unless the
|
446 | * {@link CostAnalyzer.Workload.silent} is `true`):
|
447 | * ```text
|
448 | * ✔ aws 128MB queue 15.385s 0.274σ $0.00003921
|
449 | * ✔ aws 192MB queue 10.024s 0.230σ $0.00003576
|
450 | * ✔ aws 256MB queue 8.077s 0.204σ $0.00003779
|
451 | * ▲ ▲ ▲ ▲ ▲ ▲
|
452 | * │ │ │ │ │ │
|
453 | * provider │ mode │ stdev average
|
454 | * │ │ execution estimated
|
455 | * memory │ time cost
|
456 | * size │
|
457 | * average cloud
|
458 | * execution time
|
459 | * ```
|
460 | *
|
461 | * The output lists the provider, memory size, ({@link CommonOptions.mode}),
|
462 | * average time of a single execution of the workload, the standard
|
463 | * deviation (in seconds) of the execution time, and average estimated cost
|
464 | * for a single run of the workload.
|
465 | *
|
466 | * The "execution time" referenced here is not wall clock time, but rather
|
467 | * execution time in the cloud function. The execution time does not include
|
468 | * any time the workload spends waiting locally. If the workload invokes
|
469 | * multiple cloud functions, their execution times will be summed even if
|
470 | * they happen concurrently. This ensures the execution time and cost are
|
471 | * aligned.
|
472 | */
|
473 | function analyze<T extends object, A extends string>(userWorkload: Workload<T, A>): Promise<Result<T, A>>;
|
474 | /**
|
475 | * Cost analyzer results for each workload and configuration.
|
476 | * @remarks
|
477 | * The `estimates` property has the cost estimates for each configuration.
|
478 | * See {@link CostAnalyzer.Estimate}.
|
479 | * @public
|
480 | */
|
481 | class Result<T extends object, A extends string> {
|
482 | /** The workload analyzed. */
|
483 | readonly workload: Required<Workload<T, A>>;
|
484 | /**
|
485 | * Cost estimates for each configuration of the workload. See
|
486 | * {@link CostAnalyzer.Estimate}.
|
487 | */
|
488 | readonly estimates: Estimate<A>[];
|
489 | /** @internal */
|
490 | constructor(
|
491 | /** The workload analyzed. */
|
492 | workload: Required<Workload<T, A>>,
|
493 | /**
|
494 | * Cost estimates for each configuration of the workload. See
|
495 | * {@link CostAnalyzer.Estimate}.
|
496 | */
|
497 | estimates: Estimate<A>[]);
|
498 | /**
|
499 | * Comma-separated output of cost analyzer. One line per cost analyzer
|
500 | * configuration.
|
501 | * @remarks
|
502 | * The columns are:
|
503 | *
|
504 | * - `memory`: The memory size allocated.
|
505 | *
|
506 | * - `cloud`: The cloud provider.
|
507 | *
|
508 | * - `mode`: See { CommonOptions.mode}.
|
509 | *
|
510 | * - `options`: A string summarizing other faast.js options applied to the
|
511 | * `workload`. See { CommonOptions}.
|
512 | *
|
513 | * - `completed`: Number of repetitions that successfully completed.
|
514 | *
|
515 | * - `errors`: Number of invocations that failed.
|
516 | *
|
517 | * - `retries`: Number of retries that were attempted.
|
518 | *
|
519 | * - `cost`: The average cost of executing the workload once.
|
520 | *
|
521 | * - `executionTime`: the aggregate time spent executing on the provider for
|
522 | * all cloud function invocations in the workload. This is averaged across
|
523 | * repetitions.
|
524 | *
|
525 | * - `executionTimeStdev`: The standard deviation of `executionTime`.
|
526 | *
|
527 | * - `billedTime`: the same as `exectionTime`, except rounded up to the next
|
528 | * 100ms for each invocation. Usually very close to `executionTime`.
|
529 | */
|
530 | csv(): string;
|
531 | }
|
532 | }
|