“VŨ KHÍ TỐI THƯỢNG” KẾT NỐI DATABASE

Khi làm việc với cơ sở dữ liệu cho những hệ thống tương đối lớn thì vấn đề rất quan trọng đó là đảm bảo yêu cầu hiệu năng cao. Một trong những vấn đề cần thiết nhất đó là phải xử lý để tối ưu số kết nối tới cơ sở dữ liệu. Đối với lập trình viên mới vào nghề, bình thường với mỗi client request sẽ mở 1 kết nối tới database server và rồi lại đóng lại. Việc tạo và hủy các kết nối tới Database sẽ ảnh hưởng rất nhiều tới hiệu năng của ứng dụng bởi chúng cần thực hiện tiến trình quản lý tài nguyên cơ sở dữ liệu.

Connection pool (tạm dịch là vùng kết nối): là kỹ thuật cho phép tạo và duy trì 1 tập các kết nối dùng chung nhằm tăng hiệu suất cho các ứng dụng web bằng cách sử dụng lại các kết nối khi có yêu cầu thay vì việc tạo kết nối mới.

Connection pool cho phép ta tạo một tập các connection trong bộ nhớ đệm, với mỗi request đến database, connection pool sẽ “phân phát” cho request đó một connection trong số các connection đang rảnh. Mỗi một connection sau khi hoàn thành nhiệm vụ sẽ không bị đóng mà sẽ quay về pool và chờ để thực hiện những kết nối tiếp theo. Trường hợp mà tất cả các connection trong pool đều bận, request phải chờ cho có ít nhất 1 connection trong pool hoàn thành nhiệm vụ mới có thể kết nối vào database.

 

Tự làm một Connection Pool đơn giản

Để làm một connection pool, chúng ta cần hiểu nguyên lý hoạt động của pool.

  • Khi khởi tạo một connection pool, connection pool sẽ khởi tạo một số connection trong pool để sẵn sàng sử dụng. Connection pool có thể lưu các connection ở một Araylist, một Blocking queue, …..
  • Khi có một request đến, pool sẽ tự động lấy ra một connection đang ở trạng thái chờ. Nếu trong pool không có connection sẵn sàng và số connection tạo ra nhỏ hơn số connection tối đa, một connection mới được tạo ra, bỏ vào trong pool và lấy ra.
  • Song song với quá trình cung cấp các connection, pool tạo  một thread để loại bỏ các connection timeout và thay thế chúng bằng connection mới.
  • Connection sau khi hoàn thành nhiệm vụ sẽ được đưa trở lại pool để phục vụ những kết nối tiếp theo.

Ví dụ cụ thể

Tạo một abstract thread


public abstract class AbsThread extends Thread{
@Override
public void run() {
while(true) {
synchronized (this) {
try {
sleep(10);
} catch (Exception e) {
					logger.info(e);
}
}
}
}
public abstract void execute();


Tạo một class để làm class config


public class DBConnectionPoolConfig {
private static final String SERVER_NAME = "localhost"; 
	public static final int MAX_POOL_SIZE = 20;
public static final int MIN_POOL_SIZE = 5;
public static final int INIT_POOL_SIZE = 10;
public static final String DB_PORT = "1521";
public static final String USERNAME = "vietlot";
public static final String PASSWORD = "hoi1999bac";
public static final String SID = "orcl";
public static final String URL =  "jdbc:oracle:thin:
                                     @" + SERVER_NAME + ":" + DB_PORT + ":" + SID;
public static final long TIME_OUT = 200;
}

 

Mỗi connection trong một pool sẽ định nghĩa nó với tên connectionCell


// This class contain Connection and check Connection close and get Timeout
public class DBConnectionCell {
private String username;
private String password;
private String url;
private long relaxTime;
private long timeOut;
Logger logger = Logfactory.getLogger(DBConnectionCell.class);
Connection conn;
public Connection getDbConnection() {		
		return conn;
}
public long getRelaxTime() {
return relaxTime;
}
public long getTimeOut() {
return timeOut;
}

        // Tạo mới một connection
public DBConnectionCell
                (String username, String password, String url, long relaxTime) {
super();
this.username = username;
this.password = password;
this.url = url;
this.relaxTime = relaxTime;
try {
			conn = DriverManager.getConnection
                (DBConnectionPoolConfig.URL, DBConnectionPoolConfig.USERNAME, 
                DBConnectionPoolConfig.PASSWORD);
} catch (SQLException e) {
			logger.info(getInformation());
} 
	}
        
	public boolean isTimeOut() {
if(System.currentTimeMillis() - relaxTime > timeOut) {
return true;
}
return false;
}
public void close() throws Exception{
try {
			conn.close();
} catch (Exception e) {
			logger.warn(getInformation(), e);
}
}
public boolean isClosed() throws Exception{
return conn.isClosed();
}
public String getInformation() {
String infor = "\nInfor :  Connection 
                ( URL :"+url+" , User name : "+username+", 
                Password : "+password+", "+conn.toString()+" )";
return infor;
}
        
	public void setRelaxTime(long relaxTime) {
this.relaxTime = relaxTime;
}

 

Class ConnectionPool


public class BaseConnectionPool {
Logger logger = Logfactory.getLogger(BaseConnectionPool.class);
private LinkedBlockingQueue<DBConnectionCell> 
        pool = new LinkedBlockingQueue<DBConnectionCell>();
protected int numOfConnectionCreated = 0;
protected String sid;
protected int max_pool_size;
protected int init_pool_size;
protected int min_pool_size;
protected long time_out = 10000;
protected String url;
protected String user;
protected String password;
protected Thread thread;
protected long start_time;
protected long end_time;
protected static BaseConnectionPool instancePool;
public BaseConnectionPool() {
}
//Setting for Pool
public synchronized static BaseConnectionPool getInstace() {
if (instancePool == null) {
			instancePool = new BaseConnectionPool();
			instancePool.setInit_pool_size
(DBConnectionPoolConfig.INIT_POOL_SIZE);
			instancePool.setMax_pool_size
(DBConnectionPoolConfig.MAX_POOL_SIZE);
			instancePool.setMin_pool_size
(DBConnectionPoolConfig.MIN_POOL_SIZE);
			instancePool.setUrl
(DBConnectionPoolConfig.URL);
			instancePool.setUser
(DBConnectionPoolConfig.USERNAME);
			instancePool.setPassword
(DBConnectionPoolConfig.PASSWORD);
			instancePool.setTime_out(DBConnectionPoolConfig.TIME_OUT);
			instancePool.sid = DBConnectionPoolConfig.SID;
			instancePool.thread = new AbsThread() {
/*
			* When the number of connection > min connection , close TimeOut Connection
			*/
@Override
public void execute() {
for (DBConnectionCell connection : instancePool.pool) {
if (instancePool.numOfConnectionCreated > instancePool.min_pool_size) {
if (connection.isTimeOut()) {
try {
					connection.close();
					instancePool.pool.remove(connection);
					instancePool.numOfConnectionCreated--;
} catch (Exception e) {
					logger.info("Waring : Connection can not close in timeOut !");
}
}
}
}
}
};
}
return instancePool;
}
public void start() {
		logger.info("Create Connection pool........................ ");
// Load Connection to Pool
		start_time = System.currentTimeMillis();
try {
for (int i = 0; i < init_pool_size; i++) {
DBConnectionCell connection = new DBConnectionCell(url, user, password, time_out);
				pool.put(connection);
				numOfConnectionCreated++;
}
} catch (Exception e) {
			logger.warn(String.format(
"[Message : can not start connection pool] - [Connection pool : %s] - " + "[Exception : %s]",
this.toString(), e));
}
		thread.start();
		end_time = System.currentTimeMillis();
		logger.info("Start Connection pool in : " + end_time + start_time + " ms .");
}

 


public synchronized DBConnectionCell getConnection() {
DBConnectionCell connectionWraper = null;
if (pool.size() == 0 && numOfConnectionCreated < max_pool_size) {
			connectionWraper = new DBConnectionCell(url, user, password, time_out);
try {
			pool.put(connectionWraper);
} catch (InterruptedException e) {
			logger.warn("Can not PUT Connection to Pool, Current Poll size = " + pool.size()
+ " , Number Connection : " + numOfConnectionCreated, e);
				e.printStackTrace();
}
			numOfConnectionCreated++;
}
try {
			connectionWraper = pool.take();
} catch (InterruptedException e) {
			logger.warn("Can not GET Connection from Pool, Current Poll size = " + pool.size()
+ " , Number Connection : " + numOfConnectionCreated);
			e.printStackTrace();
}
		connectionWraper.setRelaxTime(System.currentTimeMillis());
return connectionWraper;
}
public void releaseConnection(DBConnectionCell conn) {
try {
if (conn.isClosed()) {
				pool.remove(conn);
DBConnectionCell connection = new DBConnectionCell(url, user, password, time_out);
				pool.put(connection);
} else {
				pool.put(conn);
}
} catch (Exception e) {
			logger.info("Connection : " + conn.toString(), e);
}
}
@Override
    public String toString() {
        return "ConnectionPool{" +
                "pool=" + pool +
                ", max_pool_size=" + max_pool_size +
                ", init_pool_size=" + init_pool_size +
                ", min_pool_size=" + min_pool_size +
                ", time_out=" + time_out +
                ", url='" + url + '\'' +
                ", user='" + user + '\'' +
                ", password='" + password + '\'' +
                '}';
    }


Qua bài viết này, Hybrid Technologies muốn giới thiệu đến các bạn một công cụ lợi hại: Connection pool và lợi ích nó mang lại. Các bạn có thắc mắc hay góp ý, hãy comment ở bên dưới nhé, chúng mình rất sẵn lòng lắng nghe ý kiến của các bạn!

Nguồn: Sưu tầm.

Facebook Comments
Đánh giá bài viết

Bạn thích bài viết này chứ?
Đăng ký để nhận những bài viết thú vị như thế hàng tuần.

Đừng sợ thất bại, chỉ sợ việc dậm chân tại chỗ

TÌM VIỆC
Bình luận