وفي فبراير من هذا العام، أعلنت الذي – التي الأبله يتم الآن إنشاء الإصدارات كثنائيات محسنة موجهة بالملف الشخصي (PGO)، مما يؤدي إلى الاستفادة من هذه الميزة القوية لـ جولانج 1.20
لزيادة أداء قراءة Dolt بنسبة 5.3%.
قبل إعلاني، قام زاك، أحد خبراء Golang المقيمين لدينا، بتجربة واختبار ميزة pgo الخاصة بـ Golang و كتب عن مكاسب الأداء لقد لاحظ في Dolt بعد بنائه باستخدام الملفات الشخصية التي تم إنشاؤها أثناء تشغيل موقعنا اختبارات قياس الأداء Sysbench ضدها أولا. ومن هناك، علمنا أنه يتعين علينا تحقيق مكاسب الأداء هذه في الثنائيات التي تم إصدارها، لذلك قمنا بإعادة تجهيز عملية إصدار Dolt لإنشاء إصدارات pgo.
اليوم، سأغطي عملية الإصدار العامة لـ Dolt، والتي تستخدم إجراءات جيثب، وسوف أقوم بتفصيل جميع مراحل عملية الإصدار لدينا. سأراجع أيضًا ما قمنا بتغييره في عمليتنا لبدء إصدار إصدارات pgo. نأمل أن يسمح لك هذا بجمع بعض الأفكار التي يمكنك استخدامها للعمل على تصميمات pgo في إصدارات Golang الخاصة بك!
دعونا نتعمق في الأمر.
يتم إصدار Dolt باستخدام إجراءات GitHub
تستفيد Dolt من إجراءات GitHub لتنفيذ عدد من المهام الآلية، إحداها هي إنشاء الإصدارات ونشرها.
تستخدم إجراءات GitHub ملفات تسمى سير العمل للتعريف وظائف أنه سيقوم بالعمل المحدد في ملف سير العمل. يتم نشر هذه الوظائف ل العدائين، أو الأجهزة المضيفة، التي يمكنك إما استضافتها بنفسك أو السماح لـ GitHub باستضافتها لك.
يتم توفير برامج التشغيل المستضافة ذاتيًا وصيانتها بواسطتك، خارج إجراءات GitHub. تتم استضافة جميع برامج التشغيل المستضافة على GitHub، والتي تكون مجانية للمستودعات العامة، بواسطة GitHub وصيانتها، ولكن لديهم حدود محددة للتخزين والذاكرة ووحدة المعالجة المركزية اعتمادًا على مستوى الاشتراك الخاص بك. بالنسبة إلى Dolt، نستخدم المتسابقين ذوي المستوى المجاني المستضافين على GitHub.
على مستوى عالٍ، تحتاج عملية إصدار Dolt إلى تحقيق بعض الأهداف.
أولاً، والأهم من ذلك، تحتاج العملية إلى إنشاء علامة وإصدار للإصدار الجديد من Dolt وتحميل ثنائيات Dolt المترجمة مسبقًا إلى الافراج عن الأصول.
ثانيًا، تحتاج عملية الإصدار إلى إجراء اختبارات قياس أداء Sysbench مقابل هذا الإصدار الجديد من Dolt وإرسال النتائج بالبريد الإلكتروني إلى موقعنا فريق دولتهب.
ثالثًا، وهي ليست ذات صلة كبيرة بهذه المدونة، تحتاج العملية إلى بدء أي مهام مساعدة أخرى نحتاج إلى تنفيذها أثناء الإصدار، مثل إنشاء ملاحظات إصدار Dolt التي تعتمد على أوصاف طلبات السحب من مستودعات متعددة، نشر الإصدار إلى مديري الحزم المختلفين بحيث يمكن تثبيته بسهولة منهم، ودفع الجديد صور عامل ميناء إلى DockerHubأو ترقية تبعية Dolt في المستودعات المختلفة التي نمتلكها.
لذلك، مع وضع هذه الأهداف في الاعتبار، توصلنا إلى مجموعة من مهام سير عمل GitHub Actions التي تستفيد من repository_dispatch الحدث حتى نتمكن من تحقيق كل من هذه الأهداف. دعونا نلقي نظرة على رسم تخطيطي يوضح كيف يبدو هذا التصميم من حيث المبدأ، ثم سنتعمق في تفاصيل سير العمل.
في الرسم البياني أعلاه، سترى سياقين، سياق إجراءات GitHub وسياق كوبيرنيتيس (K8s) سياق. دعونا نناقش سياق إجراءات GitHub أولاً.
بالنسبة لعملية الإصدار الأصلية لـ Dolt، استخدمنا ثلاثة مسارات عمل: سير عمل “Release Dolt”، وسير عمل “Deploy K8s Sysbench Benchmarking Job”، وسير عمل “Email team”.
يبدأ سير عمل “Release Dolt” عملية إصدار Dolt بالكامل، ويتم تشغيله يدويًا بواسطة فريقنا الهندسي عندما يكون جاهزًا لإصدار إصدار جديد من Dolt. فيما يلي نسخة مختصرة من سير العمل تشير إلى الخطوات الموضحة في الرسم البياني أعلاه.
name: Release Dolton: workflow_dispatch: inputs: version: description: 'SemVer format release tag, i.e. 0.24.5' required: truejobs: format-version: runs-on: ubuntu-22.04 outputs: version: ${{ steps.format_version.outputs.version }} steps: - name: Format Input id: format_version run: | version="${{ github.event.inputs.version }}" if [[ $version==v* ]]; then version="${version:1}" fi echo "version=$version">> $GITHUB_OUTPUT create-release: needs: format-version name: Create release runs-on: ubuntu-22.04 outputs: release_id: ${{ steps.create_release.outputs.id }} steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Go 1.x uses: actions/setup-go@v3 with: go-version: ^1.21 - name: Update dolt version command run: sed -i -e 's/Version=".*"/Version="'"$NEW_VERSION"'"/' "$FILE" env: FILE: ${{ format('{0}/go/cmd/dolt/dolt.go', github.workspace) }} NEW_VERSION: ${{ needs.format-version.outputs.version }} - name: Set minver TBD to version run: sed -i -e 's/minver:"TBD"/minver:"'"$NEW_VERSION"'"/' "$FILE" env: FILE: ${{ format('{0}/go/cmd/dolt/commands/sqlserver/yaml_config.go', github.workspace) }} NEW_VERSION: ${{ needs.format-version.outputs.version }} - name: update minver_validation.txt working-directory: ./go run: go run -mod=readonly ./utils/genminver_validation/ $FILE env: FILE: ${{ format('{0}/go/cmd/dolt/commands/sqlserver/testdata/minver_validation.txt', github.workspace) }} - uses: EndBug/add-and-commit@v9.1.1 with: message: ${{ format('[ga-bump-release] Update Dolt version to {0} and release v{0}', needs.format-version.outputs.version) }} add: ${{ format('["{0}/go/cmd/dolt/dolt.go", "{0}/go/cmd/dolt/commands/sqlserver/yaml_config.go", "{0}/go/cmd/dolt/commands/sqlserver/testdata/minver_validation.txt"]', github.workspace) }} cwd: "." pull: "--ff" - name: Build Binaries id: build_binaries run: | latest=$(git rev-parse HEAD) echo "commitish=$latest">> $GITHUB_OUTPUT GO_BUILD_VERSION=1.21 go/utils/publishrelease/buildbinaries.sh - name: Create Release id: create_release uses: dolthub/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: v${{ needs.format-version.outputs.version }} release_name: ${{ needs.format-version.outputs.version }} draft: false prerelease: false commitish: ${{ steps.build_binaries.outputs.commitish }} - name: Upload Linux AMD64 Distro id: upload-linux-amd64-distro uses: dolthub/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: go/out/dolt-linux-amd64.tar.gz asset_name: dolt-linux-amd64.tar.gz asset_content_type: application/zip... - name: Upload Install Script id: upload-install-script uses: dolthub/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: go/out/install.sh asset_name: install.sh asset_content_type: text/plain trigger-performance-benchmark-email: needs: [format-version, create-release] runs-on: ubuntu-22.04 steps: - name: Trigger Performance Benchmarks uses: peter-evans/repository-dispatch@v2.0.0 with: token: ${{ secrets.REPO_ACCESS_TOKEN }} event-type: release-dolt client-payload: '{"version": "${{ needs.format-version.outputs.version }}", "actor": "${{ github.actor }}"}'
يتم تشغيل سير العمل هذا يدويًا باستخدام Workflow_dispatch الحدث، ويتطلب رقم إصدار جديد كمدخل. ومن هناك، يقوم بإجراء بعض التنسيق السريع لإدخال الإصدار، ثم يكتب هذا الإصدار الجديد ويرسله إلى Dolt’s main
فرع بحيث تقوم الثنائيات التي تم إصدارها بإخراج هذا الرقم الجديد من نسخة دولت يأمر.
في خطوة “إنشاء الثنائيات”، create-release
الوظيفة تدير buildbinaries.sh البرنامج النصي الذي يبني Dolt من المصدر باستخدام Golang عامل ميناء الحاوية التي تدير go build
يأمر.
نحن نستخدم حاويات Docker لبناء Dolt بحيث يكون إخراج المسار عن طريق تتبعات المكدس هو Linux عام go
المسارات وليس المسارات التي تشير إلى أ go
التثبيت على المشغل أو على أحد أجهزة الكمبيوتر الشخصية لدينا (وهو ما حدث في الإصدارات المبكرة من Dolt 🤠).
بعد ذلك، تقوم خطوة “إنشاء إصدار” بإنشاء العلامة ونشر الإصدار على GitHub. كما يوفر أيضًا upload_url
والذي يستخدم في جميع الخطوات اللاحقة لل create-release
مهمة تحميل الثنائيات المجمعة إلى إصدار GitHub الجديد.
الجزء الأخير من سير العمل هذا هو مهمة أخرى يتم تشغيلها بعد اكتمال كافة المهام السابقة. هذه الوظيفة تسمى trigger-performance-benchmark-email
. يستخدم عمل جيثب وجدنا في أسواقهم أن ينبعث منها أ repository_dispatch
الحدث الذي يبدأ سير عمل Dolt منفصل. يمكننا رؤيته إذا نظرنا إلى الرسم البياني.
يُظهر الرسم البياني الخاص بنا الخطوة الأخيرة من سير عمل “Release Dolt” الذي يشير إلى سير عمل آخر يسمى “Deploy K8s Sysbench Benchmarking Job”. هذا هو سير العمل الذي بدأه trigger-performance-benchmark-email
وظيفة سير العمل.
تم تصميم سير العمل هذا، وغيره من الأمور المشابهة، ليتم إرساله بشكل غير متزامن جزئيًا بحيث لا يقترن بإحكام بسير عمل “Release Dolt” فقط.
في الواقع، ستؤدي مسارات العمل المختلفة إلى تشغيل سير العمل هذا باستخدام ملف repository_dispatch
الحدث، لأننا نحتاج إلى تشغيل مقاييس الأداء في أوقات مختلفة، وليس فقط أثناء الإصدار. ومن المثير للاهتمام أن سير العمل هذا، في حد ذاته، يطلق عملية أخرى غير متزامنة، والتي يمكننا رؤيتها في الرسم البياني المشار إليه بالسهم – فهو ينشر وظيفة K8s الذي يدير معايير Sysbench الخاصة بنا.
لقد كتبنا كثيرًا عن استخدام Dolt لـ Sysbench لقياس أداء Dolt وMySQL لمقارنة أدائهما، لكنني لا أعتقد أننا ناقشنا تفاصيل التنفيذ لكيفية القيام بذلك على وجه التحديد. هذه المدونة جيدة بالنسبة لي لمراجعة ذلك، لذلك سأفعل ذلك للحظات. قبل أن أفعل ذلك، دعونا نلقي نظرة سريعة على سير عمل “نشر وظيفة قياس أداء K8s Sysbench”.
name: Benchmark Latencyon: repository_dispatch: types: [ benchmark-latency ]jobs: performance: runs-on: ubuntu-22.04 name: Benchmark Performance strategy: matrix: dolt_fmt: [ "__DOLT__" ] steps: - name: Checkout uses: actions/checkout@v3 - uses: azure/setup-kubectl@v3.0 with: version: 'v1.23.6' - name: Install aws-iam-authenticator run: | curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && chmod +x ./aws-iam-authenticator && sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator aws-iam-authenticator version - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2.2.0 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Create and Auth kubeconfig run: | echo "$CONFIG"> kubeconfig KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1 KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=performance-benchmarking KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context env: CONFIG: ${{ secrets.CORP_KUBECONFIG }} - name: Create Sysbench Performance Benchmarking K8s Job run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh env: FROM_SERVER: ${{ github.event.client_payload.from_server }} FROM_VERSION: ${{ github.event.client_payload.from_version }} TO_SERVER: ${{ github.event.client_payload.to_server }} TO_VERSION: ${{ github.event.client_payload.to_version }} MODE: ${{ github.event.client_payload.mode }} ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }} ACTOR: ${{ github.event.client_payload.actor }} ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }} REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} KUBECONFIG: "./kubeconfig" INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }} NOMS_BIN_FORMAT: ${{ matrix.dolt_fmt }} TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }} - name: Create TPCC Performance Benchmarking K8s Job run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh env: FROM_SERVER: ${{ github.event.client_payload.from_server }} FROM_VERSION: ${{ github.event.client_payload.from_version }} TO_SERVER: ${{ github.event.client_payload.to_server }} TO_VERSION: ${{ github.event.client_payload.to_version }} MODE: ${{ github.event.client_payload.mode }} ISSUE_NUMBER: ${{ github.event.client_payload.issue_number }} ACTOR: ${{ github.event.client_payload.actor }} ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }} REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} KUBECONFIG: "./kubeconfig" INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }} NOMS_BIN_FORMAT: ${{ matrix.dolt_fmt }} WITH_TPCC: "true" TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
قصير، ولكنه مشغول نوعًا ما، يقوم سير العمل هذا بالمصادقة على ملف kubectl العميل ضد أ مجموعة K8s حيث نقوم بتشغيل معايير Sysbench الخاصة بنا ونوفر متغيرات البيئة المطلوبة لتشغيل برنامج نصي يسمى تشغيل-benchmarks.sh. يستخدم هذا البرنامج النصي القيم من هذه المتغيرات لكتابة ملف ملف تكوين وظيفة K8s وثم يتقدم it، الذي ينشر وظيفة القياس في مجموعة K8s الخاصة بنا.
في هذه المرحلة، قد تتساءل عن سبب اختيارنا تشغيل معايير Dolt في مجموعة K8s وليس فقط استخدام GitHub Actions ومشغليها لقياس Dolt. حسنًا، هناك عدة أسباب لذلك.
أولاً، لدى المتسابقين المستضافين على GitHub حدود محددة جدًا، على الأقل بالنسبة للطبقة المجانية، ولقياس قاعدة البيانات الخاصة بنا، لا نريد بالضرورة أن نكون مقيدين بهذه الحدود.
بالإضافة إلى ذلك، لا توجد طريقة لنا لمعرفة أو التحكم في العمليات أو البرامج الأخرى التي يتم تشغيلها على برامج التشغيل المستضافة على GitHub أثناء قيامنا بإجراء اختبار قياس الأداء، وقد يؤثر ذلك سلبًا على نتائج التشغيل بطرق غير متوقعة.
وعلى الرغم من أنه من الممكن بالتأكيد استخدام عداء مستضاف ذاتيًا في GitHub Actions للتحايل على هاتين المشكلتين، ففي هذه الحالة نحن استطاع معيار دولت باستخدام فقط GitHub Actions، لدينا بالفعل مضيفات يمكن توفيرها بسهولة ومتوفرة في مجموعة K8s الخاصة بنا، لذلك اخترنا استخدامها ببساطة بدلاً من ذلك.
في الواقع، بكل بساطة applying
ستوفر وظيفة قياس الأداء K8s لدينا مضيفًا قياسًا جديدًا باستخدام مقياس تلقائي للمجموعة K8s، وهو أمر رائع جدًا.
على أي حال، بالعودة إلى الرسم البياني الخاص بنا للحظة وجيزة، نرى أنه بعد المصادقة على kubectl
العميل، يقوم سير العمل “Deploy Sysbench Benchmarking Job” بنشر وظيفة K8s، وتنتقل العملية إلى سياق K8s ويتم تشغيل “وظيفة K8s Sysbench Benchmarking Job”.
الآن من الناحية الفنية، كان هذا الجزء من عملية إصدار Dolt الأصلية بمثابة خطوة ما بعد الإصدار. لم يكن تشغيل مهمة قياس الأداء مطلوبًا لإنشاء إصدار Dolt جديد على GitHub، بل زود فريقنا بتقرير حول زمن وصول الإصدار. ولكن من المهم رؤية هذا الجزء من عملية الإصدار الأصلية الخاصة بنا حتى تكون تحديثات pgo الخاصة بنا لعملية إصدار Dolt أكثر منطقية، ولكن المزيد عن ذلك لاحقًا.
في سياق K8s للرسم التخطيطي، يمكننا أن نرى أن مهمة القياس تؤدي بضع خطوات. يقوم ببناء Dolt ثنائي من المورد ارتكاب شا. في هذه الحالة يكون SHA من رأس من دولت main
.
بعد ذلك، يقوم بتشغيل اختبارات Sysbench مقابل إصدار Dolt المترجم، ثم يقوم بتحميل نتائج تشغيل Sysbench إلى دلو AWS S3. وأخيرًا، يقوم بتشغيل سير عمل GitHub Actions مختلفًا موجودًا في مستودع Dolt المسمى بسير عمل “فريق البريد الإلكتروني”.
لإجراء كل هذا القياس والتحميل والتشغيل، قمنا بكتابة أداة داخلية يمكن استخدامها لقياس إصدار Dolt مقابل إصدار MySQL.
تستخدم هذه الأداة بعض أكواد المكتبة التي نحتفظ بها في مستودع Dolt، ولكنني سأقدم بعض المقتطفات ذات الصلة من الأداة الداخلية وكود المكتبة حتى تتمكن من التعرف على كيفية تنفيذنا لها لتشغيل معاييرنا.
رمز أداة القياس الداخلي لدينا هو في الأساس ما يلي go
وظيفة:
انقر لرؤية الرمز
func compare(ctx context.Context,fromServer,toServer runner.ServerType,fromVersion,toVersion,fromProfile,toProfile,dir,doltCommand,doltgresCommand,mysqlExec,mysqlProtocol,mysqlSocketPath,postgresExec,initDbExec,nomsBinFormat,resultsDir,resultsPrefix,resultsFilename,scriptDir,schema,outputFormat string,defaultRuns int,initBigRepo,useDoltHubLuaScriptsRepo,writeResultsToFile bool,queries []string) (string, error) {config := benchmark.NewComparisonBenchmarkingConfig(fromServer,toServer,fromVersion,toVersion,fromProfile,toProfile,dir,doltCommand,doltgresCommand,mysqlExec,mysqlProtocol,mysqlSocketPath,postgresExec,initDbExec,nomsBinFormat,scriptDir,defaultRuns,initBigRepo,useDoltHubLuaScriptsRepo)sr := benchmark.NewSysbenchComparer(config)err := sr.Run(ctx)if err != nil {return "", err}fromServerConfig, err := config.GetFromServerConfig(ctx)if err != nil {return "", err}toServerConfig, err := config.GetToServerConfig(ctx)if err != nil {return "", err}resultsDbName := fmt.Sprintf("sysbench-%s", benchmark.ComparisonDbFilename)db := benchmark.NewSqlite3ResultsDb(fromServerConfig, toServerConfig, dir, schema, resultsDir, resultsPrefix, resultsFilename, resultsDbName, outputFormat, queries, writeResultsToFile)uploadDir, err := db.QueryResults(ctx)if err != nil {return "", err}return uploadDir, nil}
compare
يتم استخدامه لمقارنة نتائج Sysbench لإصدار واحد من قاعدة البيانات بإصدار آخر. يمكنك أن ترى من معلمات الوظيفة أن هذه الأداة لا تُستخدم فقط مع Dolt وMySQL، ولكنها تُستخدم أيضًا لتقييم أحدث منتجاتنا دولتغريسكل، وهو منافس PostgreSQL.
ال compare
تشير الوظيفة إلى أ fromServerConfig
، وهو التكوين لخادم قاعدة البيانات “من”، ويشير إلى ملف toServerConfig
، وهو تكوين خادم قاعدة البيانات “إلى”. من الناحية الدلالية، هنا، ستقوم هذه الأداة بمقارنة قاعدة البيانات “من” بقاعدة البيانات “إلى” جنبًا إلى جنب لسهولة التحليل. أثناء عملية إصدار Dolt، سيكون MySQL هو الخادم “من” وسيكون Dolt هو الخادم “إلى”.
قد تلاحظ أيضًا أننا نستخدم sqlite3 في هذه الأداة، كما أشار benchmark.NewSqlite3ResultsDb
، وهي قطعة أثرية قديمة تعود إلى أيام قبل الإصدار 1.0.0 من Dolt، ولكنها لا تزال تتمتع ببعض القيمة الفريدة هنا.
تحت غطاء محرك السيارة، بعد تشغيل المعايير مع sr.Run()
، نقوم بتحميل النتائج في ملف sqlite3
قاعدة البيانات وتشغيل بعض الاستعلامات عليها للحصول على النتائج المقارنة لكل خادم قاعدة بيانات. فائدة الاستخدام sqlite3
على Dolt للقيام بذلك، والذي يعمل أيضًا، هو ذلك sqlite3
تقوم بإرجاع مخرجات الاستعلام في العديد من التنسيقات باستخدام علامات بسيطة، مثل --html
و --markdown
، مما يوفر علينا الاضطرار إلى ترميز منطق تحويل نتيجة الاستعلام.
ال uploadDir
عاد من db.QueryResults()
يحتوي على نتائج استعلامات المقارنة ونسخة من sqlite3
قاعدة البيانات ليتم تحميلها إلى S3. سيتم تنزيل هذه النتائج قريبًا من خلال سير عمل “فريق البريد الإلكتروني”، كما سنرى قريبًا.
عندما يتعلق الأمر في الحقيقة تشغيل معايير Sysbench، و benchmark.NewSysbenchComparer(config)
هو مجرد غلاف البنية حول ال Run
وظيفة من بعض كود المكتبة المعياري الذي نحتفظ به في مستودع Dolt.
انقر لرؤية الرمز
func Run(config *Config) error {err := config.Validate()if err != nil {return err}ctx := context.Background()err = sysbenchVersion(ctx)if err != nil {return err}cwd, err := os.Getwd()if err != nil {return err}for _, serverConfig := range config.Servers {var results Resultsvar b Benchmarkerswitch serverConfig.Server {case Dolt:fmt.Println("Running dolt sysbench tests")b = NewDoltBenchmarker(cwd, config, serverConfig)case Doltgres:fmt.Println("Running doltgres sysbench tests")b = NewDoltgresBenchmarker(cwd, config, serverConfig)case MySql:fmt.Println("Running mysql sysbench tests")b = NewMysqlBenchmarker(cwd, config, serverConfig)case Postgres:fmt.Println("Running postgres sysbench tests")b = NewPostgresBenchmarker(cwd, config, serverConfig)default:panic(fmt.Sprintf("unexpected server type: %s", serverConfig.Server))}results, err = b.Benchmark(ctx)if err != nil {return err}fmt.Printf("Successfuly finished %sn", serverConfig.Server)err = WriteResults(serverConfig, results)if err != nil {return err}fmt.Printf("Successfuly wrote results for %sn", serverConfig.Server)}return nil}
تقوم هذه الوظيفة بإنشاء Benchmarker
بناءً على نوع الخادم الذي يراه، ثم يتصل به Benchmark()
، الذي يدير Sysbench t ضد هذا الخادم. فيما يلي مثال على ما يفعله Dolt Benchmarker Benchmark()
تطبيق يشبه:
انقر لرؤية الرمز
func (b *doltBenchmarkerImpl) Benchmark(ctx context.Context) (Results, error) {err := b.checkInstallation(ctx)if err != nil {return nil, err}err = b.updateGlobalConfig(ctx)if err != nil {return nil, err}testRepo, err := b.initDoltRepo(ctx)if err != nil {return nil, err}serverParams, err := b.serverConfig.GetServerArgs()if err != nil {return nil, err}server := NewServer(ctx, testRepo, b.serverConfig, syscall.SIGTERM, serverParams)err = server.Start(ctx)if err != nil {return nil, err}tests, err := GetTests(b.config, b.serverConfig, nil)if err != nil {return nil, err}results := make(Results, 0)for i := 0; i < b.config.Runs; i++ {for _, test := range tests {tester := NewSysbenchTester(b.config, b.serverConfig, test, stampFunc)r, err := tester.Test(ctx)if err != nil {server.Stop(ctx)return nil, err}results = append(results, r)}}err = server.Stop(ctx)if err != nil {return nil, err}return results, os.RemoveAll(testRepo)}
أثناء ال Benchmark()
استدعاء، سيتحقق هذا التنفيذ من تثبيت Dolt، وتحديث بعض تكوينات Dolt العالمية، والحصول على الوسائط المستخدمة لبدء تشغيل خادم Dolt SQL، وبدء تشغيل الخادم، والحصول على اختبارات Sysbench التي سيتم تشغيلها، ثم تشغيل هذه الاختبارات عن طريق الاتصال tester.Test()
.
عندما يتم ذلك، فإنه يعود results
وينظف ما كتبه على القرص.
وكما رأينا في الأدوات الداخلية compare
الدالة، يتم تحميل هذه النتائج إلى sqlite3
وتحميلها إلى S3 حتى يمكن إرسالها عبر البريد الإلكتروني إلى فريق DoltHub. ولكننا لا نزال نفتقد خطوة واحدة، وهي تشغيل سير عمل “فريق البريد الإلكتروني” باستخدام ملف repository_dispatch
الحدث بعد انتهاء أداة قياس الأداء الداخلي من تحميل النتائج.
لذا فإن الجزء الأخير من أداتنا الداخلية يتضمن ما يلي:
err := d.DispatchEmailReportEvent(ctx, *toVersion, *nomsBinFormat, *bucket, key)if err != nil {log.Fatal(err)}
ال DispatchEmailReportEvent()
الطريقة على أ Dispatcher
الواجهة التي كتبناها. إنه ببساطة يقدم طلب HTTP إلى GitHub Actions Workflow REST API الذي ينبعث repository_dispatch
الحدث، مما يؤدي إلى تشغيل سير عمل “فريق البريد الإلكتروني”. لذلك دعونا ننظر إلى ذلك بعد ذلك.
مثل سير عمل “Deploy K8s Sysbench Benchmarking Job”، يتم استخدام سير عمل “Email team” من خلال عمليات متعددة إلى جانب عملية إصدار Dolt فقط، ولهذا السبب قمنا بتشغيله باستخدام repository_dispatch
الأحداث. ملف سير العمل هو كما يلي:
name: Email Team Memberson: repository_dispatch: types: [ email-report ]jobs: email-team: runs-on: ubuntu-22.04 name: Email Team Members steps: - uses: actions/checkout@v3 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v2.2.0 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Get Results id: get-results run: aws s3api get-object --bucket="$BUCKET" --key="$KEY" results.log env: KEY: ${{ github.event.client_payload.key }} BUCKET: ${{ github.event.client_payload.bucket }} - name: Get Addresses id: get-addresses run: | addresses="$TEAM" if [ ! -z "$RECIPIENT" ]; then addresses="["$RECIPIENT"]" fi echo "addresses=$addresses">> $GITHUB_OUTPUT env: RECIPIENT: ${{ github.event.client_payload.email_recipient }} TEAM: '["${{ secrets.PERF_REPORTS_EMAIL_ADDRESS }}"]' - name: Send Email uses: ./.github/actions/ses-email-action with: template: ${{ github.event.client_payload.template }} region: us-west-2 version: ${{ github.event.client_payload.version }} format: ${{ github.event.client_payload.noms_bin_format }} toAddresses: ${{ steps.get-addresses.outputs.addresses }} dataFile: ${{ format('{0}/results.log', github.workspace) }}
كما هو موضح في الرسم البياني، ملخص سير العمل هذا هو تنزيل نتائج Sysbench لإصدار Dolt ثم إرسالها بالبريد الإلكتروني إلى فريقنا؛ لا شيء مجنون.
وهذه هي عملية إصدار Dolt. أو ذلك كان عملية الافراج عن دولت. سأتحدث الآن عن كيفية تحديث هذه العملية لبدء إنشاء ثنائيات pgo الخاصة بـ Dolt عند الإصدار.
إصدارات PGO مع إجراءات GitHub
بالنسبة لأولئك الذين ليسوا على دراية بتصميمات pgo، فإنهم يحتاجون إلى -pgo
العلم مع المسار إلى أ الملف الشخصي لـجولانج المقدمة خلال go build
يأمر. هذا الجزء هو في الواقع بسيط جدا. ولكن قبل ذلك، تحتاج إلى إنشاء ملف التعريف الذي تريد استخدامه للتصميم الأمثل، وهذا يتطلب منا تحديث بعض أكواد مكتبتنا المعيارية، وكود أدواتنا الداخلية، حتى يتمكنوا من كلا الأمرين يولد الملف الشخصي و يقبل ملف تعريف كمدخل. اسمحوا لي أن أشرح بمزيد من التفصيل.
في كود مكتبة القياس لدينا، نستخدم أداة Dolt أخرى تسمى dolt_builder لبناء ثنائيات Dolt فعليًا من المصدر. لاستخدام هذه الأداة، ما عليك سوى توفير التزام SHA أو العلامة التي تريد إنشاء Dolt منها، وسوف تقوم بإنشائها لك. لذلك نستخدم هذه الأداة في عدد من الأماكن لتسهيل إنشاء إصدارات متعددة من Dolt في وقت واحد.
لذا فإن أول شيء فعلناه هو تحديث هذه الأداة لقبول ملف تعريف Golang الذي يمكن استخدامه لإنشاء Dolt:
انقر لرؤية الرمز
// goBuild builds the dolt binary and returns the path to the binaryfunc goBuild(ctx context.Context, source, dest, profilePath string) (string, error) {goDir := filepath.Join(source, "go")doltFileName := "dolt"if runtime.GOOS == "windows" {doltFileName = "dolt.exe"}args := make([]string, 0)args = append(args, "build")if profilePath != "" {args = append(args, fmt.Sprintf("-pgo=%s", profilePath))}toBuild := filepath.Join(dest, doltFileName)args = append(args, "-o", toBuild, filepath.Join(goDir, "cmd", "dolt"))build := ExecCommand(ctx, "go", args...)build.Dir = goDirerr := build.Run()if err != nil {return "", err}return toBuild, nil}
والشيء التالي الذي قمنا به هو تحديث كود المكتبة القياسي ليتم تشغيله في وضع “التوصيف”. في الوضع الافتراضي، كما هو موضح أعلاه، يتم استدعاء هذا الرمز Benchmark()
وإرجاع النتائج. في وضع “التوصيف” الجديد، يستدعي الرمز Profile()
على Profiler
واجهه المستخدم:
...case Dolt:// handle a profiling runsc, ok := serverConfig.(ProfilingServerConfig)if ok {if string(sc.GetServerProfile()) != "" {fmt.Println("Profiling dolt while running sysbench tests")p := NewDoltProfiler(cwd, config, sc)return p.Profile(ctx)}}...
Profile()
يعمل بالمثل Benchmark()
، ولكنه ينشئ ملف تعريف golang تم التقاطه أثناء تشغيل معايير Sysbench. يتيح لنا ذلك إنشاء ملفات تعريف لـ Dolt بسهولة يمكننا استخدامها في عملية الإصدار الجديد.
نقوم أيضًا بتحديث رمز المكتبة هذا إلى يقبل ملف تعريف كمدخل. بهذه الطريقة يمكننا أن نزوده بملف تعريفي، والذي بدوره سيزوده به dolt_builder
لإنشاء ملف ثنائي pgo، ثم تشغيل Sysbench وإخراج تلك النتائج.
للتوضيح، قمنا بشكل أساسي بتحديث رمز المكتبة هذا حتى نتمكن من تشغيله في وضع واحد لإنشاء ملف تعريف Golang، ثم تشغيله في الوضع الافتراضي للحصول على نتائج قياس الأداء العادية، ولكنه سيتم أيضًا يقبل ملف تعريف Golang كمدخل، واستخدامه لإنشاء Dolt باستخدام ملف go build -pgo
. نأمل أن يكون هذا منطقيًا بالنسبة لك، لأنه يصعب عليّ وصفه 🤠.
للمضي قدمًا، احتجنا بعد ذلك إلى تحديث أداتنا الداخلية التي تستخدم كل رموز المكتبة هذه للحصول أيضًا على وضع “التوصيف” وقبول ملفات تعريف Golang كمدخل. كانت خطتنا لعملية الإصدار الجديد هي تشغيل الأداة الداخلية مرة واحدة، في وضع التوصيف، لإنشاء ملف تعريف Golang. بعد ذلك، قم بتشغيل الأداة الداخلية مرة أخرى في الوضع الافتراضي، ولكن قم بتزويد ملف تعريف Golang إليها مرة أخرى، مما قد ينتج عنه نتائج القياس مقابل Dolt المبني من pgo.
لذا، مثل compare
وظيفة، تمكنا من إضافة profile
تعمل على الأداة الداخلية التي تنشئ ملف تعريف Golang cpu لإصدار Dolt.
انقر لرؤية الرمز
func profile(ctx context.Context, dir, profileDir, resultsDir, resultsPrefix, version, profile, doltCommand, scriptsDir string, useDoltHubLuaScriptsRepo bool) (string, error) {config := benchmark.NewProfilingConfig(dir,profileDir,version,profile,doltCommand,scriptsDir,useDoltHubLuaScriptsRepo)toUpload := filepath.Join(resultsDir, resultsPrefix)sr := benchmark.NewSysbenchProfiler(config, toUpload, profileDir)return toUpload, sr.Run(ctx)}
تقوم هذه الدالة بإرجاعها toUpload
الدليل مثل compare
لا، ولكن هذه المرة يحتوي على ملف التعريف الذي سيتم تحميله إلى S3.
بعد هذه التغييرات على التعليمات البرمجية، أصبحنا على استعداد لتحديث سير عمل GitHub Actions لبدء إنشاء إصدارات pgo من Dolt. فيما يلي رسم تخطيطي يوضح عملية إصدار Dolt الجديدة باستخدام GitHub Actions.
كما ترون من الرسم التخطيطي لسير عمل الإصدار الجديد، فقد أضفنا بعض مسارات عمل GitHub Actions الجديدة، ولكنها تشبه تلك الأصلية. دعونا ننظر إليهم عن كثب.
بالنسبة لعملية إصدار Dolt الجديدة، فإن سير العمل الأول الذي نقوم بتشغيله، والذي يسمى “Release Dolt (الملف الشخصي)”، يعمل لا قم بالفعل بإنشاء إصدار GitHub أو إنشاء أي ثنائيات Dolt.
وبدلاً من ذلك، فإن وظيفته الوحيدة هي تشغيل سير عمل ثانٍ يسمى “Deploy K8s Sysbench Profiling Job”.
name: Release Dolt (Profile)on: workflow_dispatch: inputs: version: description: 'SemVer format release tag, i.e. 0.24.5' required: truejobs: format-version: runs-on: ubuntu-22.04 outputs: version: ${{ steps.format_version.outputs.version }} steps: - name: Format Input id: format_version run: | version="${{ github.event.inputs.version }}" if [[ $version==v* ]]; then version="${version:1}" fi echo "version=$version">> $GITHUB_OUTPUT profile-benchmark-dolt: runs-on: ubuntu-22.04 needs: format-version name: Trigger Benchmark Profile K8s Workflows steps: - uses: actions/checkout@v4 with: ref: main - name: Get sha id: get_sha run: | sha=$(git rev-parse --short HEAD) echo "sha=$sha">> $GITHUB_OUTPUT - uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.REPO_ACCESS_TOKEN }} event-type: profile-dolt client-payload: '{"from_version": "${{ steps.get_sha.outputs.sha }}", "future_version": "${{ needs.format-version.outputs.version }}", "mode": "release", "actor": "${{ github.actor }}", "actor_email": "dustin@dolthub.com", "template_script": "./.github/scripts/performance-benchmarking/get-dolt-profile-job-json.sh"}'
تعمل “Deploy K8s Sysbench Profiling Job” بشكل مماثل تقريبًا لـ “Deploy K8s Sysbench Benchmarking Job”، باستثناء أنها تنشر مهمة قياس أداء تعمل في وضع “التوصيف” إلى مجموعة K8s، بحيث نقوم بإنشاء ملف تعريف Golang باستخدام HEAD
من دولت main
.
name: Profile Dolt while Benchmarkingon: repository_dispatch: types: [ profile-dolt ]jobs: performance: runs-on: ubuntu-22.04 name: Profile Dolt while Benchmarking steps: - name: Checkout uses: actions/checkout@v4 - uses: azure/setup-kubectl@v4 with: version: 'v1.23.6' - name: Install aws-iam-authenticator run: | curl -o aws-iam-authenticator https://amazon-eks.s3.us-west-2.amazonaws.com/1.18.8/2020-09-18/bin/linux/amd64/aws-iam-authenticator && chmod +x ./aws-iam-authenticator && sudo cp ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator aws-iam-authenticator version - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Create and Auth kubeconfig run: | echo "$CONFIG"> kubeconfig KUBECONFIG=kubeconfig kubectl config set-credentials github-actions-dolt --exec-api-version=client.authentication.k8s.io/v1alpha1 --exec-command=aws-iam-authenticator --exec-arg=token --exec-arg=-i --exec-arg=eks-cluster-1 KUBECONFIG=kubeconfig kubectl config set-context github-actions-dolt-context --cluster=eks-cluster-1 --user=github-actions-dolt --namespace=performance-benchmarking KUBECONFIG=kubeconfig kubectl config use-context github-actions-dolt-context env: CONFIG: ${{ secrets.CORP_KUBECONFIG }} - name: Create Profile Benchmarking K8s Job run: ./.github/scripts/performance-benchmarking/run-benchmarks.sh env: PROFILE: "true" FUTURE_VERSION: ${{ github.event.client_payload.future_version }} FROM_VERSION: ${{ github.event.client_payload.from_version }} MODE: ${{ github.event.client_payload.mode }} ACTOR: ${{ github.event.client_payload.actor }} ACTOR_EMAIL: ${{ github.event.client_payload.actor_email }} REPO_ACCESS_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }} KUBECONFIG: "./kubeconfig" INIT_BIG_REPO: ${{ github.event.client_payload.init_big_repo }} NOMS_BIN_FORMAT: "__DOLT__" TEMPLATE_SCRIPT: ${{ github.event.client_payload.template_script }}
بمجرد تشغيل وظيفة K8s المعيارية في وضع “التوصيف”، يمكننا رؤية الخطوات التي يتم تنفيذها في الرسم التخطيطي المحدث. نرى أيضًا أن مخرجات هذه الوظيفة عبارة عن ملف تعريف جديد لـ Golang، تم تحميله إلى S3، وهو جاهز للاستخدام في الخطوات المتبقية من عمليتنا لإنشاء إصدارات pgo.
في نهاية مهمة ملف التعريف K8s، بعد تحميل ملف التعريف، يتم تشغيل سير عمل “Release Dolt”. يعمل سير العمل هذا بشكل أساسي مثل سير العمل الأصلي “Release Dolt”، باستثناء أن خطوته الأولى هي جارى التحميل ملف تعريف Golang الذي تم تحميله بواسطة وظيفة التوصيف.
... create-pgo-release: needs: format-version runs-on: ubuntu-22.04 name: Release PGO Dolt outputs: release_id: ${{ steps.create_release.outputs.id }} steps: - uses: actions/checkout@v4 with: ref: main - name: Set up Go 1.x uses: actions/setup-go@v5 with: go-version-file: go/go.mod - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2 - name: Get Results id: get-results run: aws s3api get-object --bucket="$BUCKET" --key="$KEY" dolt-cpu-profile.pprof env: KEY: ${{ github.event.inputs.profile_key || github.event.client_payload.profile_key }} BUCKET: ${{ github.event.inputs.profile_bucket || github.event.client_payload.bucket }}...
ثم يقوم بتزويد ملف التعريف الذي تم تنزيله، والذي يسمى هنا dolt-cpu-profile.pprof
إلى buildbinaries.sh
البرنامج النصي الذي يعمل go build -pgo=./dolt-cpu-profile.pprof
، الذي يجمع ثنائيات Dolt الجديدة. بعد ذلك، مثل الإصدار الأصلي لسير العمل، يقوم بإنشاء إصدار GitHub وتحميل هذه الثنائيات كأصول إصدار.
قبل الانتهاء، تبدأ إحدى المهام النهائية في سير العمل هذا مهمة K8s المعيارية الأخرى فقط هذا الوقت لتزويد المهمة بمفتاح S3 لملف تعريف Golang الذي استخدمته لإنشاء ثنائيات Dolt.
... trigger-performance-benchmark-email: needs: [format-version, create-pgo-release] runs-on: ubuntu-22.04 steps: - name: Trigger Performance Benchmarks uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.REPO_ACCESS_TOKEN }} event-type: release-dolt client-payload: '{"version": "${{ needs.format-version.outputs.version }}", "actor": "${{ github.actor }}", "profile_key": "${{ github.event.inputs.profile_key || github.event.client_payload.profile_key }}"}'
يؤدي هذا إلى نشر مهمة قياس الأداء إلى مجموعة K8s الخاصة بنا مرة أخرى، ولكن الآن ستقوم الوظيفة بتنزيل ملف تعريف Golang من S3 واستخدامه لإنشاء ثنائيات pgo الخاصة بـ Dolt لاستخدامها في قياس الأداء وإنتاج النتائج.
ويمكننا أن نرى من الرسم البياني في سياق K8s، أن الخطوة الأخيرة من مهمة القياس الثانية هذه تبدأ سير عمل “فريق البريد الإلكتروني”، بحيث يحصل فريقنا على نتائج قياس الأداء لـ Dolt المجهز الآن.
وهكذا فعلنا ذلك! نقوم الآن بإصدار إصدارات pgo من Dolt.
خاتمة
كما ترون، هناك القليل من التعقيد في تحديث عملية الإصدار لإنتاج ثنائيات pgo، على الأقل كان هذا هو الحال بالنسبة لنا. لكن الجهد كان يستحق بالتأكيد مكاسب الأداء التي شهدناها.
أتمنى أن تجد هذا مفيدًا لمساعيك الخاصة، ونحن نشجعك على محاولة تحديث إصداراتك أيضًا. إذا قمت بذلك، فنحن نحب أن نسمع عنها. تفضلوا وشاركوا تجربتكم على موقعنا الفتنة.
ولا تنس أيضًا التحقق من عروض منتجاتنا المختلفة أدناه:
- الأبله– إنه Git للبيانات.
- دولتهب– إنه GitHub للبيانات.
- دولتلاب– إنه GitLab للبيانات.
- استضافت دولت– إنه RDS لقواعد بيانات Dolt.