智付云系统架构及配置
1.系统架构说明
本文档描述的智付云系统架构脱胎于现有的apoll系统,并大幅优化了系统的并发性,可维护性能,组件之间的通讯全部使用异步
通讯,使得更有利于适应现在的互联网的运行环境和开发模式。
1.1系统架构图
1.2系统架构说明
智付云系统前置接入用ng来做LB处理,利用libev作为socket的异步通讯机制,使用flask web框架来作为微服务架构基础构建。整体架构分为3部分,第一部分为python动态加载框架用来加载C、python或者其他语言编写的模块,第二块是redis-server服务端组件,第三块为流程转发组件。动态组件之间的消息传递由redis服务实现。在一个交易流程中以xml消息总线维持之间的通讯。如需多次交互,由redis服务暂存xml消息总线的内容。
1.3Python动态加载框架
此框架由python语言编写,加载Ctype库,从而实现动态加载C或者其他语言库的能力。在动态库的编写上力求接口同化,都以int funcname(char * resq,char* resp)的方式命名,其中resq为接收的xml消息总线的内容,resp为返回的消息总线的内容及该服务处理后的结果。
Python的动态加载框架所需的配置文件存放在智付云mpos/json/和mpos/xml里,由*.json,init_op.xml,init_func.xml,user.xml,yl_trans.xml组成,及各用户文件下的trans_next.xml组成。
1.4Redis服务组件
Redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都 支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排 序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文 件,并且在此基础上实现了master-slave(主从)同步 Redis服务组件主要的作用为:为各个组件的通讯提供了mem层的服务,为多次交互的实现提供缓存xml数据总线的服务。
Redis服务较之于传统的消息队列,管道通讯来说有巨大的优势。首先redis服务是基于key_value存储系统,这个特性在高并发的时候能够有效的提供支持。其次在最新的redis中提供了cluster的能力,为智付云系统提供了组件集群的能力。最后,redis提供了比消息队列,管道丰富多的数据类型及操作,基本上一个redis服务就可以完全满足现有或者将来的组件通讯及缓存、高并发的所有需求。
1.5服务转发组件
本组件由Python语言编写,通过加载json文件夹里的配置文件来驱动交易流程。
Json文件夹里的配置流程,按功能分可以划分为3块(“协议配置”,“交易处理配置”,“错误处理配置”)。由于json的流程组件都是标准的json格式,可以完全展现在web平台,并有web平台管理与生成。
Json配置文件采用多级模板体系,对于重复的交易流程,以及交易模块,可以分不同的粒度来生成对应的模板,以达到管理的方便与配置的重用。
2.组件配置
2.1组件加载
启动时由mpos_daemon程序加载mpos/xml/daemon.xml,由daemon.xml里的配置来启动对应的程序。
Daemon.xml实例:
0004 10 mpos_control.py 00
0010 5 mpos_service 01 <01>mpos_dbfunc01>
0011 10 mpos_service 01 <01>mpos_pyfunc01>
0012 5 mpos_service 01 <01>mpos_pypos01>
0013 5 mpos_service 01 <01>mpos_pyesb01>
0014 5 mpos_service 01 <01>mpos_public01>
0090 01 mpos_nac 02 <01>0001><02>server_term.ini02>
0091 01 mpos_nac 02 <01>0101><02>server_term.ini02>
0092 01 mpos_nac 02 <01>0201><02>server_term.ini02>
0093 01 mpos_nac 02 <01>0301><02>server_term.ini02>
Srvid:服务的id号,不重复就可以
Srvnum:启动服务的个数,此例子中启动2个mpos_public服务
Paramdata:需要加载的python动态框架,此处为mpos_service框架
Num:标示需要加载的参数个数
01:参数01的内容为mpos_public,就代表此流程需要加载mpos_public服务
整个流程为:python mpos_service mpos_public
Python动态加载框架启动时,从Mpos/xml/init_op.xml加载对应的模块,从Mpos/xml/init_func.xml加载对应的服务。
Init_op.xml实例:
mpos_dbfunc mpos_dbfunc mpos_dbfunc py
mpos_pyfunc mpos_pyfunc mpos_pyfunc py
mpos_pypos mpos_pypos mpos_pypos py
mpos_pyesb mpos_pyesb mpos_pyesb py
mpos_public mpos_public libmpos_public.so c
mpos_socket mpos_socket libmpos_socket.so c
这里的实例为智付云组件服务需要加载的组件
svrname:服务的名称
Libname:需要加载到框架里服务的名称,此处为mpos_public服务
Lib:需要加载的服务的文件名,此处为libmpos_public.so
Type:加载库的类型,此处为c库
init_func.xml实例:
mpos_public get_term_to_local
Libname:为需要加载的服务名,此处为mpos_public
Func:需要加载的函数名称。此处为get_term_to_local
3编程示例
下面以查余额为一个示例流程
3.1交易流程
交易中需要加载的的配置文件有:Mpos/xml/yl_trans.xml, Mpos/xml/userid/trans_next.xml,Mpos/json/
(1) Mpos/xml/yl_trans.xml为交易终端送上来的交易码转换为智付云系统内部的交易码:
signin 20000002 签到 signin
Uniontrans:为交易终端上送的交易码
Localtrans:为智付云系统内部交易码
(2) Mpos/xml/userid/trans_next.xml为内部交易时的流程转换:
此处没有
100000005 00 00000 10000005 余额查询
Begintrans:为当前交易码
Nextflag:为下步流程选择项,如begintrans为10000005时,nextflag为00时,nexttrans的值为10000005。
Nexttrans:为下批处理流程的交易码
(3) Mpos/json/*.json为交易流程处理驱动配置:
首先在bankuser.json中增加用户类型
{
"bankuser": [
{
"usertype": "01",
"describe": "term",
"next_step": "term_menu.json"
}
]
}
Usertype:为用户类型,此处为01
Describe:为描述字段,此处为term,标示为支付终端
Next_step:为“01”的用户菜单模板
(4) 下面为term_menu.json的菜单内容:
{
"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:为本次交易流程错误流程处理模板json
Readme:为交易内容说明
(5) 通用支付流程:
{
"term_signin": [
{
"service": "mpos_pypos",
"command": [
{ "op": "trans_cups" }
]
},
{
"service": "mpos_dbfunc",
"command": [
{ "op": "update_signin" }
]
},{
"next_step":"term_end.json"
}
]
}
Trans_id:为智付云系统内部交易码
next_step:为交易模板
trans_tag:动态模板标签,根据此标签定义不同的模板功能
(6) 流程处理解释:
当从yl_trans.xml中获得智付云本地交易码后执行term_signin处理流程,
{
"service": "mpos_pypos",
"command": [
{ "op": "trans_cups" }
]
}
通过调用mpos_pypos服务将签到报文通过trans_cups函数发往收单系统,并接受返回报文 。
service:为当前流程需要的哪个服务模块处理
Command:为处理流程
op:服务模块的名称
{ "op": "trans_cups" } :与收单系统通信
做完这个模板交易后,执行交易:
{
"service": "mpos_dbfunc",
"command": [
{ "op": "update_signin" }
]
}
调用mpos_dbfunc服务,将签到结果记录到数据库中。
"op": "update_signin":跟新终端的签到信息
根本结束后,最后执行模板 "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" }
]
}
]
}
最后整个流程走完,重新打包发给交易终端
"op": "set_resp":设置交易结果
"op": "encrypt_message":加密返回报文
"op": "packhttp_pad_trans":打包交易报文
"op": "packhttp_pad_head":打包交易报文头
"op": "log_list":记录交易日志
"op": "gen_FPOSR_buf":生成返回报文
"op": "EnableGatewayIndex":发往网关
3.2代码示例
智付云系统中python动态加载框架所加载的服务必须是以int funcname(char resq,charresp)的方式,否则Python框架无法加载函数。
例如:
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为函数名称
resq:传入的xml数据总线
resp:返回的xml数据总线
从交易报文中取得F61和FTRANS标签的值,通过判断结果和交易类型来判断是否交易成功
请注意,每次调用函数返回的resp,Python动态加载框架都会加入xml数据总线中
在mpos_pyfunc中写好此函数后,需要加入init_func.xml中:
mpos_pyfunc set_resp
3.3交易组包流程
交易组包的模块在mpos_pyfunc服务中,其功能完成了xml到json的互转,http报文的打包与解包,utf-8与GBK的互转。mpos_pyfunc服务启动时,从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:外部标签
Sys_code:本地标签
signin_pack为打包配置,signin_uppack为解包配置
4 unixodbc及freetds 配置
4.1 配置freetds并用tsql测试连接
vim /home/ehmuser/Mpos_local/etc/freetds.conf
添加如下内容:
[Sybase]
host = IP 地址
port = 端口号
tds version = 5.0
client charset = UTF-8
具体的IP和端口号替换成个人所需即可
测试连接:
/usr/local/freetds/bin/tsql -S Sybase -U 用户名 -P 密码
如果出现如下内容,或者类似内容,表示连接成功,此时可以执行一些SQL语句试试
locale is "en_US.utf8"
locale charset is "UTF-8"
using default charset "UTF-8"
1>
4.2 配置unixodbc以及测试isql
创建驱动的模板文件tds.txt 内容如下:
[NHJSTDS]
Description = NHJSDB
Driver64 = /home/ehmuser/Mpos_local/lib/libtdsodbc.so
Driver = /home/ehmuser/Mpos_local/lib/libtdsodbc.so
FileUsage = 1
然后使用odbcinst安装驱动:
odbcinst -i -d -f tds.txt
执行完成之后,可以检查一下/home/ehmuser/Mpos_local/etc/odbcinst.ini,如果可以看到TDS的内容,说明配置没问题
4.3 创建数据源的模板文件
[ehmdb]
Driver = NHJSTDS
Descrption = Sybase Server
Trace = No
Server = 147.91.1.117
Database = master
Port = 4400
odbcinst -i -s -f unixodbc.txt
执行完成以后,会在用户的home目录下生成.odbc.ini的文件,vim ~/.odbc.ini检查一下文件内容即可。也可以用odbcinst -q -s检查可用的数据源
用isql测试连接: isql -v ehmdb 用户名 密码
如果出现如下内容,说明连接成功了。
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL>