Introduction to Alitelecom's basic communication technology structure - Alibaba Cloud Developer Forums: Cloud Discussion Forums

  • UID63
  • Fans7
  • Follows1
  • Posts67

Introduction to Alitelecom's basic communication technology structure

More Posted time:Jan 22, 2016 18:29 PM
Introduction to Alitelecom's Basic Communication Technology Structure

By Babo from Alibaba Group

I. Outline                                                                                                                                                                                
When we work on projects such as Alitelecom Billing, we select the most common utility classes to establish a base library. While working on Ali Telecom’s project, I have found several very useful tools that I would like to share in the introduction below.  Dependent library:

The following points will be discussed:
1. The DAO process; flexible database and table sharding policies that support free custom database and table sharding rules;
2. The use of annotations to achieve method-level cache; control cache updates through diamond configuration;
3. The implementation of distributed lock through Tair;
4. Convenient JMX support through appropriate annotations;
5. Communication clients such as HTTP/HTTPS, FTP/ FTPS, SFTP and OSS;
6. Some other utility classes including:
a. FrameDiamondUtil: to read Diamond configurations, monitor diamond configuration changes and save to internal cache without writing a listener
b. FrameBeanFactory: convenient access to Spring beans
c. FrameTimeUtil: convenient time handling function, thread-safe, Joda-based time handler class with fast performance
d. JacksonUtil: JSON processing with Jackson; EncryptUtil: 3DES; Md5Util: generation of MD5

In the second section, I will elaborate on some of the above mentioned points.

II. DAO operation and convenient database and table sharding support                                                                        
1. Let me begin by introducing the standard procedure of DAO operation using Spring + iBATIS.
a. The datasource configuration should be the initial step as it is a crucial one. We usually use the Group layer of TDDL to configure appName and dbGroupKey of the corresponding data source. Each bean corresponds to one data source.

b. Compose the sqlmap file: xxxxx1_sqlmap.xml and xxxxx2_sqlmap.xml. Each table corresponds to one sqlmap. Reference the sqlmap file in the sqlMapConfig.

c. Configure sqlMap operation class, sqlMapClient or sqlMapClientTemplate. It is necessary to configure sqlMapConfig and DataSources properties. Each DataSource corresponds to one sqlMapClient.

d. Compose the DAO class. Depending on the operation types, sqlMapClient or sqlMapClientTemplate perform certain sqlmap statements.
If it involves database and table sharding, it is necessary to provide further processing. Table sharding means the corresponding table name in sqlmap is composed by external parameters. Usually, we will write TableRoute and splice table names accordingly. Database sharding essentially uses sqlMapClient of a different DataSource. We usually write DbRoute and locate sqlMapClient according to the rule.
When it involves a transaction, we need to add configuration processing related to the transaction. The traditional way of doing it may lead to some problems such as:
• Redundant and complicated configurations;
• Inflexible database and table sharding rules. Database and table sharding operations have a great impact on DAO code.
2. What do we offer?
a. Configuration files:
• persistence.xml: Configuration of the datasource is necessary. The configuration of the sequence should follow the original transaction configurations.
However, there is no need to manually configure sqlMapClient or SqlMapClientTemplate. It is necessary to set the mapping relation between the DAO path and the data source. For database sharding, it is necessary to add the wildcard DBNAME.
• sql-map-config.xml and sql-map-null.xml files (no need to change)
One is sqlMapConfig global configuration. The other file only contains the schema and is used as the internal structure template.
b. Naming and directory convention
All DAO files are in the dao directory. All DO files are in the dataobject directory and the directories are parallel.
The DAO implementation class is called xxxx DAOImpl and the corresponding DO class is called xxxxDO.
Further clarifications for the convention will be provided at a later point.
c. The DAO implementation class inherits from the BaseDAO. The annotation specified sqlMap file is automatically registered
as a bean.
d. The DO implementation class inherits from the BaseDO. The database sharding rules are achieved through @DbDefine and table sharding rules, through @TableDefine.
We use code generators to build DAO/DO and SQLMAP code. These processes are completely automated.
e. Special introduction of database and table sharding
 • Change the table name of sqlmap file to
 _TABLE_NAME_ such as:

• Add annotation @TableDefine to the DO class.
The content in “[]” can define the table sharding key and key conversion rules. As shown in the above example, gmt_create is the table sharding key. Conversion rules can be seen in the monthTableConvert class.  
Besides, multiple “[]” can be used to define more complicated table sharding rules. For example:

