
เมื่อผู้ใช้รายงานปัญหา: เมื่อเกิดข้อผิดพลาดเมื่อใช้ฟังก์ชันออนไลน์บางอย่าง จะสามารถระบุตำแหน่งได้อย่างรวดเร็วและแม่นยำได้อย่างไร? จะติดตามการปรับให้เหมาะสมอย่างมีประสิทธิภาพได้อย่างไรเมื่ออินเทอร์เฟซคำขอบางอย่างส่งคืนข้อมูลช้า
ตามที่เราทุกคนทราบดี เมื่อมีการร้องขอ บันทึกต่อไปนี้อาจจะถูกสร้างขึ้น:
1. AceesLog: บันทึกการเข้าถึงของผู้ใช้
2. ข้อยกเว้น: บันทึกข้อยกเว้นของโค้ด
3. SQL: บันทึกการสืบค้น SQL
4. ThirdParty: Third-
บันทึกการบริการของฝ่าย
จะติดตามบันทึกทั้งหมดที่สร้างโดยการร้องขอได้อย่างไร
วิธีการทั่วไปคือการใช้ requestId เป็นตัวระบุที่ไม่ซ้ำกัน
จากนั้นจึงเขียนมิดเดิลแวร์เพื่อแทรก requestId ลงในบริบท เมื่อจำเป็นต้องทำการบันทึก ให้นำออกจากบริบทสำหรับการพิมพ์
ในบริการของบริษัทอื่นและบันทึก SQL คุณต้องแทรก requestId ลงในบริบทด้วย requestId จะถูกส่งผ่านไปยังฟังก์ชันที่เกี่ยวข้องสำหรับการพิมพ์ การส่งผ่านทีละเลเยอร์นั้นยุ่งยากเกินไป และโค้ดก็ค่อนข้างรบกวนเช่นกัน
เป้าหมายของเราคือลดการบุกรุกโค้ด แทรกโค้ดเพียงครั้งเดียว และติดตามโค้ดโดยอัตโนมัติ
หลังจากการวิจัย async_hooks สามารถติดตามวงจรชีวิตของพฤติกรรมแบบอะซิงโครนัสได้ ในแต่ละทรัพยากรแบบอะซิงโครนัส (แต่ละคำขอเป็นทรัพยากรแบบอะซิงโครนัส) โดยมี 2 รหัส
ได้แก่ asyncId (ID วงจรชีวิตปัจจุบันของทรัพยากรแบบอะซิงโครนัส) trigerAsyncId (ทรัพยากรแบบอะซิงโครนัสหลัก) บัตรประจำตัว)
async_hooks จัดเตรียม hooks วงจรชีวิตต่อไปนี้เพื่อฟังทรัพยากรแบบอะซิงโครนัส:
asyncHook = async_hook.createHook({
//ฟังการสร้างทรัพยากรแบบอะซิงโครนัส init(asyncId,type,triggerAsyncId,resource){}
// ก่อนที่ฟังก์ชันการเรียกกลับทรัพยากรแบบอะซิงโครนัสจะเริ่มดำเนินการก่อน (asyncId){}
//หลังจากที่ฟังก์ชันเรียกกลับทรัพยากรแบบอะซิงโครนัสเริ่มดำเนินการ หลังจาก(asyncId){}
// ตรวจสอบการทำลายทรัพยากรแบบอะซิงโครนัส destroy(asyncId){}
}) จากนั้นหากเราทำการแมป แต่ละ asyncId จะแมปกับที่เก็บข้อมูล และ requestId ที่เกี่ยวข้องจะถูกจัดเก็บไว้ในที่เก็บข้อมูล ดังนั้น requestId ก็สามารถรับได้อย่างง่ายดาย
มันเพิ่งเกิดขึ้นที่ไลบรารี cls-hooked ได้รับการห่อหุ้มตาม async_hooks โดยคงสำเนาของข้อมูลไว้ในทรัพยากรแบบอะซิงโครนัสเดียวกันและจัดเก็บไว้ในรูปแบบของคู่คีย์-ค่า (หมายเหตุ: จำเป็นต้องใช้ async_hooked ในเวอร์ชันที่สูงกว่าของโหนด>=8.2.1) แน่นอนว่ายังมีการใช้งานอื่นๆ ในชุมชน เช่น cls-session, node-continuation-local-storage เป็นต้น
มาพูดถึงตัวอย่างของการใช้ cls-hooked ในโปรเจ็กต์ของฉัน:
/session.js สร้างพื้นที่เก็บข้อมูลที่มีชื่อ
const createNamespace = need('cls-hooked').createNamespace
const session = createNamespace('requestId-store')
module.exports = session /logger.js บันทึกการพิมพ์
const session = need('./session')
โมดูล.ส่งออก = {
ข้อมูล: (ข้อความ) =>
-
const requestId = session.get('requestId')
console.log(`requestId:${requestId}`, ข้อความ)
-
ข้อผิดพลาด: (ข้อความ) =>
-
const requestId = session.get('requestId')
console.error(`requestId:${requestId}`, ข้อความ)
-
} /sequelize.js sql เรียก logger เพื่อพิมพ์บันทึก
const logger = need("./logger")
ใหม่ Sequelize(
การบันทึก: ฟังก์ชั่น (sql, costtime) {
logger.error( `sql exe : ${sql} | ต้นทุนเวลา ${costtime} ms` );
} ) /app.js ตั้งค่า requestId ตั้งค่า requestId เพื่อส่งคืนส่วนหัวการตอบกลับ และบันทึกการเข้าถึงการพิมพ์
const session = need('./session')
const logger = ต้องการ('./logger')
ฟังก์ชัน async accessHandler (ctx ถัดไป)
-
const requestId = ctx.header['x-request-id'] ||.
const params = ctx.request.body ? JSON.stringify(ctx.request.body) : JSON.stringify(ctx.request.query)
//ตั้งค่า requestId session.run(() => { session.set('requestId', requestId)
logger.info(`url:${ctx.request.path}; params:${params}`) ถัดไป()
//ตั้งค่าส่วนหัวการตอบกลับ ctx.res.setHeader('X-Request-Id',requestId)
}) } ลองดูบันทึกเมื่อเส้นทางคำขอเป็น /home?a=1:
บันทึกการเข้าถึง:
requestId:79f422a6-6151-4bfd-93ca-3c6f892fb9ac url:/home;params:{"a": "1"}
บันทึก SQL:
รหัสคำขอ: 79f422a6-6151-4bfd-93ca-3c6f892fb9ac sql exe:
ดำเนินการแล้ว (ค่าเริ่มต้น): SELECT `id` FROM t_user คุณจะเห็นว่ารหัสคำขอบันทึกของลิงก์ทั้งหมดสำหรับคำขอเดียวกันนั้นเหมือนกัน หากมีการแจ้งเตือนที่ส่งไปยังแพลตฟอร์มการแจ้งเตือนในภายหลัง เราจะสามารถค้นหาลิงก์ทั้งหมดที่ดำเนินการโดยคำขอนี้โดยยึดตาม requestId
นักเรียนที่ระมัดระวังอาจสังเกตเห็นว่าฉันยังตั้งค่า requestId ในส่วนหัวการตอบกลับที่ส่งคืนโดยอินเทอร์เฟซ จุดประสงค์คือหากพบว่าคำขอตอบสนองช้าหรือมีปัญหา สามารถทราบ requestId ได้โดยตรงจากเบราว์เซอร์และวิเคราะห์
ฉันทำการทดสอบความเครียดในเครื่อง
นี่คือการเปรียบเทียบการใช้หน่วยความจำ:

มากกว่าการไม่ใช้ async_hook ประมาณ 10%
ไม่เป็นไรสำหรับระบบ QPS ของเราที่มีระบบ 100 ระดับ แต่หากเป็นบริการที่เกิดขึ้นพร้อมกันสูง เราอาจจะต้องพิจารณาอย่างรอบคอบ
PS. หากมีข้อผิดพลาดประการใด โปรดชี้แนะ หากไม่ชอบ โปรดอย่าแสดงความคิดเห็น