เมื่อพัฒนาระบบเซิร์ฟเวอร์เพื่อปรับให้เข้ากับคำขอข้อมูลขนาดใหญ่และพร้อมกันเรามักจะต้องจัดเก็บข้อมูลแบบอะซิงโครนัสโดยเฉพาะอย่างยิ่งเมื่อทำงานในระบบกระจาย ในเวลานี้เราไม่สามารถรอให้ฐานข้อมูลแทรกเพื่อส่งคืน ID อัตโนมัติเพื่อเรียกคืน แต่เราจำเป็นต้องสร้าง ID ที่ไม่ซ้ำกันทั่วโลกก่อนที่จะแทรกฐานข้อมูลโดยใช้ ID ที่ไม่ซ้ำกันทั่วโลก ในเกมเซิร์ฟเวอร์ ID ที่ไม่ซ้ำกันทั่วโลกสามารถใช้สำหรับการรวมเซิร์ฟเวอร์ในอนาคตและจะไม่มีความขัดแย้งที่สำคัญ ในอนาคตในกรณีที่มีการเติบโตของธุรกิจฐานข้อมูลและตารางแยกสามารถนำไปใช้ได้ ตัวอย่างเช่นรายการของผู้ใช้จะต้องอยู่ในเศษเดียวกันและเศษนี้อาจถูกกำหนดตามค่าช่วงของ ID ผู้ใช้เช่น ID ผู้ใช้ที่มีรหัสผู้ใช้มากกว่า 1,000 และน้อยกว่า 100,000 ในเศษ ปัจจุบันมีการใช้งานทั่วไปต่อไปนี้:
1. uuid ของ Java เอง
uuid.randomuuid (). toString () สามารถสร้างได้ในพื้นที่ผ่านโปรแกรมบริการและการสร้าง ID ไม่ได้ขึ้นอยู่กับการใช้งานฐานข้อมูล
ข้อดี:
สร้าง ID ในพื้นที่และไม่จำเป็นต้องมีการโทรจากระยะไกล
โลกเป็นคนเดียวที่ไม่ได้ทำซ้ำ
ความสามารถในการขยายแนวนอนนั้นดีมาก
ข้อเสีย:
ID มี 128 บิตซึ่งใช้พื้นที่ขนาดใหญ่และจำเป็นต้องจัดเก็บเป็นประเภทสตริงและประสิทธิภาพการทำดัชนีต่ำมาก
ID ที่สร้างขึ้นไม่มีการประทับเวลาและแนวโน้มไม่สามารถรับประกันได้ว่าจะเพิ่มขึ้น เป็นการยากที่จะพึ่งพาเมื่อแบ่งฐานข้อมูลฐานข้อมูล
2. วิธีการที่ใช้ Redis-based
Redis เองดำเนินการเธรดเดี่ยวและ Incl ทำให้มั่นใจได้ว่าการดำเนินการที่เพิ่มขึ้นแบบอะตอม นอกจากนี้ยังรองรับการตั้งค่าขนาดขั้นตอนที่เพิ่มขึ้น
ข้อดี:
มันง่ายต่อการปรับใช้และใช้งานง่าย คุณจะต้องโทรหา Redis API เท่านั้น
เซิร์ฟเวอร์หลายเครื่องสามารถแบ่งปันบริการ Redis เพื่อลดเวลาในการพัฒนาของข้อมูลที่ใช้ร่วมกัน
Redis สามารถนำไปใช้ในกลุ่มเพื่อแก้ปัญหาความล้มเหลวจุดเดียว
ข้อเสีย:
หากระบบมีขนาดใหญ่เกินไปการร้องขอบริการหลายรายการไปยัง Redis ในเวลาเดียวกันจะทำให้เกิดปัญหาคอขวด
3. การแก้ปัญหาจากการสั่นไหว
โซลูชันนี้ขึ้นอยู่กับ ID การปรับตัวอัตโนมัติของฐานข้อมูลซึ่งใช้ฐานข้อมูลแยกต่างหากสำหรับการสร้าง ID คุณสามารถค้นหารายละเอียดออนไลน์ได้ โดยส่วนตัวแล้วฉันคิดว่ามันค่อนข้างลำบากในการใช้งานและไม่แนะนำให้ใช้
4. เกล็ดหิมะ Twitter
Snowflake เป็นอัลกอริทึมการสร้าง ID แบบกระจายซึ่งเป็นโอเพ่นซอร์สบน Twitter แนวคิดหลักของมันคือการสร้าง ID ประเภทยาวโดยใช้ 41 บิตเป็นจำนวนมิลลิวินาที 10 บิตเป็นหมายเลขเครื่องและ 12 บิตเป็นหมายเลขซีเรียลภายในมิลลิวินาที อัลกอริทึมนี้สามารถสร้าง ID ได้มากถึง 1,000*(2^12) ต่อวินาทีต่อเครื่องซึ่งประมาณ 400W ซึ่งสามารถตอบสนองความต้องการของธุรกิจได้อย่างเต็มที่
ตามความคิดของอัลกอริทึม Snowflake เราสามารถสร้าง ID ที่ไม่ซ้ำกันทั่วโลกของเราเองตามสถานการณ์ทางธุรกิจของเรา เนื่องจากความยาวของประเภทยาวใน Java คือ 64bits ID ที่เราออกแบบจึงจำเป็นต้องควบคุมที่ 64bits
ข้อดี: ประสิทธิภาพสูง, เวลาแฝงต่ำ; แอปพลิเคชันอิสระ เป็นระเบียบตามเวลา
ข้อเสีย: จำเป็นต้องมีการพัฒนาและการปรับใช้อิสระ
ตัวอย่างเช่น ID ที่เราออกแบบมีข้อมูลต่อไปนี้:
- 41 บิต: การประทับเวลา | 3 บิต: พื้นที่ | 10 บิต: หมายเลขเครื่อง | 10 บิต: หมายเลขซีเรียล |
รหัส Java ที่สร้าง ID ที่ไม่ซ้ำกัน:
/*** ตัวสร้าง ID ที่กำหนดเอง* กฎการสร้าง ID: ID สูงสุด 64 บิต ** | 41 บิต: การประทับเวลา (MS) | 3 บิต: พื้นที่ (ห้องคอมพิวเตอร์) | 10 บิต: หมายเลขเครื่อง | 10 บิต: หมายเลขซีเรียล |*/คลาสสาธารณะ GameUUID {// เวลาอ้างอิง Twepoch ยาวส่วนตัว = 1288834974657L; // thu, 04 พ.ย. 2010 01:42:54 gmt // ธงภูมิภาคตัวเลขหลักสุดท้ายคงที่ regionidbits ยาวคงที่ = 3l; // เครื่องระบุตัวตนของเครื่องจักรส่วนตัวสุดท้ายคงที่ long workeridbits = 10l; // ตัวเลขหมายเลขส่วนตัว ค่าสูงสุดของ ID เครื่องจักรส่วนตัวสุดท้ายคงที่ Long MaxWorkerId = -1l ^ (-1l << WorkerIdBits); // ค่าสูงสุดของหมายเลขซีเรียลหมายเลขส่วนตัวสุดท้ายคงที่สุดท้ายคงที่ความยาวคง Static Long regionIdShift = SequenceBits + WorkerIdBits; // เวลาถูกเลื่อนไปทางซ้ายโดย 23 บิตส่วนตัวสุดท้ายคงที่ระยะยาวคงที่การจับเวลาระยะยาว = SequenceBits + WorkerIdBits + regionIdbits; LastTimestamp ส่วนตัวคงที่ = -1L; ลำดับความยาวส่วนตัว = 0L; ส่วนตัวรอบสุดท้าย ภาคเอกชนรอบสุดท้าย regionid; public gameuuid (Long Workerid, Long regionID) {// ถ้าอยู่นอกช่วงข้อยกเว้นจะถูกโยนลงถ้า (workerid> maxworkerid || workerid <0) {โยน unlegalargumentException ใหม่ ("ID คนงานไม่สามารถมากกว่า %d หรือน้อยกว่า 0"); %d หรือน้อยกว่า 0 ");} this.workerid = workerId; this.regionId = regionId;} public gameuuid (Long Workerid) {// ถ้าอยู่นอกช่วงจะถูกโยนลงถ้า (workerid> maxworkerid || workerid <0) {โยน unlegalargumentException ใหม่ ("ID คนงานไม่สามารถมากกว่า %d หรือน้อยกว่า 0"); this.nextid (false, 0);}/*** รหัสจริงที่สร้างขึ้นโดย @param ispadding* @param busid* @return*/ส่วนตัวซิงโครไนซ์ยาว NextId (บูลีน ispadding, busid ยาว) {timestamp ยาว = timeGen () {โยนข้อยกเว้นใหม่ ("นาฬิกาย้ายไปข้างหลังปฏิเสธที่จะสร้าง ID สำหรับ" + (LastTimestamp - timestamp) + "ล้านมอนิกอน");} catch (Exception e) {E.printstacktrace ();}} // ถ้าเวลาสุดท้ายคือเวลาเดียวกัน {// ลำดับเพิ่มขึ้นด้วยตัวเองเนื่องจากลำดับเป็นเพียง 10 บิตมันจะรวมกับ sequenceMask และลบลำดับบิตสูง = (ลำดับ + 1) & sequenceMask; // ตัดสินว่ามันล้นนั่นคือเกิน 1024 ในทุกมิลลิวินาที เมื่อมันคือ 1024 มันจะรวมกับ sequencemask และลำดับเท่ากับ 0if (sequence == 0) {// สปินรอจนกระทั่งเวลาต่อไปมิลลิวินาทีถัดไป = tailnextmillis (LastTimestamp);}} อื่น ๆ อีกครั้ง // เพื่อให้แน่ใจว่า Mantissa นั้นสุ่มมากขึ้นตั้งค่าหมายเลขสุ่มในลำดับบิตสุดท้าย = ใหม่ securerandom (). nextint (10);} lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampleftshift) | (paddingnum << regionidshift) | (WorkerId << WorkerIdShift) | Sequence;} // ป้องกันเวลาการสร้างที่เล็กกว่าครั้งก่อน (เนื่องจากปัญหาเช่นการโทรกลับ NTP) และรักษาแนวโน้มที่เพิ่มขึ้นต่อย tailnextmillis ยาว (สุดท้าย lasttimestamp) {timestamp ยาว {timestamp; TimeGen () {return system.currentTimeMillis ();}}บางสิ่งที่ควรทราบเมื่อใช้วิธีการที่กำหนดเอง:
เพื่อรักษาแนวโน้มการเติบโตจึงจำเป็นต้องหลีกเลี่ยงเวลาของเซิร์ฟเวอร์บางตัว แต่เนิ่นๆและเซิร์ฟเวอร์บางตัวสายดังนั้นเวลาของเซิร์ฟเวอร์ทั้งหมดจะต้องถูกควบคุมและเวลาที่เซิร์ฟเวอร์เวลา NTP โทรกลับไปยังเซิร์ฟเวอร์ เมื่อข้ามมิลลิวินาทีหมายเลขซีเรียลจะถึง 0 เสมอซึ่งจะทำให้ ID มากขึ้นด้วยหมายเลขซีเรียล 0 ส่งผลให้ ID ที่ไม่สม่ำเสมอหลังจากโมดูโลดังนั้นหมายเลขซีเรียลไม่ได้อยู่ใน 0 ทุกครั้ง แต่หมายเลขสุ่มจาก 0 ถึง 9
เราสามารถเลือกวิธีการที่กล่าวถึงข้างต้นตามความต้องการของเรา ในการพัฒนาเซิร์ฟเวอร์เกมคุณสามารถเลือกตามประเภทเกมของคุณเองเช่นเกมมือถือและคุณสามารถใช้วิธี Redis อย่างง่ายซึ่งง่ายและไม่ง่ายที่จะทำผิดพลาด เนื่องจากจำนวน ID ใหม่ที่สร้างขึ้นโดยเซิร์ฟเวอร์เดี่ยวในเกมประเภทนี้ไม่ใหญ่เกินไปจึงสามารถตอบสนองความต้องการได้อย่างสมบูรณ์ สำหรับเซิร์ฟเวอร์เกมโลกขนาดใหญ่พวกมันจะกระจายเป็นหลักดังนั้นคุณสามารถใช้เกล็ดหิมะได้ รหัสเกล็ดหิมะข้างต้นเป็นเพียงตัวอย่างและจำเป็นต้องปรับแต่งตามความต้องการของคุณดังนั้นจึงมีปริมาณการพัฒนาเพิ่มเติมและคุณควรให้ความสนใจกับข้อควรระวังข้างต้น
ข้างต้นเป็นบทสรุปของวิธีการใช้รหัส Java เพื่อใช้เซิร์ฟเวอร์เกมเพื่อสร้าง ID ที่ไม่ซ้ำกันทั่วโลกตามรหัส Java ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับทุกคนในเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!