• If it does not involve database sharding, we can get the final DS through mapping the DAO path and DataSource.
• If it involves database sharding, what we get from the mapping rules will be the DS name with a wildcard DBNAME. It is necessary to add annotation @DbDefine on the DO class. The usage is the same as @TableDefine. Through the annotation, we can define the database sharding key and database conversion method class and finally we will be able to replace the wildcard and get the real DS.
• Regarding the DAO implementation method, we can pass parameters to the final sqlmap through DO, Query and Map objects. If it involves database and table sharding, the object must contain the table sharding key field.
3. Implementation
• AbstractConvert
Abstract class of all the database and table sharding rules. Specific database and table sharding rules are available through implementation of this class.
For instance, 64 tables by ID modulus, four databases by ID modulus, monthly table sharding by timestamp, daily table sharding by time stamps and yearly table sharding by time stamps.
There are two methods to implement:
String getDefaultKey() If the external annotation does not specify the database or table sharding key, this is the default key.
String convert(String key,Object) It controls how to convert specific database and table sharding logic.
It provides set_TABLE_NAME_() for table sharding.
Base classes of all the DAO operations.  
At initialization:
Get sqlmap path with @SQLMap annotation.  
Find the same-level DO (according to the previous DAO and DO naming conventions).  Identify the database sharding and its rules based on the presence of @DbDefine annotation, and table sharding and its rules based on the presence of @TableDefine annotation.
In SQL operations, SqlMapClientTemplate is gained through the getTemplate method.
The principal operations include: For non database sharding, DS name is directly obtained based on the packet path mapping. For database sharding, the wildcard is replaced according to the database sharding rules. The DS is obtained and the data source is constructed according to DS (the data source is built upon initial operation and obtained from the Map in subsequent operations). For table sharding, the final table name is obtained according to sharding rules and it will be passed to sqlmap through objects.

III. FrameDiamondUtil: easy-to-use Diamond utility class                                                                                                      
1. General usage of Diamond
Diamond is a great asset. A lot of dynamically configured business scenarios inside Alibaba are achieved with Diamond. You can find an introduction to Diamond on the Internet.
There are two principal Diamond usages:
• Diamond.getConfig(dataId,group,timeoutMs)
• Diamond. addListener(dataId,group,new ManagerListenerAdapter()
{ public void receiveConfigInfo(String configInfo) { …}
To this end, we need to add the init method to the class using Diamond, get appropriate configuration by calling getConfig and assign values to our business variables.
We can add a listener to implement the receiveConfigInfo method. We have to replace the business variables when Diamond configuration changes.
2. What do we offer?
It may look not elegant to add the code to every class that uses Diamond. We want to find a utility class so that we can obtain the Diamond configuration values directly through static methods. At the same time, we can make related Diamond code for pushing updates implicitly transparent to the caller.
FrameDiamondUtil is the type of utility class which provides public static String getConfig(String dataId,String group,long timeoutMs). External users only need
to call this static method and assign values.

If you want to return conversions instead of original configuration String content, you can call public static Object getConfig(String dataId,String group,long
timeoutMs,Convert convert) and implement the Convert class.
3. Implementation
Actually, it is quite simple. You need to build a Map. When you call getConfig from the Map, use group^dataId as the key. If this is the first call, call Diamond.getConfig and register a listener.

Replace the Map content in the listener code.

IV. Implementation of method-level cache through annotations                                                                                              
1. What kind of problems may be solved?
I think we are familiar with the method of using AOP to separate cache implementation and business logic. For example, by using the SpringCache framework, we can implement method-level cache through annotations.
Please visit for an introduction to SpringCache.
Our structure is based on SpringCache with some extensions. With the help of Diamond, we can update the cache regularly without having to reboot.
2. What do we offer?
To implement method-level cache through Spring annotations, we support caching to local JVM or Tair and the local cache follows the LRU policy. Cache lifecycle management is conducted through Diamond.
a. Statement annotation

b. The configuration file designates the Diamond to be managed and cacheManager configuration.

c. Cache can be implemented through an annotation of the given method.
d. Cache lifecycle management using Diamond
 When the time is greater than the configured content, you can refresh the cache (i.e., replace the cache key). However, it looks like refreshing the cache.

3. Implementation
a. Global dependency on SpringCache.
b. Implementation of Cache interface of SpringCache.  
The local cache uses Google's concurrentlinkedhashmap. When maximum memory usage is reached, it adopts LRU.
Determine whether Tair shall be used through configuration. If enableTair is configured, Tair will be read when the local cache cannot be read. Local cache and Tair
will be put together.

c. Special implementation of the SpringCache KeyGenerator.  
We often adopt DefaultKeyGenerator when using SpringCache and we build the key with the method name and parameter name (some define the key with expressions).
We have a special implementation of KeyGenerator. Besides the method name and parameter name, the time stamp from Diamond configuration serves as a key prefix. If Diamond content changes, the corresponding key will change. At this time, if you change the key, you will not get the cache and it will trigger a real method call. If the cache key does not change in the second call, it will be able to read the cache.

V. Distributed lock                                                                                                                                                                  
1. Introduction
The distributed lock is implemented based on the atomic operations of Tair.
2. Usage
a. Implement TairLockObject
Take CreditAcctIdLock for example. Identify the prefix of lock key: KEY_PREFIX, identify the CONFIG_PREFIX. and pass acctId into the constructor.

b. Using lock
Construct an object: AcctIdLock lock = new AcctIdLock(6536182776198L);
 Get the lock: lock.acquire();
 Release the lock: lock.release().
3. Implementation
It is dependent on the atomic operations of Tair.
TairLockObject determines the composition of the key, and the method to get the Tair configuration (e.g.: database or configuration file). It also involves obtaining some policies of the lock, such as the number of lock failure retries and the wait time.
 Add lock: implement tairManager.incr based on key.
 Release lock: implement tairManager.delete based on key.

VI. Conclusion                                                                                                                                                                      
I hope that the above introduction is helpful towards accomplishing the specific business objectives while providing some reference for future projects.
[Cloudy edited the post at Jan 22, 2016 20:18 PM]