智付云系統(tǒng)架構(gòu)及配置
1.系統(tǒng)架構(gòu)說明
本文檔描述的智付云系統(tǒng)架構(gòu)脫胎于現(xiàn)有的apoll系統(tǒng)驼仪,并大幅優(yōu)化了系統(tǒng)的并發(fā)性茄螃,可維護(hù)性能搓谆,組件之間的通訊全部使用異步
通訊,使得更有利于適應(yīng)現(xiàn)在的互聯(lián)網(wǎng)的運(yùn)行環(huán)境和開發(fā)模式顽爹。
1.1系統(tǒng)架構(gòu)圖
1.2系統(tǒng)架構(gòu)說明
智付云系統(tǒng)前置接入用ng來做LB處理,利用libev作為socket的異步通訊機(jī)制骆姐,使用flask web框架來作為微服務(wù)架構(gòu)基礎(chǔ)構(gòu)建镜粤。整體架構(gòu)分為3部分,第一部分為python動(dòng)態(tài)加載框架用來加載C玻褪、python或者其他語言編寫的模塊肉渴,第二塊是redis-server服務(wù)端組件,第三塊為流程轉(zhuǎn)發(fā)組件带射。動(dòng)態(tài)組件之間的消息傳遞由redis服務(wù)實(shí)現(xiàn)同规。在一個(gè)交易流程中以xml消息總線維持之間的通訊。如需多次交互窟社,由redis服務(wù)暫存xml消息總線的內(nèi)容捻浦。
1.3Python動(dòng)態(tài)加載框架
此框架由python語言編寫,加載Ctype庫桥爽,從而實(shí)現(xiàn)動(dòng)態(tài)加載C或者其他語言庫的能力朱灿。在動(dòng)態(tài)庫的編寫上力求接口同化,都以int funcname(char * resq,char* resp)的方式命名钠四,其中resq為接收的xml消息總線的內(nèi)容盗扒,resp為返回的消息總線的內(nèi)容及該服務(wù)處理后的結(jié)果。
Python的動(dòng)態(tài)加載框架所需的配置文件存放在智付云mpos/json/和mpos/xml里缀去,由*.json,init_op.xml侣灶,init_func.xml,user.xml缕碎,yl_trans.xml組成褥影,及各用戶文件下的trans_next.xml組成。
1.4Redis服務(wù)組件
Redis是一個(gè)key-value存儲(chǔ)系統(tǒng)咏雌。和Memcached類似凡怎,它支持存儲(chǔ)的value類型相對更多校焦,包括string(字符串)、list(鏈表)统倒、set(集合)寨典、zset(sorted set --有序集合)和hash(哈希類型)。這些數(shù)據(jù)類型都 支持push/pop房匆、add/remove及取交集并集和差集及更豐富的操作耸成,而且這些操作都是原子性的。在此基礎(chǔ)上浴鸿,redis支持各種不同方式的排 序井氢。與memcached一樣,為了保證效率岳链,數(shù)據(jù)都是緩存在內(nèi)存中毙沾。區(qū)別的是redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文 件,并且在此基礎(chǔ)上實(shí)現(xiàn)了master-slave(主從)同步 Redis服務(wù)組件主要的作用為:為各個(gè)組件的通訊提供了mem層的服務(wù)宠页,為多次交互的實(shí)現(xiàn)提供緩存xml數(shù)據(jù)總線的服務(wù)左胞。
Redis服務(wù)較之于傳統(tǒng)的消息隊(duì)列,管道通訊來說有巨大的優(yōu)勢举户。首先redis服務(wù)是基于key_value存儲(chǔ)系統(tǒng)烤宙,這個(gè)特性在高并發(fā)的時(shí)候能夠有效的提供支持。其次在最新的redis中提供了cluster的能力俭嘁,為智付云系統(tǒng)提供了組件集群的能力躺枕。最后,redis提供了比消息隊(duì)列供填,管道豐富多的數(shù)據(jù)類型及操作拐云,基本上一個(gè)redis服務(wù)就可以完全滿足現(xiàn)有或者將來的組件通訊及緩存、高并發(fā)的所有需求近她。
1.5服務(wù)轉(zhuǎn)發(fā)組件
本組件由Python語言編寫叉瘩,通過加載json文件夾里的配置文件來驅(qū)動(dòng)交易流程。
Json文件夾里的配置流程粘捎,按功能分可以劃分為3塊(“協(xié)議配置”薇缅,“交易處理配置”,“錯(cuò)誤處理配置”)攒磨。由于json的流程組件都是標(biāo)準(zhǔn)的json格式泳桦,可以完全展現(xiàn)在web平臺,并有web平臺管理與生成娩缰。
Json配置文件采用多級模板體系灸撰,對于重復(fù)的交易流程,以及交易模塊,可以分不同的粒度來生成對應(yīng)的模板浮毯,以達(dá)到管理的方便與配置的重用完疫。
2.組件配置
2.1組件加載
啟動(dòng)時(shí)由mpos_daemon程序加載mpos/xml/daemon.xml,由daemon.xml里的配置來啟動(dòng)對應(yīng)的程序。
Daemon.xml實(shí)例:
<srvid>0004</srvid><srvnum>10</srvnum><paramdata>mpos_control.py</paramdata><paramindex><num>00</num></paramindex>
<srvid>0010</srvid><srvnum>5</srvnum><paramdata>mpos_service</paramdata><paramindex><num>01</num><01>mpos_dbfunc</01></paramindex>
<srvid>0011</srvid><srvnum>10</srvnum><paramdata>mpos_service</paramdata><paramindex><num>01</num><01>mpos_pyfunc</01></paramindex>
<srvid>0012</srvid><srvnum>5</srvnum><paramdata>mpos_service</paramdata><paramindex><num>01</num><01>mpos_pypos</01></paramindex>
<srvid>0013</srvid><srvnum>5</srvnum><paramdata>mpos_service</paramdata><paramindex><num>01</num><01>mpos_pyesb</01></paramindex>
<srvid>0014</srvid><srvnum>5</srvnum><paramdata>mpos_service</paramdata><paramindex><num>01</num><01>mpos_public</01></paramindex>
<srvid>0090</srvid><srvnum>01</srvnum><paramdata>mpos_nac</paramdata><paramindex><num>02</num><01>00</01><02>server_term.ini</02></paramindex>
<srvid>0091</srvid><srvnum>01</srvnum><paramdata>mpos_nac</paramdata><paramindex><num>02</num><01>01</01><02>server_term.ini</02></paramindex>
<srvid>0092</srvid><srvnum>01</srvnum><paramdata>mpos_nac</paramdata><paramindex><num>02</num><01>02</01><02>server_term.ini</02></paramindex>
<srvid>0093</srvid><srvnum>01</srvnum><paramdata>mpos_nac</paramdata><paramindex><num>02</num><01>03</01><02>server_term.ini</02></paramindex>
Srvid:服務(wù)的id號亲轨,不重復(fù)就可以
Srvnum:啟動(dòng)服務(wù)的個(gè)數(shù)趋惨,此例子中啟動(dòng)2個(gè)mpos_public服務(wù)
Paramdata:需要加載的python動(dòng)態(tài)框架鸟顺,此處為mpos_service框架
Num:標(biāo)示需要加載的參數(shù)個(gè)數(shù)
01:參數(shù)01的內(nèi)容為mpos_public惦蚊,就代表此流程需要加載mpos_public服務(wù)
整個(gè)流程為:python mpos_service mpos_public
Python動(dòng)態(tài)加載框架啟動(dòng)時(shí),從Mpos/xml/init_op.xml加載對應(yīng)的模塊讯嫂,從Mpos/xml/init_func.xml加載對應(yīng)的服務(wù)蹦锋。
Init_op.xml實(shí)例:
<svrname>mpos_dbfunc</svrname><libname>mpos_dbfunc</libname><lib>mpos_dbfunc</lib><type>py</type>
<svrname>mpos_pyfunc</svrname><libname>mpos_pyfunc</libname><lib>mpos_pyfunc</lib><type>py</type>
<svrname>mpos_pypos</svrname><libname>mpos_pypos</libname><lib>mpos_pypos</lib><type>py</type>
<svrname>mpos_pyesb</svrname><libname>mpos_pyesb</libname><lib>mpos_pyesb</lib><type>py</type>
<svrname>mpos_public</svrname><libname>mpos_public</libname><lib>libmpos_public.so</lib><type>c</type>
<svrname>mpos_socket</svrname><libname>mpos_socket</libname><lib>libmpos_socket.so</lib><type>c</type>
這里的實(shí)例為智付云組件服務(wù)需要加載的組件
svrname:服務(wù)的名稱
Libname:需要加載到框架里服務(wù)的名稱,此處為mpos_public服務(wù)
Lib:需要加載的服務(wù)的文件名欧芽,此處為libmpos_public.so
Type:加載庫的類型莉掂,此處為c庫
init_func.xml實(shí)例:
<libname>mpos_public</libname><func>get_term_to_local</func>
Libname:為需要加載的服務(wù)名,此處為mpos_public
Func:需要加載的函數(shù)名稱千扔。此處為get_term_to_local
3編程示例
下面以查余額為一個(gè)示例流程
3.1交易流程
交易中需要加載的的配置文件有:Mpos/xml/yl_trans.xml, Mpos/xml/userid/trans_next.xml,Mpos/json/
(1) Mpos/xml/yl_trans.xml為交易終端送上來的交易碼轉(zhuǎn)換為智付云系統(tǒng)內(nèi)部的交易碼:
<uniontrans>signin</uniontrans><localtrans>20000002</localtrans><tradename>簽到</tradename><readme>signin</readme>
Uniontrans:為交易終端上送的交易碼
Localtrans:為智付云系統(tǒng)內(nèi)部交易碼
(2) Mpos/xml/userid/trans_next.xml為內(nèi)部交易時(shí)的流程轉(zhuǎn)換:
此處沒有
<begintrans>100000005</begintrans><nextflag>00</nextflag><F2>00000</F2><nexttrans>10000005</nexttrans><tag></tag><readme>余額查詢</readme>
Begintrans:為當(dāng)前交易碼
Nextflag:為下步流程選擇項(xiàng)憎妙,如begintrans為10000005時(shí),nextflag為00時(shí)曲楚,nexttrans的值為10000005厘唾。
Nexttrans:為下批處理流程的交易碼
(3) Mpos/json/*.json為交易流程處理驅(qū)動(dòng)配置:
首先在bankuser.json中增加用戶類型
{
"bankuser": [
{
"usertype": "01",
"describe": "term",
"next_step": "term_menu.json"
}
]
}
Usertype:為用戶類型,此處為01
Describe:為描述字段龙誊,此處為term,標(biāo)示為支付終端
Next_step:為“01”的用戶菜單模板
(4) 下面為term_menu.json的菜單內(nèi)容:
{
"term_menu": [
{
"trans_id": "10000005",
"menu":
{
"next_step": "term_query.json",
"next_step_err": "term_err_info.json",
"readme":"query"
}
},
{
"trans_id": "20000002",
"menu": {
"next_step": "term_signin.json",
"next_step_err": "term_err_info.json",
"readme": "term_signin"
}
}
]
}
Trans_id:為本地交易碼
Menu:為交易處理流程
Next_step:為本交易流程的模板json
Next_step_err:為本次交易流程錯(cuò)誤流程處理模板json
Readme:為交易內(nèi)容說明
(5) 通用支付流程:
{
"term_signin": [
{
"service": "mpos_pypos",
"command": [
{ "op": "trans_cups" }
]
},
{
"service": "mpos_dbfunc",
"command": [
{ "op": "update_signin" }
]
},{
"next_step":"term_end.json"
}
]
}
Trans_id:為智付云系統(tǒng)內(nèi)部交易碼
next_step:為交易模板
trans_tag:動(dòng)態(tài)模板標(biāo)簽抚垃,根據(jù)此標(biāo)簽定義不同的模板功能
(6) 流程處理解釋:
當(dāng)從yl_trans.xml中獲得智付云本地交易碼后執(zhí)行term_signin處理流程,
{
"service": "mpos_pypos",
"command": [
{ "op": "trans_cups" }
]
}
通過調(diào)用mpos_pypos服務(wù)將簽到報(bào)文通過trans_cups函數(shù)發(fā)往收單系統(tǒng)趟大,并接受返回報(bào)文 鹤树。
service:為當(dāng)前流程需要的哪個(gè)服務(wù)模塊處理
Command:為處理流程
op:服務(wù)模塊的名稱
{ "op": "trans_cups" } :與收單系統(tǒng)通信
做完這個(gè)模板交易后,執(zhí)行交易:
{
"service": "mpos_dbfunc",
"command": [
{ "op": "update_signin" }
]
}
調(diào)用mpos_dbfunc服務(wù)逊朽,將簽到結(jié)果記錄到數(shù)據(jù)庫中罕伯。
"op": "update_signin":跟新終端的簽到信息
根本結(jié)束后,最后執(zhí)行模板 "next_step":"term_end.json":
{
"next_step":"term_end.json"
}
{
"term_end": [
{
"service": "mpos_pyfunc",
"command": [
{ "op": "set_resp" },
{ "op": "encrypt_message" },
{ "op": "packhttp_pad_trans"},
{ "op": "packhttp_pad_head"},
{ "op": "log_list" },
{ "op": "gen_FPOSR_buf"},
{ "op": "EnableGatewayIndex"}
]
},
{
"service": "mpos_nac",
"command": [
{ "op": "None" }
]
}
]
}
最后整個(gè)流程走完叽讳,重新打包發(fā)給交易終端
"op": "set_resp":設(shè)置交易結(jié)果
"op": "encrypt_message":加密返回報(bào)文
"op": "packhttp_pad_trans":打包交易報(bào)文
"op": "packhttp_pad_head":打包交易報(bào)文頭
"op": "log_list":記錄交易日志
"op": "gen_FPOSR_buf":生成返回報(bào)文
"op": "EnableGatewayIndex":發(fā)往網(wǎng)關(guān)
3.2代碼示例
智付云系統(tǒng)中python動(dòng)態(tài)加載框架所加載的服務(wù)必須是以int funcname(char resq,charresp)的方式捣炬,否則Python框架無法加載函數(shù)。
例如:
def set_resp(resq, resp):
#新增返回信息
err_code = public.xml_getvalue(resq.value, "F61")
tran_type = public.xml_getvalue(resq.value, "FTRANS")
if(len(err_code)==0 and (tran_type=="common" or tran_type=="esign" or tran_type=="activate" or tran_type=="query_detail" or tran_type=="signin")):
resp.value = public.xml_chgvalue(resp.value, "F61", "000000")
resp.value = public.xml_chgvalue(resp.value, "F60", "交易成功")
print err_code
if(err_code == "000000" or err_code == "00" ):
resp.value = public.xml_chgvalue(resp.value, "F61","000000")
resp.value = public.xml_chgvalue(resp.value, "F60","交易成功")
if (err_code!="00" and len(err_code)==2):
resq.value = public.xml_chgvalue(resq.value, "FERR", err_code)
get_err_name(resq,resp)
set_resp為函數(shù)名稱
resq:傳入的xml數(shù)據(jù)總線
resp:返回的xml數(shù)據(jù)總線
從交易報(bào)文中取得F61和FTRANS標(biāo)簽的值绽榛,通過判斷結(jié)果和交易類型來判斷是否交易成功
請注意湿酸,每次調(diào)用函數(shù)返回的resp,Python動(dòng)態(tài)加載框架都會(huì)加入xml數(shù)據(jù)總線中
在mpos_pyfunc中寫好此函數(shù)后灭美,需要加入init_func.xml中:
<libname>mpos_pyfunc</libname><func>set_resp</func>
3.3交易組包流程
交易組包的模塊在mpos_pyfunc服務(wù)中推溃,其功能完成了xml到j(luò)son的互轉(zhuǎn),http報(bào)文的打包與解包届腐,utf-8與GBK的互轉(zhuǎn)铁坎。mpos_pyfunc服務(wù)啟動(dòng)時(shí)蜂奸,從Mpos/cfg_json/http_mapping.json中加載。
"signin_unpack":
[
{"out_code":"term_sign", "sys_code":"FSIGN", "flag":"T","father":""},
{"out_code":"company", "sys_code":"FCOM", "flag":"T","father":""},
{"out_code":"user_id", "sys_code":"FUID", "flag":"T","father":""},
{"out_code":"app_ver", "sys_code":"FVER", "flag":"T","father":""},
{"out_code":"Longitude", "sys_code":"FLON", "flag":"T","father":""},
{"out_code":"Latitude", "sys_code":"FLAT", "flag":"T","father":""},
{"out_code":"key", "sys_code":"Frsakey", "flag":"T","father":""},
{"out_code":"key_index", "sys_code":"Fkey_index", "flag":"T","father":""},
{"out_code":"message", "sys_code":"FPOS", "flag":"T","father":""},
{"out_code":"message_type", "sys_code":"Ftype", "flag":"T","father":""}
],
"signin_pack":
[
{"out_code":"Code", "sys_code":"F61", "flag":"T","father":""},
{"out_code":"Msg", "sys_code":"F60", "flag":"T","father":""},
{"out_code":"message", "sys_code":"FPOS", "flag":"T","father":""}
]
Out_code:外部標(biāo)簽
Sys_code:本地標(biāo)簽
signin_pack為打包配置硬萍,signin_uppack為解包配置
4 unixodbc及freetds 配置
4.1 配置freetds并用tsql測試連接
vim /home/ehmuser/Mpos_local/etc/freetds.conf
添加如下內(nèi)容:
[Sybase]
host = IP 地址
port = 端口號
tds version = 5.0
client charset = UTF-8
具體的IP和端口號替換成個(gè)人所需即可
測試連接:
/usr/local/freetds/bin/tsql -S Sybase -U 用戶名 -P 密碼
如果出現(xiàn)如下內(nèi)容扩所,或者類似內(nèi)容,表示連接成功朴乖,此時(shí)可以執(zhí)行一些SQL語句試試
locale is "en_US.utf8"
locale charset is "UTF-8"
using default charset "UTF-8"
1>
4.2 配置unixodbc以及測試isql
創(chuàng)建驅(qū)動(dòng)的模板文件tds.txt 內(nèi)容如下:
[NHJSTDS]
Description = NHJSDB
Driver64 = /home/ehmuser/Mpos_local/lib/libtdsodbc.so
Driver = /home/ehmuser/Mpos_local/lib/libtdsodbc.so
FileUsage = 1
然后使用odbcinst安裝驅(qū)動(dòng):
odbcinst -i -d -f tds.txt
執(zhí)行完成之后祖屏,可以檢查一下/home/ehmuser/Mpos_local/etc/odbcinst.ini,如果可以看到TDS的內(nèi)容买羞,說明配置沒問題
4.3 創(chuàng)建數(shù)據(jù)源的模板文件
[ehmdb]
Driver = NHJSTDS
Descrption = Sybase Server
Trace = No
Server = 147.91.1.117
Database = master
Port = 4400
odbcinst -i -s -f unixodbc.txt
執(zhí)行完成以后袁勺,會(huì)在用戶的home目錄下生成.odbc.ini的文件,vim ~/.odbc.ini檢查一下文件內(nèi)容即可畜普。也可以用odbcinst -q -s檢查可用的數(shù)據(jù)源
用isql測試連接: isql -v ehmdb 用戶名 密碼
如果出現(xiàn)如下內(nèi)容期丰,說明連接成功了。
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL>