/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* https://opensource.org/licenses/GPL-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
package beans.service;
import beans.dbaccess.OddSecondLevelService;
import beans.dbaccess.SecondLevelService;
import beans.dbaccess.SecondLevelServiceIPInfo;
;
import beans.request.IPPortPair;
import ngse.org.AccessZooKeeper;
import ngse.org.DBUtil;
import ngse.org.JsonRPCHandler;
import ngse.org.Tools;
import org.apache.log4j.Logger;
import org.apache.zookeeper.*;
import org.json.JSONObject;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.CountDownLatch;
/**
* Created by Administrator on 2016/3/2.
*/
public class LoadBalance {
static public String startLBSrv() {
/*
String[] cmd = {"/usr/local/zookeeper/bin/zkServer.sh", "start"};
StringBuffer sb = new StringBuffer();
int v = Tools.runCommand(cmd, sb, true);
*/
return "success";
}
static public String stopLBSrv() {
String[] cmd = {"/usr/local/zookeeper/bin/zkServer.sh", "stop"};
StringBuffer sb = new StringBuffer();
int v = Tools.runCommand(cmd, sb, true);
return "success";
}
//写一个服务的IP信息到LB
static public String writeOneServiceConfigInfo(AccessZooKeeper azk, String svcname,boolean isStandard,
ArrayList<IPPortPair> iplist) throws Exception
{
Logger logger = Logger.getLogger(LoadBalance.class);
/*
logger.info("generate IP->[port list] map...");
Map<String, String> map = new HashMap<String, String>();// ip -> ports
for (int i = 0; i < iplist.size(); i++) {
IPPortPair pair = iplist.get(i);
String ports = map.get(pair.getIp());
if (ports == null)
{
ports = "" + pair.getPort() ;
map.put(pair.getIp(), ports);
}
else
{
ports = ports + ", " + pair.getPort() ;
map.remove(pair.getIp());
map.put(pair.getIp(), ports);
}
}
StringBuffer data = new StringBuffer();
data.append("{ \"IPInfo\":["); //ipinfo是一个数组
int eleIndex = 0;
for (Map.Entry<String, String> entry : map.entrySet()) {
if (eleIndex > 0)
{
data.append(","); //与前面的数组元素分割起来
}
//数组的每一个元素,是一个对象,包括w t ip ports四个字段
data.append("{");
data.append("\"w\":100, \"t\":\"all\", \"IP\":\"");
data.append(entry.getKey());
//ports也是一个数组
data.append("\",\"ports\":[");
data.append(entry.getValue());
data.append("]");
data.append("}");//一个对象,或者说一个数组元素结束
eleIndex++;
}
data.append("]}");
*/
StringBuffer data = new StringBuffer();
if (isStandard)
{
data.append("{ \"Policy\":\"standard\"");
}
else
{
data.append("{ \"Policy\":\"odd\"");
}
data.append(", \"IPInfo\":["); //ipinfo是一个数组
int eleIndex = 0;
for (int i = 0; i < iplist.size();++i)
{
if (eleIndex > 0)
{
data.append(","); //与前面的数组元素分割起来
}
//数组的每一个元素,是一个对象,包括w t ip ports四个字段
data.append("{");
IPPortPair oneEle = iplist.get(i);
String comm_proto = oneEle.getComm_proto();
if (comm_proto.equals("tcp and udp"))
{
comm_proto = "all";
}
data.append("\"w\":100, \"t\":\""+comm_proto+"\", \"IP\":\"");
data.append(oneEle.getIp());
//ports也是一个数组
data.append("\",\"ports\":[");
data.append(oneEle.getPort());
data.append("]");
data.append("}");//一个对象,或者说一个数组元素结束
eleIndex++;
}
data.append("]}");
String path = "/nameservice/" + svcname;
logger.info("write LB server: path="+path);
logger.info("data="+data.toString());
String result = azk.write(path, data.toString().getBytes());
if (result == null || !result.equals("success"))
{
logger.error("LB write failed:"+result);
return result;
}
return "success";
}
//读一个服务的IP信息到LB
static public byte[] readOneServiceConfigInfo(AccessZooKeeper azk, String svcname) throws Exception
{
String path = "/nameservice/"+svcname;
byte[] ret = azk.read(path);
return ret;
}
//读取一个服务指定IP的负载信息
static public int readOneServiceLoadInfo(AccessZooKeeper azk, String svcname, String ip) throws Exception
{
String path = "/loadreport/"+ip;
Logger logger = Logger.getLogger(LoadBalance.class);
byte[] data = azk.read(path);
if (data == null||data.length < 10)//不存在
{
logger.error("load information NOT exist:"+path);
return -1;
}
String jsonStr = new String(data, Charset.forName("UTF-8"));
logger.info("read ip load info from LB:path="+path);
logger.info("data="+jsonStr);
JSONObject obj = new JSONObject(jsonStr);
int cpu = obj.getInt("cpu");
//cpu = cpu / 100;
return cpu;
}
//从数据库中获取所有的服务
static public ArrayList<SecondLevelService> getAllService( DBUtil util)
{
ArrayList<SecondLevelService> serviceList ;
String sql = "select first_level_service_name, second_level_service_name,type from t_second_level_service";
List<Object> params = new ArrayList<Object>();
try {
serviceList = util.findMoreRefResult(sql, params, SecondLevelService.class);
return serviceList;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
//从数据库中获取一个服务的所有IP信息
static public ArrayList<IPPortPair> getIPPortInfoByServiceName(String flsn, String slsn, DBUtil util)
{
ArrayList<IPPortPair> ipList ;
List<Object> params = new ArrayList<Object>();
String sql = "";
sql = "select ip,port,status,comm_proto from t_second_level_service_ipinfo where " +
"second_level_service_name=? and first_level_service_name=? and status='enabled'";
params.add(slsn);
params.add(flsn);
try {
ipList = util.findMoreRefResult(sql, params, IPPortPair.class);
return ipList;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//建立从IP到服务列表的映射
static private void geneIP2Svcs(String svc, ArrayList<IPPortPair> ips,
HashMap<String, HashSet<String>> ip2Svcs )
{
for (int j = 0; j < ips.size(); j++) {
String ip = ips.get(j).getIp();
if (ip2Svcs.get(ip) == null)
{
HashSet<String> value = new HashSet<String>();
value.add(svc);
ip2Svcs.put(ip,value );
}
else
{
HashSet<String> value = ip2Svcs.get(ip);
value.add(svc);
}
}
return;
}
//把所有服务的配置信息写入LB
static public String writeServiceConfigInfo(AccessZooKeeper azk) throws Exception
{
DBUtil util = new DBUtil();
Logger logger = Logger.getLogger(LoadBalance.class);
if (util.getConnection() == null)
{
return "db connect failed";
}
logger.info("write IP information of ALL services into LB...");
try {
//删除掉整个配置信息
String path = "/nameservice";
azk.deleteRecursive(path);
logger.info("delete whole tree:"+path);
//获得所有服务
ArrayList<SecondLevelService> services = getAllService(util);
if (services == null) {
return "get standard service list from db failed";
}
logger.info("getAllService() OK, service number:"+services.size());
//对每个服务获取下属的IP
for (int i = 0; i < services.size(); i++) {
SecondLevelService svc = services.get(i);
ArrayList<IPPortPair> ips = getIPPortInfoByServiceName(svc.getFirst_level_service_name(),
svc.getSecond_level_service_name(), util);
if (ips == null) {
return "get ip list from db failed";
}
logger.info("get ip for "+svc.getSecond_level_service_name()+" OK, ip number"+ips.size());
//写到 LB系统里
String result = writeOneServiceConfigInfo(azk,
svc.getFirst_level_service_name() + "/" + svc.getSecond_level_service_name(),
svc.getType().equals("standard"),
ips);
if (result == null || !result.equals("success"))
{
logger.error("write service IP information into LB failed!"+result);
return result;
}
logger.info("write to LB ok");
}
return "success";
}
finally {
util.releaseConn();
}
}
//以IP为key的配置信息写入LB,whiteNameList为需要写的白名单IP列表,可以为null
static public String writeIPConfigInfo(AccessZooKeeper azk, ArrayList<String> whiteNameList) throws Exception
{
Logger logger = Logger.getLogger(LoadBalance.class);
DBUtil util = new DBUtil();
if (util.getConnection() == null)
{
return "db connect failed";
}
logger.info("write IP key info into LB ...");
HashMap<String, HashSet<String>> ip2Svcs = new HashMap<String, HashSet<String>>();
try {
//获得所有服务
ArrayList<SecondLevelService> services = getAllService(util);
if (services == null) {
logger.error("get all service failed");
return "get service list from db failed";
}
//对每个服务获取下属的IP
for (int i = 0; i < services.size(); i++) {
SecondLevelService svc = services.get(i);
ArrayList<IPPortPair> ips = getIPPortInfoByServiceName(svc.getFirst_level_service_name(),
svc.getSecond_level_service_name(), util);
if (ips == null) {
logger.error("get ip list for "+svc.getSecond_level_service_name()+" failed.");
return "get ip list from db failed";
}
logger.info("get ip list for "+svc.getSecond_level_service_name()+" successfully.ip number"+ips.size());
//生成IP为key、servicename列表为value的反向映射关系
geneIP2Svcs(svc.getFirst_level_service_name() + "." + svc.getSecond_level_service_name(),
ips, ip2Svcs);
}
logger.info("gene IP->service map successfully, map size:"+ip2Svcs.size());
if (whiteNameList == null)
{
//删除掉整个ip配置信息
String path = "/nodeservices";
azk.deleteRecursive(path);
logger.info("delete whole tree:"+path);
}
else
{
//删除掉白名单中的ip配置信息
for (int i = 0; i < whiteNameList.size() ; i++) {
String path = "/nodeservices/"+whiteNameList.get(i);
azk.deleteRecursive(path);
logger.info("delete node:"+path);
}
}
//往LB写入ip为key的数据
for (Map.Entry<String, HashSet<String>> entry : ip2Svcs.entrySet()) {
if (whiteNameList != null)//如果只更新列表中的指定的IP列表
{
if (whiteNameList.indexOf(entry.getKey()) < 0)
{
continue;
}
}
String path = "/nodeservices/"+entry.getKey();
String data = "{\"services\":[";
Iterator<String> it = entry.getValue().iterator();
int eleIndex =0;
while( it.hasNext())
{
if (eleIndex > 0)
{
data += ","; //与前一个元素的分割
}
data += "\""+ it.next() +"\"";
eleIndex++;
}
data += "]}";
logger.info("write LB, path="+path);
logger.info("data="+data);
String result = azk.write(path, data.getBytes());
if (result == null || !result.equals("success"))
{
logger.error("write LB failed:"+result);
return result;
}
}
return "success";
}
finally {
util.releaseConn();
}
}
}