Sức mạnh của Index trong Database

Việc nghe nói về tác dụng của Index trong quá trình Turning Database nói chung và Oracle nói riêng từ rất lâu. Việc cảm nhận thấy được tốc độ truy vấn, các chỉ số liên quan tới quá trình Turning như I/O… trong quá trình thực thi thấy rất rõ ràng. Những việc này mình thấy được do những người khác chỉ, bản thân thấy được trước và sau quá trình người khác đánh Index để sử dụng. Về tầm quan trọng và sức mạnh của Index trong Database là không cần bàn cãi.

Vừa rồi mình có phải build một luồng nghiệp vụ hoàn toàn mới cho một quy trình nghiệp vụ mới. Cụ thể là mỗi một khách hàng mới cần phải có một mã OTP để nhắn tin xác thực số điện thoại. Mã OTP là ngẫu nhiên, có thể là chữ hoặc số.
Sau khi phân tích và họp, hệ thống sẽ sinh trước mã OTP. Mỗi mã OTP gồm 5 ký tự có thể có cả chữ hoặc số. Toàn bộ các mã OTP này được sinh ra và lưu vào 1 bảng, hàng ngày hệ thống sẽ quét các khách hàng mới và tiến hành cập nhật ngẫu nhiên vào bảng này. Bảng này sẽ có (10+26)(10+26)(10+26)(10+26)(10+26) = 60 triệu dòng.
Hàng ngày có dưới 1000 khách hàng mới nên hệ thống xử lý cũng hơi chậm nhưng không có gì đáng ngại khi lấy ngẫu nhiên các mã OTP để cập nhật khách hàng, lấy ngẫu nhiên mỗi mã OTP mất hơn 1s.

Nhưng hôm vừa rồi, hệ thống cần đồng bộ gần 100.000 khách hàng mới vào và cũng có yêu cầu xác thực nên phải lấy ngẫu nhiên từng đó mã OTP. Việc này khi chạy thì đúng là không ổn chút nào. Nếu để chạy bình thường thì phải vài ngày mới có thể chạy xong, như vậy không đảm bảo tiến độ. Tình thế này buộc mình phải xem lại phương thức lấy ngẫu nhiên mã OTP. Vì không muốn thay đổi quy tắc lấy ngẫu nhiên nên mình tập trung vào tối ưu câu truy vấn. Khi kiểm tra độ phức tạp và I/O của câu lệnh lấy thì mình thấy việc lấy mã OTP rất nặng. Phải thôi, lấy ngẫu nhiên 1 trong 60 triệu dòng mà phải loại đi những mã OTP đã qua sử dụng thì khá nặng rồi.
Mình kiểm tra thì đúng là mình chưa đánh Index cho bảng này, thế là việc đầu tiên mình tiến hành đánh Index và đo lại thì hiệu quả thật không ngờ. Tốc độ lấy mã OTP của một khác hàng giảm xuống còn ~0.0016s. Mình chạy cho 100.000 khách hàng mất chưa tới 3 phút là xong. Công việc hàng ngày khoảng 1000 khách hàng thì chưa tới 2s đã chạy xong.

Sử dụng Index còn cần phải quan tâm đến quá trình Insert, Update dữ liệu. Nhưng hệ thống mình thì trường đánh Index này chỉ sinh ra một lần và không có thao tác update vào trường Index nên không phải quan tâm đến nó. Sau việc này đúng là mình đã thực sự bị thuyết phục bởi sức mạnh của Index trong Database. Bài học sau này cần vận dụng nhiều hơn tới Index trong quá trình triển khai hệ thống.

Monorepos vs Multilrepos

Lang thang trên mạng tự nhiên gặp bài viết này [1] nên tò mò xem Momorepos là gì? Sau đó tìm hiểu thêm google thì có bài viết [2] [3] [4] giải thích và cho ví dụ khá rõ ràng.

