ข้อมูลฐานข้อมูลในโครงการที่เพิ่งเปิดตัวกำลังเข้าใกล้ความอิ่มตัว ข้อมูลตารางที่ใหญ่ที่สุดอยู่ใกล้กับ 3000W และมีหลายตารางที่มีข้อมูลนับล้าน โครงการกำหนดให้เวลาในการอ่านข้อมูลต้องไม่เกิน 0.05 วินาที แต่สถานการณ์จริงไม่เป็นไปตามข้อกำหนด อธิบายการจัดทำดัชนีและการใช้เทคโนโลยีแคช Redis และ Ehcache ไม่สามารถตอบสนองความต้องการได้อีกต่อไป ดังนั้นเราจึงเริ่มใช้เทคโนโลยีการอ่านและเขียน บางทีเมื่อปริมาณข้อมูลเกินกว่า 100 ล้านหรือมากกว่าในอนาคตเราต้องพิจารณาการปรับใช้ฐานข้อมูลแบบกระจาย อย่างไรก็ตามในปัจจุบันการอ่านและเขียนการแยก + แคช + ดัชนี + พาร์ติชันตาราง + การเพิ่มประสิทธิภาพ SQL + การปรับสมดุลโหลดสามารถตอบสนองการทำงานของการสืบค้น 100 ล้านปริมาณข้อมูล ลองมาดูขั้นตอนในการใช้ฤดูใบไม้ผลิเพื่อให้ได้การอ่านและเขียนแยก:
1. พื้นหลัง
แอปพลิเคชันทั่วไปของเราคือการ "อ่านเพิ่มเติมและเขียนน้อยลง" สำหรับฐานข้อมูลซึ่งหมายความว่าความดันในฐานข้อมูลเพื่ออ่านข้อมูลค่อนข้างสูง แนวคิดหนึ่งคือการใช้โซลูชันคลัสเตอร์ฐานข้อมูล
หนึ่งในนั้นคือห้องสมุดหลักซึ่งรับผิดชอบในการเขียนข้อมูลซึ่งเราเรียกว่า: การเขียนห้องสมุด;
คนอื่น ๆ ทั้งหมดมาจากห้องสมุดซึ่งรับผิดชอบในการอ่านข้อมูลซึ่งเราเรียกว่า: การอ่านไลบรารี;
ดังนั้นข้อกำหนดสำหรับเราคือ:
1. ข้อมูลของไลบรารีอ่านและไลบรารีการเขียนมีความสอดคล้องกัน (นี่เป็นปัญหาที่สำคัญมากการประมวลผลตรรกะทางธุรกิจควรดำเนินการในชั้นบริการและไม่อยู่ในระดับ DAO หรือ MAPPER)
2. เมื่อเขียนข้อมูลคุณต้องเขียนลงในห้องสมุดการเขียน
3. คุณต้องไปที่ไลบรารีการอ่านเพื่ออ่านข้อมูล
2. แผน
มีสองวิธีแก้ปัญหาการแยกการอ่านและเขียน: โซลูชันแอปพลิเคชันเลเยอร์และโซลูชันมิดเดิลแวร์
2.1. โซลูชันเลเยอร์แอปพลิเคชัน:
ข้อได้เปรียบ:
1. แหล่งข้อมูลหลายแหล่งง่ายต่อการสลับและเสร็จสมบูรณ์โดยโปรแกรมโดยอัตโนมัติ
2. ไม่จำเป็นต้องมีมิดเดิลแวร์
3. ในทางทฤษฎีสนับสนุนฐานข้อมูลใด ๆ
ข้อบกพร่อง:
1. เสร็จสิ้นโดยโปรแกรมเมอร์และการดำเนินงานและการบำรุงรักษาไม่เกี่ยวข้อง
2. ไม่สามารถเพิ่มแหล่งข้อมูลแบบไดนามิกได้
2.2. โซลูชันมิดเดิลแวร์
ข้อดีและข้อเสีย:
ข้อได้เปรียบ:
1. โปรแกรมต้นฉบับสามารถบรรลุการอ่านและเขียนโดยไม่มีการเปลี่ยนแปลงใด ๆ
2. การเพิ่มแหล่งข้อมูลแบบไดนามิกไม่จำเป็นต้องรีสตาร์ทโปรแกรม
ข้อบกพร่อง:
1. โปรแกรมพึ่งพามิดเดิลแวร์ซึ่งทำให้ยากต่อการสลับฐานข้อมูล
2. มิดเดิลแวร์ใช้เป็นตัวแทนการขนส่งและประสิทธิภาพได้ลดลง
3. ใช้สปริงเพื่อใช้งานตามเลเยอร์แอปพลิเคชัน
3.1. หลักการ
ก่อนที่จะเข้าสู่บริการให้ใช้ AOP เพื่อตัดสินไม่ว่าจะใช้ห้องสมุดเขียนหรือห้องสมุดอ่านพื้นฐานการตัดสินสามารถตัดสินได้ตามชื่อวิธีเช่นที่เริ่มต้นด้วยการสืบค้นค้นหา, Get, ฯลฯ และห้องสมุดเขียนอื่น ๆ
3.2. DynamicDataSource
นำเข้า org.springframework.jdbc.datasource.lookup.abstractroutingDatasource;/*** กำหนดแหล่งข้อมูลแบบไดนามิกและใช้ abstractroutingDataSource ที่จัดทำโดยการรวมสปริง คุณจะต้องใช้เมธอด decinecurrentLookupkey * * เนื่องจาก DynamicDataSource เป็น Singleton และ Thread-Insecure, ThreadLocal จึงถูกใช้เพื่อให้แน่ใจว่ามีความปลอดภัยจากด้ายซึ่งเสร็จสมบูรณ์โดย DynamicDataSourceHolder * * @author Zhijun * */คลาสสาธารณะ DynamicDataSource ขยาย AbstractroutingDataSource {@Override วัตถุที่ได้รับการป้องกันการกำหนดค่าความปลอดภัย () {// ใช้ DynamicDataSourceHolder - 3.3. DynamicDataSourceholder
/** * * ใช้เทคโนโลยี ThreadLocal เพื่อบันทึกคีย์ของแหล่งข้อมูลในเธรดปัจจุบัน * * @author Zhijun * */คลาสสาธารณะ DynamicDataSourceHolder {// เขียนแหล่งข้อมูลที่สอดคล้องกับห้องสมุด // อ่านแหล่งข้อมูลที่สอดคล้องกับ Library Private Private String Slave = "Slave"; // ใช้ ThreadLocal เพื่อบันทึกแหล่งข้อมูลของเธรดปัจจุบันแบบคงที่แบบคงที่ threadLocal <String> Holder = ใหม่ ThreadLocal <String> (); / ** * ตั้งค่าคีย์แหล่งข้อมูล * @param คีย์ */ โมฆะสาธารณะคงที่ putdataSourceKey (คีย์สตริง) {holder.set (คีย์); } / ** * รับคีย์แหล่งข้อมูล * @return * / สตริงคงที่สาธารณะ getDataSourceKey () {return holder.get (); } / *** มาร์กอัปเขียนไลบรารี* / โมฆะคงที่สาธารณะ markmaster () {putdataSourceKey (อาจารย์); } / *** มาร์กอัปอ่านห้องสมุด* / โมฆะสาธารณะคงที่ markslave () {putdataSourceKey (ทาส); - 3.4. DataSourceAspect
นำเข้า org.apache.commons.lang3.Stringutils; นำเข้า org.aspectj.lang.joinpoint;/** * กำหนดส่วน AOP ของแหล่งข้อมูลและตัดสินว่าถึงเวลาที่จะอ่านไลบรารีหรือเขียนห้องสมุด * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * โมฆะสาธารณะก่อน (จุด JoinPoint) {// รับสตริงชื่อวิธีการที่ดำเนินการในปัจจุบันเมธอด name = point.getSignature (). getName (); if (isslave (methodName)) {// mark เป็น read library dynamicDataSourceholder.markslave (); } else {// mark เป็น Library Library DynamicDataSourceHolder.markmaster (); }} / ** * พิจารณาว่าเป็นไลบรารีอ่าน * * @param methodname * @return * / บูลีนส่วนตัว Isslave (String MethodName) {// ชื่อเมธอดเริ่มต้นด้วยการสืบค้น, ค้นหา, รับ, ส่งคืน Stringutils.startswithany (เมธอด -3.5. กำหนดค่าแหล่งข้อมูล 2 แหล่ง
3.5.1. jdbc.properties
jdbc.master.driver = com.mysql.jdbc.driverjdbc.master.url = jdbc: mysql: //127.0.0.1: 3306/mybatis_1128? useunicode = True & CH aracterencoding = utf8 & autoreconnect = true & allowmultiqueries = truejdbc.master.username = rootjdbc.master.password = 123456jd bc.slave01.driver = com.mysql.jdbc.driverjdbc.slave01.url = jdbc: mysql: //127.0.0.1: 3307/mybatis_1128? aracterencoding = utf8 & autoreconnect = true & allowmultiqueries = truejdbc.slave01.username = rootjdbc.slave01.password = 123456
3.5.2. กำหนดพูลการเชื่อมต่อ
<!-กำหนดค่าพูลการเชื่อมต่อ-> <bean id = "masterDataSource" destroy-method = "close"> <!-ไดรเวอร์ฐานข้อมูล-> <property name = "driverclass" value = "$ {jdbc.master.driver}" /> <! <!-ชื่อผู้ใช้ของฐานข้อมูล-> <property name = "ชื่อผู้ใช้" value = "$ {jdbc.master.username}" /> <!-รหัสผ่านของฐานข้อมูล-> <property name = "password" value = "$ {jdbc.master.passwall}" /> < หน่วยเป็นเศษส่วน ค่าเริ่มต้นคือ 240 ถ้าคุณต้องการยกเลิกตั้งค่าเป็น 0-> <ชื่อคุณสมบัติ = "IdleConnectionTestPeriod" value = "60" /> <!-จำนวนการเชื่อมต่อสูงสุดที่ไม่ได้ใช้ในพูลเชื่อมต่อ หน่วยเป็นเศษส่วน ค่าเริ่มต้นคือ 60 ถ้าคุณต้องการอยู่รอดตลอดไปให้ตั้งค่าเป็น 0-> <property name = "idleMaxage" value = "30" /> <!-จำนวนสูงสุดของการเชื่อมต่อต่อพาร์ติชัน-> <name property = "MaxConnectionperpartition" ค่า maxConnections = "150" /> <! จำนวนขั้นต่ำของการเชื่อมต่อต่อพาร์ติชัน-> <property name = "MaxConnectionsPerPartition" value = "150" /> <!-จำนวนการเชื่อมต่อขั้นต่ำต่อพาร์ติชัน-> <ชื่อคุณสมบัติ = "minConnectionperPartition" value "5" /> </epean> <! <property name = "driverclass" value = "$ {jdbc.slave01.driver}" /> <!-jdbcurl สำหรับไดรเวอร์ที่เกี่ยวข้อง-> <property name = "jdbcurl" value = "$ {jdbc.slave01.url}" /> <! value = "$ {jdbc.slave01.username}" /> <!-รหัสผ่านของฐานข้อมูล-> <ชื่อคุณสมบัติ = "รหัสผ่าน" value = "$ {jdbc.slave01.password}" /> <! หน่วยเป็นเศษส่วน ค่าเริ่มต้นคือ 240 ถ้าคุณต้องการยกเลิกตั้งค่าเป็น 0-> <property name = "IdleConnectionTestPeriod" value = "60" /> <!-เวลาการอยู่รอดสูงสุดของลิงก์ที่ไม่ได้ใช้ในพูลการเชื่อมต่อ หน่วยเป็นเศษส่วน ค่าเริ่มต้นคือ 60 ถ้าคุณต้องการอยู่รอดตลอดไปให้ตั้งค่าเป็น 0-> <property name = "idleMaxage" value = "30" /> <!-จำนวนสูงสุดของการเชื่อมต่อต่อพาร์ติชัน-> <property name = "MaxConnectionsPertition" Name = "Name-name =" 150 " />> <! 3.5.3. กำหนดแหล่งข้อมูล
<!-กำหนดแหล่งข้อมูลและใช้แหล่งข้อมูลที่คุณใช้งาน-> <bean id = "DataSource"> <!-ตั้งแหล่งข้อมูลหลายแหล่ง-> <property name = "TargetDataSources"> <แผนที่ key-type = "java.lang.string"> <! key = "slave" value-ref = "slave01datasource"/> </map> </คุณสมบัติ> <!-ตั้งค่าแหล่งข้อมูลเริ่มต้นที่นี่ไลบรารีการเขียนเริ่มต้น-> <property name = "defaultTargetDataSource" ref = "MasterDataSource"/> </epean>
3.6. กำหนดค่าการจัดการธุรกรรมและเปลี่ยนพื้นผิวแหล่งข้อมูลแบบไดนามิก
3.6.1. การกำหนดผู้จัดการธุรกรรม
<!-ตัวจัดการธุรกรรมนิยาม-> <bean id = "transactionManager"> <property name = "DataSource" ref = "DataSource" /> </ebean>
3.6.2. กำหนดนโยบายการทำธุรกรรม
<!-กำหนดนโยบายการทำธุรกรรม-> <tx: คำแนะนำ id = "txAdvice" ธุรกรรม-ผู้จัดการ = "transactionManager"> <tx: คุณลักษณะ> <!-กำหนดวิธีการสอบถามคือการอ่านอย่างเดียว-> <tx: method name = "read-on /" name* rest-only = "true" /> <!-ห้องสมุดหลักดำเนินการและพฤติกรรมการแพร่กระจายการทำธุรกรรมถูกกำหนดเป็นพฤติกรรมเริ่มต้น-> <tx: method name = "save*" การแพร่กระจาย = "จำเป็น" /> <tx: method = "update*" การแพร่กระจาย = "ต้องการ" name = "*"/> </tx: แอตทริบิวต์> </tx: คำแนะนำ>
3.6.3. กำหนดแง่มุม
<!-กำหนดโปรเซสเซอร์ส่วน AOP-> <bean id = "DataSourceAspect" /> <aop: config> <!-กำหนดส่วน, วิธีการทั้งหมดของบริการทั้งหมด-> <aop: pointcut id = "txpointcut" expression = "การดำเนินการ <AOP: คำแนะนำที่ปรึกษา-ref = "txadvice" pointcut-ref = "txpointcut" /> <!-ใช้ส่วนกับโปรเซสเซอร์ส่วนที่กำหนดเอง -9999 ทำให้มั่นใจได้ว่าส่วนมีการดำเนินการลำดับความสำคัญสูงสุด-> </aop: แง่มุม> </aop: config>
4. ปรับปรุงการใช้งานส่วนและใช้การจับคู่กฎการทำธุรกรรม
ในการใช้งานก่อนหน้านี้เราจะจับคู่ชื่อวิธีแทนที่จะใช้คำจำกัดความในนโยบายการทำธุรกรรมและเราจะใช้การจับคู่กฎในนโยบายการจัดการธุรกรรม
4.1. ปรับปรุงการกำหนดค่า
<!-กำหนดโปรเซสเซอร์ส่วน AOP-> <bean id = "DataSourceAspect"> <!-ระบุนโยบายการทำธุรกรรม-> <property name = "txAdvice" ref = "txAdvice"/> <!-ระบุคำนำหน้าของวิธีการของทาส
4.2. ปรับปรุงการใช้งาน
นำเข้า java.lang.reflect.field; นำเข้า java.util.arraylist; นำเข้า java.util.list; นำเข้า java.util.map นำเข้า org.apache.commons.lang3.stringutils; นำเข้า org.aspectj.lang.lang.joinpoint; org.springframework.transaction.interceptor.TransactionAttribute; นำเข้า org.springframework.transaction.interceptor.TransactionAttributesource; นำเข้า org.springframework.Transaction.interceptor.TransactionInterceptor; org.springframework.util.reflectionutils;/*** กำหนดส่วน AOP ของแหล่งข้อมูลซึ่งควบคุมว่าจะใช้ต้นแบบหรือทาส * * หากนโยบายการทำธุรกรรมได้รับการกำหนดค่าในการจัดการธุรกรรมวิธีการทำเครื่องหมายแบบอ่านอย่างเดียวในนโยบายการทำธุรกรรมที่กำหนดค่าคือการใช้ทาสและอื่น ๆ ใช้มาสเตอร์ * * หากไม่มีนโยบายในการกำหนดค่าการจัดการธุรกรรมหลักการของการจับคู่ชื่อวิธีจะถูกนำมาใช้และใช้ทาสเป็นเริ่มต้นด้วยการสืบค้นค้นหาและรับและวิธีการอื่น ๆ จะถูกใช้เป็นหลัก * * @author Zhijun * */DataSourceAspect คลาสสาธารณะ {รายการส่วนตัว <String> SlaveMetHodPattern = arrayList ใหม่ <String> (); สตริงสุดท้ายคงที่ส่วนตัว [] defaultSlaveMethodStart = สตริงใหม่ [] {"Query", "ค้นหา", "get"}; สตริงส่วนตัว [] Slavemethodstart; / ** * อ่านนโยบายในการจัดการธุรกรรม * * @param txadvice * @throws ยกเว้น */ @suppresswarnings ("unchecked") โมฆะสาธารณะ settxadvice (transactionInterceptor txadvice) โยนข้อยกเว้น {ถ้า (txadvice == null) {// นโยบายการจัดการธุรกรรม } // รับข้อมูลการกำหนดค่านโยบายจาก TxAdvice TransactionAtTributesource TransactionAtTributesource = TxAdvice.getTransactionAtTributesource (); if (! (TransactionAtTributesource อินสแตนซ์ของ namematchTransactionAtTributesource)) {return; } // ใช้เทคโนโลยีการสะท้อนกลับเพื่อรับค่าแอตทริบิวต์ NAMEMAP ใน NamematchTransactionAtTributesource Object NamematchTransactionAtTributesource MatchTransactionAtTributesource = (namematchTransactionAtTributesource) TransactionAtTributesource; Field Namemapfield = ReflectionUtils.findfield (NamematchTransactionAtTributesource.class, "Namemap"); Namemapfield.setAccessible (จริง); // ตั้งค่าฟิลด์นี้เพื่อเข้าถึง // รับค่าของ namemap <string, transactionAttribute> map = (แผนที่ <สตริง, transactionAttribute>) namemapfield.get (matchTransactionAtTributesource); // transactionAttribute> รายการ: map.entryset ()) {ถ้า (! entry.getValue (). isReadonly ()) {// หลังจากการตัดสินนโยบายแบบอ่านอย่างเดียวจะถูกกำหนดก่อนที่จะเพิ่มลงใน SlaveMethodpattern ดำเนินการต่อ; } slavemethodpattern.add (entry.getKey ()); }} / *** ดำเนินการก่อนที่จะป้อนวิธีการบริการ* @param point face object* / public void ก่อน (จุด Joinpoint) {// รับเมธอดวิธีการที่ดำเนินการในปัจจุบันเมธอด Name = point.getSignature (). getName (); บูลีน isslave = false; if (slavemethodpattern.isempty ()) {// ไม่มีนโยบายการทำธุรกรรมที่กำหนดค่าในคอนเทนเนอร์สปริงปัจจุบันและวิธีการจับคู่ชื่อวิธี isslave = isslave (เมธอดชื่อ); } else {// ใช้กฎนโยบายเพื่อให้ตรงกับ (String mappedName: SlaveMetHodPattern) {ถ้า (isMatch (methodName, mappedName)) {isslave = true; หยุดพัก; }}}} if (isslave) {// mark เป็น read library dynamicDataSourceholder.markslave (); } else {// mark เป็น Library Library DynamicDataSourceHolder.markmaster (); }} / ** * ตรวจสอบว่าเป็นไลบรารีอ่าน * * @param methodName * @return * / บูลีนส่วนตัว isslave (สตริงเมธอดชื่อ) {// ชื่อเมธอดเริ่มต้นด้วยการสืบค้น, ค้นหา, รับ stringutils.startswithany (เมธอด } /** * การจับคู่ไวด์การ์ด * * ส่งคืนหากชื่อวิธีที่กำหนดตรงกับชื่อที่แมป *<p>*การใช้งานเริ่มต้นจะตรวจสอบ "xxx*", "*xxx" และ "*xxx*" จับคู่เช่นเดียวกับความเท่าเทียมกัน*โดยตรง สามารถแทนที่ในคลาสย่อย * * @param methodname ชื่อเมธอดของคลาส * @param mappedName ชื่อใน descriptor * @return ถ้าชื่อตรงกับ * @See org.springFramework.util.patternMatchutils#simpleMatch (สตริง, สตริง) * patternmatchutils.simplematch (mappedName, methodName); } / *** คำนำหน้าชื่อวิธีของผู้ใช้ที่ระบุ Slave* @param slavemethodstart* / โมฆะสาธารณะ setslaveMethodstart (สตริง [] slavemethodstart) {this.slaveMethodstart = slaveMethodStart; } สตริงสาธารณะ [] getSlaveMethodStart () {ถ้า (this.slaveMethodStart == null) {// ไม่ได้ระบุให้ใช้ค่าเริ่มต้นค่าเริ่มต้นเริ่มต้นเริ่มต้น } return slavemethodstart; -5. การดำเนินการของอาจารย์หนึ่งคนและทาสหลายคน
ในสถานการณ์การใช้งานจริงหลายครั้งเราใช้สถาปัตยกรรม "One Master, Multiple Slave" ดังนั้นตอนนี้เราสนับสนุนสถาปัตยกรรมนี้และในปัจจุบันจำเป็นต้องปรับเปลี่ยน DynamicDataSource เท่านั้น
5.1. การดำเนินการ
นำเข้า java.lang.reflect.field; นำเข้า java.util.arraylist; นำเข้า java.util.list; นำเข้า java.util.map นำเข้า java.util.concurrent.atomic.atomicinteger; นำเข้า Javax.sql.datasource; org.slf4j.loggerfactory; นำเข้า org.springframework.jdbc.datasource.lookup.abstractroutingDataSource; นำเข้า org.springframework.util.reflectionutils; วิธีการกำหนดค่าของ LookUpkey * * เนื่องจาก DynamicDataSource เป็น Singleton และ Thread-Insecure, ThreadLocal จึงถูกใช้เพื่อให้แน่ใจว่ามีความปลอดภัยจากด้ายซึ่งเสร็จสมบูรณ์โดย DynamicDataSourceholder * * @author Zhijun * */คลาสสาธารณะ DynamicDataSource ขยาย AbstractroutingDataSource {ส่วนตัว logger logger สุดท้ายคงที่ = loggerFactory.getLogger (DynamicDataSource.class); Slavecount จำนวนเต็มส่วนตัว; // จำนวนการสำรวจความคิดเห็นเริ่มแรก -1, Atomicinteger เป็นตัวนับ atomicinteger ส่วนตัวที่ปลอดภัยต่อด้าย = new Atomicinteger (-1); // บันทึกรายการส่วนตัวคีย์ <Object> SlavedAtaSources = new ArrayList <Object> (0); @Override วัตถุที่ได้รับการป้องกัน deCurrentLookUpkey () {// ใช้ DynamicDataSourceHolder เพื่อให้แน่ใจว่ามีความปลอดภัยของเธรดและรับคีย์แหล่งข้อมูลในเธรดปัจจุบันถ้า (DynamicDataSourceholder.ismaster ()) {Object Key = DynamicDataSourceHolder.getDataSourceKey (); if (logger.isdebugenabled ()) {logger.debug ("คีย์ของแหล่งข้อมูลปัจจุบันคือ:" + คีย์); } คีย์ return; } key object = getSlavekey (); if (logger.isdebugenabled ()) {logger.debug ("คีย์ของแหล่งข้อมูลปัจจุบันคือ:" + คีย์); } คีย์ return; } @suppresswarnings ("ไม่ได้ตรวจสอบ") @Override โมฆะสาธารณะ AfterPropertIesset () {super.afterpropertiesset (); // เนื่องจากคุณสมบัติ ResolvedDataSources ของคลาสแม่เป็นคลาสย่อยส่วนตัวที่ไม่สามารถรับได้คุณต้องใช้การสะท้อนเพื่อรับฟิลด์ฟิลด์ = reflectionutils.findfield (abstractroutingDataSource.class field.setAccessible (จริง); // ตั้งค่าการเข้าถึงลอง {map <object, dataSource> resolvedDataSources = (แผนที่ <วัตถุ, dataSource>) field.get (นี่); // จำนวนข้อมูลในไลบรารีการอ่านเท่ากับจำนวนแหล่งข้อมูลทั้งหมดลบจำนวนไลบรารีการเขียน this.slaveCount = ResolvedDataSources.size () - 1; สำหรับ (map.entry <Object, DataSource> รายการ: ResolvedDataSources.entrySet ()) {ถ้า (DynamicDataSourceHolder.master.equals (entry.getKey ())) {ดำเนินการต่อ; } slavedataSources.add (entry.getKey ()); }} catch (exception e) {logger.error ("ข้อผิดพลาด fterpropertiesset!", e); }} / ** * การดำเนินการสำรวจอัลกอริทึมการสำรวจ * * @return * / วัตถุสาธารณะ getSlavekey () {// ตัวห้อยผลลัพธ์คือ: 0, 1, 2, 3 ... ดัชนีจำนวนเต็ม = counter.incrementandget () % SlaveCount; if (counter.get ()> 9999) {// เพื่อหลีกเลี่ยงเกินช่วงตัวนับจำนวนเต็มเซ็ต (-1); // คืนค่า} return slavedatasources.get (ดัชนี); -6. การจำลองแบบ Master-Master-Slave
6.1. หลักการ
หลักการของการคัดลอก MySQL Master (เรียกว่า Master) Slave (เรียกว่า Slave):
1. เมเจอร์บันทึกการเปลี่ยนแปลงข้อมูลเป็นบันทึกไบนารีนั่นคือไฟล์ที่ระบุโดยบันทึกไฟล์การกำหนดค่า (บันทึกเหล่านี้เรียกว่าเหตุการณ์บันทึกไบนารีเหตุการณ์บันทึกไบนารี) เหตุการณ์บันทึกไบนารี)
2. Slave Copy Binary Binary Logvents ไปยังบันทึกการถ่ายทอด (บันทึกรีเลย์)
3. เหตุการณ์ทาสซ้ำในบันทึกการถ่ายทอดจะเปลี่ยนข้อมูลที่สะท้อนตัวเอง (รีเพลย์ข้อมูล)
6.2. สิ่งที่ควรให้ความสนใจเมื่อกำหนดค่า Mach
1. เวอร์ชันของเซิร์ฟเวอร์ DB หลักและฐานข้อมูลเซิร์ฟเวอร์ Slave DB นั้นเหมือนกัน
2. ข้อมูลฐานข้อมูลของเซิร์ฟเวอร์ Master DB และเซิร์ฟเวอร์ Slave DB นั้นเหมือนกัน [ที่นี่คุณสามารถกู้คืนการสำรองข้อมูลหลักของ Slave ได้หรือคุณสามารถคัดลอกไดเรกทอรีข้อมูลของมาสเตอร์โดยตรงไปยังไดเรกทอรีข้อมูลของทาสที่สอดคล้องกัน]
3. เซิร์ฟเวอร์ DB หลักเปิดใช้งานบันทึกไบนารีและเซิร์ฟเวอร์ DB หลักและเซิร์ฟเวอร์เซิร์ฟเวอร์ DB Slave จะต้องไม่ซ้ำกัน
6.3. การกำหนดค่าไลบรารีหลัก (คล้ายกับ Windows, Linux)
เพื่อนบางคนอาจไม่มีที่อยู่ IP ชื่อผู้ใช้และการกำหนดค่าบัญชีของฐานข้อมูลต้นแบบและฐานข้อมูล ต่อไปนี้คือการกำหนดค่าหลักและการกำหนดค่าทาสที่ฉันทดสอบ IPS ทั้งหมด 127.0.0.1 หลังจากฉันทำตัวอย่างเสร็จฉันจะเขียนมัน
IP Master-Slave เป็นตัวอย่างของการกำหนดค่าที่แตกต่างกัน คุณสามารถใช้ตัวอย่างนี้เพื่อทำความเข้าใจวิธีการกำหนดค่าได้มากขึ้น
แก้ไขภายใต้ my.ini [mysqld] (เช่นกันจากห้องสมุด):
#ENable Master-Slave Replication การกำหนดค่าของ Library Log-Bin = MySQL3306-BIN#ระบุ Library ServerIdServer-ID = 101#ระบุฐานข้อมูลที่ซิงโครไนซ์ หากไม่ได้ระบุฐานข้อมูลทั้งหมดจะถูกซิงโครไนซ์ binlog-do-db = mybatis_1128
(คำสั่งที่ป้อนใน My.ini ต้องมีพื้นที่ด้านล่างมิฉะนั้น MySQL จะไม่รู้จัก)
เรียกใช้สถานะการสืบค้นคำสั่ง SQL: แสดงสถานะต้นแบบ
จะต้องมีการบันทึกค่าตำแหน่งและค่าเริ่มต้นการซิงโครไนซ์จะต้องตั้งค่าในไลบรารี
ให้ฉันพูดอีกอย่างหนึ่ง หากคุณดำเนินการแสดงสถานะต้นแบบการแสดงบน MySQL และพบว่าเนื้อหาที่กำหนดค่าใน my.ini ไม่ได้ผล อาจเป็นไปได้ว่าคุณไม่ได้เลือกไฟล์ my.ini หรืออาจเป็นไปได้ว่าคุณไม่ได้รีสตาร์ทบริการ เป็นไปได้มากที่มันเกิดจากหลัง
เพื่อให้การกำหนดค่ามีผลคุณต้องปิดบริการ MySQL และรีสตาร์ท
วิธีปิดบริการ:
เปิดคีย์ win enter services.msc เพื่อเรียกใช้บริการ:
เริ่ม SQLYOG อีกครั้งและพบว่าการกำหนดค่ามีผล
6.4. สร้างผู้ใช้แบบซิงโครนัสในไลบรารีหลัก
#ผู้ใช้ Slave01 ใช้รหัสผ่าน 123456 เพื่อเข้าสู่ระบบ Slave การจำลองแบบ mysqlgrant บน *. * ถึง 'slave01'@'127.0.0.1' ระบุโดย '123456';
6.5. การกำหนดค่าจากไลบรารี
แก้ไขใน my.ini:
#Specify ServerID ตราบใดที่ยังไม่ได้ทำซ้ำมีเพียงการกำหนดค่าเพียงหนึ่งการกำหนดค่าจากไลบรารีและอื่น ๆ ที่ทำงานใน SQL Server-ID = 102
ต่อไปนี้ดำเนินการ SQL (ดำเนินการโดยใช้บัญชีรูทของทาส):
ChangematerTomater_hot = '127.0.0.1', // ที่อยู่ IP ของโฮสต์ Material_uer = 'lave01', // ผู้ใช้โฮสต์ (บัญชีเพิ่งสร้างบนโฮสต์ผ่าน ql) mater_paword = '123456', mater_port = 3306, mater_log_file = 'myql3306-bin.000006', // filemate_log_po = 1120; // poition
#Start Slave Synchronization เริ่ม Slave; #View การซิงโครไนซ์สถานะแสดงสถานะทาส;
นี่คือวิธีการกำหนดค่าหลักและทาสสำหรับคอมพิวเตอร์ IP สองตัวที่แตกต่างกัน:
ระบบปฏิบัติการที่ฐานข้อมูลหลักอยู่: win7
เวอร์ชันของฐานข้อมูลหลัก: 5.0
ที่อยู่ IP ของฐานข้อมูลหลัก: 192.168.1.111
จากระบบปฏิบัติการที่ฐานข้อมูลอยู่: Linux
จากเวอร์ชันของข้อมูล: 5.0
ที่อยู่ IP จากฐานข้อมูล: 192.168.1.112
หลังจากแนะนำสภาพแวดล้อมให้พูดคุยเกี่ยวกับขั้นตอนการกำหนดค่า:
1. ตรวจสอบให้แน่ใจว่าฐานข้อมูลหลักนั้นเหมือนกับฐานข้อมูลทาส
ตัวอย่างเช่น: ฐานข้อมูลของ A ในฐานข้อมูลหลักมีตาราง B, C และ D ดังนั้นฐานข้อมูลของ A และ Tables B, C และ D ควรแกะสลักด้วยแม่พิมพ์
2. สร้างบัญชีแบบซิงโครนัสบนฐานข้อมูลหลัก
การคัดลอกรหัสมีดังนี้:
ให้การจำลองแบบทาส, ไฟล์บน *. * ถึง 'mstest'@'192.168.1.112' ระบุโดย '123456';
192.168.1.112: เป็นที่อยู่ IP ที่ทำงานโดยใช้ผู้ใช้
MSTEST: เป็นชื่อผู้ใช้ที่สร้างขึ้นใหม่
123456: เป็นรหัสผ่านของชื่อผู้ใช้ที่สร้างขึ้นใหม่
คำอธิบายโดยละเอียดของคำสั่งข้างต้นทำได้ดีที่สุดใน Baidu หากคุณเขียนมากเกินไปมันจะทำให้ไม่ชัดเจนมากขึ้น
3. กำหนดค่า my.ini ของฐานข้อมูลหลัก (เพราะอยู่ภายใต้หน้าต่างมันเป็น my.ini ไม่ใช่ my.cnf)
[MySQLD] Server-ID = 1log-bin = logbinlog-do-db = mstest // เพื่อซิงโครไนซ์ฐานข้อมูล mstest หากคุณต้องการซิงโครไนซ์หลายฐานข้อมูลให้เพิ่ม binlog-do-db = ชื่อฐานข้อมูล Binlog-ignore-db = mysql //
4. กำหนดค่า my.cnf จากฐานข้อมูล
[MySQLD] Server-ID = 2Master-Host = 192.168.1.111Master-user = MSTEST // ขั้นตอนที่ 1 สร้างชื่อผู้ใช้ของบัญชี Master-Password = 123456 // ขั้นตอนที่ 1 สร้างรหัสผ่านของบัญชี ฐานข้อมูลเพิ่มชื่อซ้ำอีกสองสามชื่อฐานข้อมูลซ้ำ ignore-db = mysql // ฐานข้อมูลที่จะถูกละเว้น
5. ตรวจสอบว่าประสบความสำเร็จ
ป้อน MySQL และป้อนคำสั่ง: แสดงสถานะทาส/g ภาพต่อไปนี้จะปรากฏขึ้น หากทั้ง slave_io_running และ slave_sql_running นั้นใช่หมายความว่าการซิงโครไนซ์สามารถทำได้สำเร็จ
6. ทดสอบข้อมูลแบบซิงโครนัส
ป้อนฐานข้อมูลหลักและป้อนคำสั่ง: แทรกลงในค่าหนึ่ง (ชื่อ) ('ปักกิ่ง');
จากนั้นป้อนคำสั่งอินพุตจากฐานข้อมูล: เลือก * จากหนึ่ง;
หากข้อมูลถูกดึงมาจากฐานข้อมูลในเวลานี้หมายความว่าการซิงโครไนซ์ประสบความสำเร็จและจะนำมาใช้หลักและทาส
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น