đ° DĂ©butants qui dĂ©couvrent AWS CDK, veuillez consulter mes articles prĂ©cĂ©dents un par un dans cette sĂ©rie.
Si au cas oĂč vous auriez manquĂ© mon article prĂ©cĂ©dent, retrouvez-le avec les liens ci-dessous.
đ Message prĂ©cĂ©dent original sur đ Dev Post
đ RepubliĂ© le post prĂ©cĂ©dent Ă đ dev Ă @aravindvcyber
Dans cet article, ajoutons une intĂ©gration simple utilisant des flux dynamodb pour effectuer des suppressions par lots dâobjets dans S3 que nous avons créés dans nos articles prĂ©cĂ©dents, et comprenons en quoi elle est plus performante quâun seul appel dâobjet de suppression S3.
Avantages dans cette approche đŠ
- Comme TTL dans dynamodb, nous avons des rĂšgles de cycle de vie qui vous permettent de supprimer les objets, mais cette approche illustrĂ©e ci-dessous est destinĂ©e Ă une architecture plus dĂ©terministe et Ă©vĂ©nementielle oĂč vous avez besoin dâun post-traitement lors du nettoyage de ces enregistrements.
- Bien quâun seul objet de suppression soit Ă©galement bon, lorsque nous avons un grand nombre dâenregistrements les uns aprĂšs les autres, cela crĂ©era trop dâappels dâAPI et de surcharge en latence.
- Les objets de suppression par lots nous aident Ă rĂ©duire le nombre de demandes dâAPI externes.
- RĂ©duction des pertes dâheures de calcul dues aux E/S externes dans une instance de mĂ©moire lourde pendant les temps dâinactivitĂ©.
- Ăvitez dâĂȘtre limitĂ© si nous avons atteint le dĂ©bit dĂ©fini pour le prĂ©fixe s3 Ă de trĂšs rares occasions
- Et il est Ă©galement possible que lambda expire si nous ne sommes pas prĂȘts Ă lâaugmenter
deleteObject
ne fournit pas de réponse complÚte pour les buckets non versionnés, alors quedeleteObjects
fournit également une réponse soignée avec les erreurs.
MĂ©thodes de cycle de vie du spoiler pour faire expirer automatiquement les Ă©lĂ©ments đ
Oui, tout comme TTL dans dynamodb, nous pourrions utiliser les mĂ©thodes de cycle de vie pour expirer automatiquement ou faire passer des objets vers dâautres classes de stockage dans s3. Mais bon, cette pensĂ©e est la meilleure stratĂ©gie Ă faire de cette maniĂšre. Chaque fois, nous finirons par avoir une fenĂȘtre beaucoup plus longue qui est nĂ©cessaire et nous lâoublierons et nous nous attendrons Ă ce quâelle se nettoie. Mais dans les deux derniers articles et celui-ci, nous essayons de notre mieux de configurer un moyen plus Ă©vĂ©nementiel pour effectuer ce nettoyage une fois que nous avons fini de traiter le message.
Cela peut Ă©galement ĂȘtre utilisĂ© comme derniĂšre option pour supprimer automatiquement certains artefacts orphelins aprĂšs une pĂ©riode dĂ©finie. Mais il a des objectifs diffĂ©rents et nous pourrons les couvrir peut-ĂȘtre dans un article ultĂ©rieur.
const stgMsgBucket = new s3.Bucket(this, 'stg-msg-bucket',{
bucketName: envParams.bucket.BucketName,
encryption: s3.BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.RETAIN,
lifecycleRules: [{
expiration: Duration.days(1),
prefix: "uploads",
id: "stg-msg-bucket-uploads-expiry-rule"
}]
});
putItem renvoie Ă©galement un lors de la crĂ©ation de lâobjet âïž
Activation des flux dynamodb dans notre table stgMessages đœ
Ce sera la table source censĂ©e gĂ©nĂ©rer les flux dynamodb. Mais la diffĂ©rence ici est que nous ne ciblerons que les flux gĂ©nĂ©rĂ©s lorsque des Ă©lĂ©ments sont supprimĂ©s. Nous allons donc essayer de supprimer le mĂȘme Ă©lĂ©ment clĂ© des compartiments s3 que nous avons initialement créés.
const stgMessages = new dynamodb.Table(this, "stgMessagesTable", {
tableName: process.env.stgMessagesTable,
sortKey: { name: "createdAt", type: dynamodb.AttributeType.NUMBER },
partitionKey: { name: "messageId", type: dynamodb.AttributeType.STRING },
encryption: dynamodb.TableEncryption.AWS_MANAGED,
readCapacity: 5,
writeCapacity: 5,
stream: dynamodb.StreamViewType.KEYS_ONLY,
});
Fonction de gestionnaire dans notre pile đ
Ici, nous avons dĂ©fini une fonction de gestionnaire que nous utiliserons dans notre rĂ©fĂ©rence pour accorder des privilĂšges et configurer la source de lâĂ©vĂ©nement, comme indiquĂ© ci-dessous.
const stgMessageStreamFunc = new lambda.Function(this, "stgMessageStreamFunc", {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromAsset("lambda"),
handler: "stg-message-stream.deleted",
logRetention: logs.RetentionDays.ONE_MONTH,
tracing: Tracing.ACTIVE,
layers: [nodejsUtils,nodejsXray],
environment: {
STAGING_MESSAGES_BUCKET_NAME: stgMsgBucket.bucketName,
},
});
stgMessageStreamFunc.applyRemovalPolicy(RemovalPolicy.DESTROY);
Accorder le privilĂšge deleteObject Ă la fonction de gestionnaire đŻ
stgMsgBucket.grantDelete(stgMessageStreamFunc);
Configuration de nos flux dynamodb en fonction de gestionnaire đ§
stgMessageStreamFunc.addEventSource(new DynamoEventSource(stgMessages, {
startingPosition: lambda.StartingPosition.LATEST,
batchSize:100,
maxBatchingWindow: Duration.seconds(60)
}))
Pour cela créons un nouveau fichier lambda/stg-message-stream.ts
avec un nom de mĂ©thode dâexportation deleted
Notez que cela ne ciblera que les eventName
comme REMOVE
. Cela nous aidera avec les clés des éléments de table qui sont supprimés et nous pourrions les supprimer en utilisant notre gestionnaire comme suit de deux maniÚres.
Gestionnaire de suppression dâobjet unique đș
Ici, nous utiliserons dâabord la suppression dâun seul objet et le comparerons avec la suppression dâun objet par lots, comme indiquĂ© ci-dessous.
exports.deleted = async function (event: any) {
console.log("Received stream:", JSON.stringify(event, undefined, 2));
const bucketName = process.env.STAGING_MESSAGES_BUCKET_NAME || "";
const result = Promise.all(
await event.Records.map(async (Record: DynamoDBStreams.Record) => {
console.log(JSON.stringify(Record, undefined, 2));
if (Record.eventName === "REMOVE") {
const key = `uploads/${Record.dynamodb?.Keys?.messageId.S}.json`;
console.log("keyId: ", key);
const bucketParams: DeleteObjectRequest = {
Bucket: bucketName,
Key: key,
};
try {
console.log("Deleting : ", bucketParams);
const deleteObjectOutput: DeleteObjectOutput = await s3
.deleteObject(bucketParams)
.promise();
console.log("Deleted : ", bucketParams);
Object.entries(deleteObjectOutput).forEach((item) =>
console.log({ item })
);
console.log(await s3.deleteObject(bucketParams).promise());
} catch (err) {
console.log("Error", err);
}
}
})
);
Object.entries(result).forEach((item) => console.log({ item }));
};
Supprimez une seule transaction deleteObject đ
Il ne faut pas plus dâune seconde pour supprimer lâobjet s3 la plupart du temps, le fait que je veux souligner ici est la façon dont la surcharge est rĂ©partie entre les diffĂ©rentes couches.
Et cela devrait expliquer comment nous utilisons un lot de 100 flux maximum Ă traiter Ă partir du mĂȘme gestionnaire. Les frais gĂ©nĂ©raux sont simplement partagĂ©s et entiĂšrement divulguĂ©s, nos couches de surveillance sont Ă©galement intĂ©grĂ©es en tant que couches et elles ont des frais gĂ©nĂ©raux.
Enfin, dĂ©couvrons la vĂ©ritable rĂ©partition ci-dessous. Vous pouvez donc voir quâil faut environ 50 ms Ă 300 ms pour terminer une seule demande dâAPI de suppression dâobjet s3, comme indiquĂ© ci-dessous.
Effets secondaires notables đ
Si nous ne les regroupons pas de maniĂšre appropriĂ©e, nous nous retrouverons dans les efforts nĂ©gatifs ci-dessous et quelques objets peuvent ĂȘtre orphelins si nous ne rĂ©essayons pas.
- perdre les heures de calcul en raison dâE/S externes
- peut-ĂȘtre Ă©tranglĂ© si nous avons atteint le dĂ©bit dĂ©fini pour le prĂ©fixe s3 en de rares occasions
- Et il est Ă©galement possible que lambda expire si nous ne sommes pas prĂȘts Ă lâaugmenter
Analyse du temps pris single delete đ
Vous pouvez constater que dans ces traces newrelic, la demande dâAPI est effectuĂ©e plusieurs fois lâune aprĂšs lâautre.
Vous pouvez dire que je peux les faire en parallĂšle, nous finirons Ă©galement par limiter la requĂȘte API au prĂ©fixe s3 lorsque nous crĂ©ons trop de requĂȘtes parallĂšles lorsque nous en exĂ©cutons plusieurs Ă la fois dans le pire des cas.
Gestionnaire de suppression dâobjets par lots đ
Puisque nous sommes conscients des points ci-dessus, effectuons une demande par lots maintenant et voyons le redressement.
exports.deleted = async function (event: any) {
console.log("Received stream:", JSON.stringify(event, undefined, 2));
const bucketName = process.env.STAGING_MESSAGES_BUCKET_NAME || "";
const keyMap: any[] = [];
const result = Promise.all(
await event.Records.map((Record: DynamoDBStreams.Record) => {
console.log(JSON.stringify(Record, undefined, 2));
if (Record.eventName === "REMOVE") {
const key = `uploads/${Record.dynamodb?.Keys?.messageId.S}.json`;
console.log("keyId: ", key);
keyMap.push(key);
}
})
);
if (keyMap.length > 0) {
const bulkParams: DeleteObjectsRequest = {
Bucket: bucketName,
Delete: {
Objects: [],
Quiet: false,
},
};
keyMap.map((key) => {
const object: ObjectIdentifier = {
Key: key,
};
bulkParams.Delete?.Objects?.push(object);
});
try {
console.log("Deleting Batch : ", bulkParams);
const deleteObjectsOutput: DeleteObjectsOutput = await s3
.deleteObjects(bulkParams)
.promise();
console.log("Deleted Batch : ", bulkParams);
Object.entries(deleteObjectsOutput).forEach((item) =>
console.log({ item })
);
} catch (err) {
console.log("Error", err);
}
}
Object.entries(result).forEach((item) => console.log({ item }));
};
Exemple de lot gĂ©nĂ©rĂ© Ă partir de mon test k6 đ
Ici, dans cet exemple, 26 Ă©lĂ©ments sont pris dans un seul lot. Mais notez que la taille de notre lot est de 100, mais il est Ă©galement possible que nos articles fassent Ă©galement partie de 2 sĂ©ries successives, en fonction de la fenĂȘtre dâinterrogation que nous avons dĂ©finie sur les annĂ©es 60.
Analyse du temps pris pour une suppression unique âïž
Lâappel de suppression par lots S3 peut prendre plus de temps que la suppression unique, mais le point Ă noter ici sera que nous pouvons Ă©viter la surcharge et la latence impliquĂ©es de maniĂšre exponentielle lorsque nous Ă©voluons cela, disons jusquâĂ 1000 objets.
Suppression des autres couches de surveillance entraßnant des frais généraux
Ceci conclut cet article.
Nous ajouterons plus de connexions à notre pile et la rendrons plus utilisable dans les prochains articles en créant de nouvelles constructions, alors pensez à suivre et à vous abonner à ma newsletter.
â Nous avons notre prochain article en serverless, consultez
đ Merci pour votre soutien ! đ
Ce serait formidable si vous aimez â Achetez-moi un cafĂ©, pour aider Ă stimuler mes efforts.
đ Message original sur đ Dev Post
đ RepubliĂ© Ă đ dev Ă @aravindvcyber
âïž AWS CDK 101 â â ïž Flux Dynamodb dĂ©clenchant batch deleteObjects S3
@hashnodeEn savoir plus sur ma pagehttps://t.co/CuYxnKI3Kg#TheHashnodeWriteathon#manuscrit #awscdk #aws #sans serveur #thwcloud-informatique https://t.co/3aoXjnp6lk
â Aravind V (@Aravind_V7) 21 mai 2022