Thì ra nó liên quan đến việc quản lý mã nguồn của dự án. Trước đây mình không để ý lắm nên không biết phân biệt giữa 2 khái niệm này. Khi dùng SVN thì công ty mình dùng theo kiểu Monorepos(mặc dù chưa biết đến thuật ngữ đó), nghĩa là có một Repository duy nhất được tạo ra, các dự án khác nhau đều tống chung vào đó, mỗi dự án là một thư mục được tạo ra. Tất nhiên vẫn phân quyền được bình thường theo từng thư mục.

Sau này khi chuyển sang Gitlab cùng với việc phát triển Microservice nên trên Gitlab mỗi một project thì đều tạo Repository riêng cho nó. Tương đương trên github mình làm các project nhỏ nhỏ khác cũng như vậy.

Sơ sơ thì mỗi cái lại có ưu và nhược điểm nhưng thấy nhiều ý kiến cho rằng đối với Startup và Công ty lớn ưa chuộng việc dùng Monorepos hơn như Google, Facebook…

[1]: https://medium.com/@hoangbkit/why-monorepo-in-2018-89221acd4bfb
[2]: https://www.reddit.com/r/devops/comments/8vgqhq/what_do_you_prefer_and_why_mono_repo_or_multiple/
[3]: https://www.atlassian.com/git/tutorials/monorepos
[4]: https://medium.com/@patrickleet/mono-repo-or-multi-repo-why-choose-one-when-you-can-have-both-e9c77bd0c668

Config send email from oracle database server

ORA-24247: network access denied by access control list (ACL)

Kiểm tra bằng cách chạy câu lệnh

select * from dba_network_acls;

Nếu có data dạng:

 HOST LOWER_PORT UPPER_PORT ACL  ACLID
 mail.vstv.vn    1   1024    /sys/acls/send_mail.xml D285E04B69B942688587AB8FE5B41C69 

Chạy câu lệnh này:

BEGIN
   DBMS_NETWORK_ACL_ADMIN.create_acl (
     acl          => 'send_mail.xml',
     description  => 'Purpose of the acl is to send mail',
     principal    => 'INTRANET',
     is_grant     => TRUE,
     privilege    => 'connect',
     start_date   => SYSTIMESTAMP,
     end_date     => NULL);
 DBMS_NETWORK_ACL_ADMIN.assign_acl (
     acl         => 'send_mail.xml',
     host        => 'mail.trituenhantao.info',
     lower_port  => 1,
     upper_port  => 1024);
 COMMIT;
 END;

Plugin Compare for Notepad++

Before, I usually using SVN to find the different points of version source code. But recently, I don’t use SVN or Source Code Management Tools other. Today, I can find the difference of a package Oracle with version before we upgrade.
I was recommended using plugin Compare for Notepad++ to work this it. It is perfect for me.

We has two ways to install Plugin Compare for Notepad++:
1: Install from Plugin Manager
Choice menu Plugins -> Plugins Admin…
Search: Compare and tick on Compare. Click Install.
After that, dialog display Notepad++ is about to exit ask confirm Notepad++ will restart to Apply plugin.
2: Install from package dowload
Dowload the last version Compare Plugin on link: https://sourceforge.net/projects/npp-compare/
Unzip file dowloaded, we have file ComparePlugin.dll
Choice Settings -> Import -> Import plugin(s)… Select the file ComparePlugin.dll

To compare, we open two file and select Plugins -> Compare -> Compare
Or press Alt + D

Thông tin file mới nhất được sửa đổi là bao giờ

Hệ thống của mình cập nhật thông tin vào một file khi có sự kiện xảy ra. Nếu hệ thống gặp trục trặc sẽ không cập nhật thông tin và sẽ gây lỗi hệ thống sau đó. Thỉnh thoảng sẽ bị lỗi như vậy mà không rõ nguyên nhân.
Mình đành viết một đoạn Script chạy 15 phút 1 lần kiểm tra xem thời gian cuối cùng nó được sửa và gửi email cho mình. Nếu vài lần liên tiếp mà file không được cập nhật thông tin thì khả năng có chuyện xảy ra và cần vào server để kiểm tra.

 import os
 from subprocess import Popen, PIPE
 import smtplib
 import sys
 from datetime import datetime, timedelta
 import os.path, time
 now = datetime.now()
 yesterday=datetime.strftime(datetime.now() - timedelta(1), '%Y%d%m')
 subject = "Last modified file Z:\TRITUE.R.S.sec" + '\n\r'
 msg = "Last modified: " + str(datetime.fromtimestamp(os.path.getmtime("Z:\TRITUE.R.S.sec")))
 msg = "ABC-"+ str(datetime.fromtimestamp(os.lstat('Z:\TRITUE.R.S.sec').st_mtime))
 sender = '[email protected]'
 message = 'From: Mail [email protected] ' + '\n' + 'To: '
 receivers = ['[email protected]','[email protected]']
 receivers = ['[email protected]']
 count = 0
 receipent_list = ''
 for each_receipent in receivers:
     if count < len(receivers) -1:
         receipent_list = receipent_list + each_receipent + ','
     else:
         receipent_list = receipent_list + each_receipent
     count = count + 1
 message = message + receipent_list + '\n'
 message = message + 'Subject: ' + subject + '\n\r'
 message = message + msg + '\n'
 try:
    smtpObj = smtplib.SMTP('mail.trituenhantao.org')
    smtpObj.sendmail(sender, receivers, message)         
    print("Successfully sent email")
 except SMTPException:
    print("Error: unable to send email")

Unlock user Workspace Administrator on Apex

Bên mình làm hệ thống báo cáo bằng Apex. Khi muốn tạo hoặc sửa báo cáo phải vào trang quản trị ứng dụng với tài khoản:
DB: XXX
User: ADMIN1
Pass: Abcd1234
Hôm nay vào vì bị lock do nhiều lần nhập sai mật khẩu.

Địa chỉ để vào quản trị ứng dụng là http://111.111.111.111:7778/apex/
Địa chỉ để vào ứng dụng là: http://111.111.111.111:7778/apex/f?p=104:LOGIN:11636406781643:::::

Ứng dụng vẫn vào được bình thường nhưng phần quản trị ứng dụng bị báo lock user.

Các bước để unlock:
B1: Vào CMD gõ lần lượt các lệnh sau:

sqlplus /nolog
connect /as sysdba
alter session set current_schema = APEX_050100;
commit;
UPDATE Apex_050100.Wwv_Flow_Fnd_User

SET Web_Password = 'Abcd1234'

WHERE User_Name = 'ADMIN'

AND Security_Group_Id = 10;

COMMIT; 
begin
wwv_flow_security.g_security_group_id := 10;
wwv_flow_fnd_user_api.UNLOCK_ACCOUNT('ADMIN');
commit;
end;

Nếu cmd không tự ngắt để enter lệnh thì gõ / và nhấn Enter.

B2: Sửa trên ứng dụng

Địa chỉ quản trị Workspace: http://111.111.111.111:7778/apex/f?p=4550:10:13666886988498::NO:::
Đăng nhập với tài khoản: ADMIN / Abcd1234

Bấm vào Manage Workspaces.
Chọn Manage Developers and Users trong mục Workspace Actions
Chọn User cần Unlock, ở đây là ADMIN1
Tìm đến mục Account Availability. Chọn Unlocked.

Thế là xong, chỉ cần vào lại trang quản trị ứng dụng và nhập thông tin cũ là được.

Cài đặt Oracle 11g, 12c

Thử cài đặt Oracle trên Máy ảo linux hoặc window

https://o7planning.org/vi/10347/huong-dan-cai-dat-va-cau-hinh-database-oracle-12c

https://o7planning.org/vi/10211/huong-dan-cai-dat-va-cau-hinh-database-oracle-11g

Một chiến lược đảm bảo an toàn dữ liệu

Hiện mình đang làm cho một công ty X về việc cung cấp dịch vụ cho khách hàng. Hệ thống lưu trữ thông tin khách hàng bao gồm nhiều thứ như họ tên, số điện thoại email, thời hạn dịch vụ, lịch sử thanh toán…

Như các bạn đã biết, dữ liệu về khách hàng của công ty là cực kỳ quan trọng. Bài toán đảm bảo an toàn dữ liệu khách như vấn đề bảo mật, tránh mất mát dữ liệu, đảm bảo hệ thống luôn sẵn sàng… là những bài toán lớn cần được giải quyết. Qua tìm hiểu hệ thống và cóp nhặt trên mạng, mình nốt lại một số thông tin về lý do và cách thức việc đảm bảo an toàn dữ liệu.

Dữ liệu thì được nằm trên cơ sở dữ liệu, từ đó các ứng dụng truy cập vào hệ thống để thực hiện các thao tác xem, thêm, sửa xóa dữ liệu. Cơ sở dữ liệu luôn phải được đảm bảo sống, nghĩa là bất kỳ lúc nào cũng có thể truy vấn được. Tuy nhiên, không phải lúc nào hệ thống cũng ổn định, có thể lỗi ở phía server(phần cứng), lỗi ở phía hệ điều hành, lỗi ở phía hệ quản trị cơ sở dữ liệu…

Sau đây mình liệt kê các mức của hệ thống:

Tính sẵn sàng của hệ thống

Hiện tại hệ thống bên mình chỉ có duy nhất một DB đang Active. Hàng giờ hệ thống liên tục đồng bộ sang 2 DB ở chế độ Standby. Chỉ khi nào xảy ra sự cố đặc biệt nghiêm trọng, DB đang Active nguy cơ không thể hồi phục trong thời gian dài thì 1 trong 2 DB này mới được bật lên ở chế độ Active. Như vậy tính rủi ro khá cao.
Ở công ty Y cũ mình thì sử dụng cơ chế 3 Node DB để đảm bảo tính sẵn sàng của hệ thống. Nghĩa là hệ thống luôn luôn có 3 DB đều ở chế độ Active, sử dụng công nghệ RAC của Oracle. Khi 1 DB (1 Node) gặp trục trặc thì hệ thống vẫn hoạt động được bình thường. Tuy nhiên khả năng Failover của hệ thống thì mình không dám chắc (Failover là khái niệm về việc giao dịch đang xử lý ở Node lỗi có tiếp tục được xử lý ở Node khác không).

Đảm bảo an toàn dữ liệu

Mô hình hệ thống Active – Standby thì sau một khoảng thời gian cần phải cập nhật thông tin từ con Active sang con Standby sử dụng công nghệ Archive log của Oracle để copy các sự thay đổi sang con Standby. Hiện tại có 2 con Standby, một con nằm cùng Data Center với con Active, một con Standby nằm ở một Data Center khác.

  • Đối với việc lỗi phần cứng của con Active, trong thời gian ngắn không khắc phục được thì con Standby cùng Data Center sẽ được bật lên để tiếp tục đảm bảo dịch vụ.
  • Đối với việc lỗi cả Data Center về phần cứng, hạ tầng mạng… thì buộc phải bật con Standby ở Data Center khác.

Theo khuyến cáo thì các Data Center đặt dữ liệu của hệ thống nên đặt xa nhau hàng trăm KM. Việc này đề phòng các thiên tai có thể xảy đến trên một vùng lớn. Ví dụ bão đổ vào Miền Bắc, cụ thể là Hà Nội. Trường hợp các Data Center ở Hà Nội đều hỏng hết thì khi đó Data Center nằm ở Bình Dương hoặc TP Hồ Chí Minh phát huy tác dụng. Không những việc đảm bảo dịch vụ mà còn đảm bảo về tính toàn vẹn của dữ liệu.
Đối với công ty lớn, dịch vụ có thể là khu vực và toàn cầu thì việc đặt dữ liệu tại Data Center thứ cấp có thể phải đặt ở nước khác hoặc châu lục khác. Việc này đảm bảo khi có chiến tranh hoặc sự tấn công lên tầm quốc gia.

Đây là hiểu biết của mình ở thời điểm hiện tại. Sau mình cần tìm hiểu rõ hơn về các khái niệm: High Availability, Cluster, Network Load Balancer, Failover

Kết nối Python với MariaDB trên Anaconda

Trong nhiệm vụ crawl dữ liệu cho những dự án linh tinh của mình, việc cần thiết là phải lưu trữ lại các dữ liệu trong một hệ quản trị cơ sở dữ liệu nào đó, mình đã chọn MariaDB để làm điều này.
Vì việc lựa chọn Python trên Anaconda để thực hiện nên mình cần một hệ quản trị cơ sở dữ liệu nào đó vừa nhẹ, dễ sử dụng và quen thuộc. Đối với SQL Server và Oracle thì quá quen thuộc nhưng phải cài đặt nó mất rất nhiều thời gian mà không cần thiết vì nó hơi to so với dự án của mình. Với lại Oracle thì mình cũng đã kết nối được với Python rồi. Sử dụng No SQL thì mình đã từng sử dụng Nodejs kết nối với MongoDB thì thực sự mình không ưa cái anh MongoDB này lắm vì thấy cũng hơi phức tạp.
Cái tên quen thuộc nữa là MySQL, ban đầu định dùng nó nhưng đúng là lúc đó đang gặp vấn đề về việc cài đặt Xampp và Wampp lên máy tính ở nhà (do xung đột một số cổng của các phần mềm khác như Skype…). Với có thông tin rằng MySQL dần dần không còn là nguồn mở nữa, anh bạn Oracle đã mua lại và không còn được hào phóng như cộng đồng nguồn mở nữa. Cho nên cái nên MariaDB là lựa chọn cuối cùng của mình.

  • MariaDB là một phiên bản khác của MySQL và được cộng đồng nguồn mở dần chuyển qua để thay thế cho MySQL ngày càng đóng lại.
    Để cài đặt MariaDB thì khá đơn giản, hoàn toàn có thể cài đặt được ở máy tính cá nhân và trên server. Các bạn có thể vào địa chỉ: https://mariadb.com/downloads/#mariadb_platform-mariadb_server để tải về và cào đặt dễ dàng (chỉ cần next thôi).
  • Trong gói này mặc định có một GUID để thao tác các câu lệnh trên đó là HeidiSQL. Ta có thể sử dụng nó để thực hiện các truy vấn cơ bản tới cơ sở dữ liệu MySQL hoặc MariaDB.

Về phần DB là xong, để kết nối từ Python tới MariaDB ta cần sử dụng một thư viện để thực hiện kết nối và thực hiện các câu lệnh như Select, Insert, Update, Delete. Vì MariaDB là một phiên bản được fork từ MySQL nên ta có thể sử dụng thư viện mysql-connector.

Trên Anaconda ta có 2 cách để cài đặt thư viện là:

  1. Vào mục Environments, tìm gói đã được Anaconda tập hợp vừa tương thích Python và tương thích với các thư viện khác.
  2. Nếu cách trên không được do một lỗi nào đó hoặc Anaconda chưa hỗ trợ thì ta có thể cài đặt thực tiếp thông qua dòng lệnh. Có thể tham khảo thông qua hướng dẫn: https://enterprise-docs.anaconda.com/en/latest/data-science-workflows/data/mariadb.html

Khi mọi thứ done ta có thể sử dụng đoạn lệnh sau để test kết nối.

import pandas as pd
 import numpy as np
 import matplotlib.pyplot as plt
 import seaborn as sns
 %matplotlib inline
 from urllib.request import urlopen
 from bs4 import BeautifulSoup
 #
 import MySQLdb
 db = MySQLdb.connect(host="127.0.0.1", port=2017, user="root", passwd="test", db="test")
 c = db.cursor()
 a1="https://trituenhantao.info/posts"
 c.execute("SELECT url FROM test")
 d=c.fetchall()
 a2=0
 for url in d:
     #if url.startswith('http://trituenhantao.info'):
         a2=a2+1
         print(f'{a2} URL: {url}')
         print(url)
 print(c.fetchone())