Commit 4df52336 authored by wutu's avatar wutu

测试qos限速模块,同时还需要学习更多关于tc限速的资料。

parent c614336a
/bishe-edge-center/target/ /bishe-edge-center/target/
*.iml *.iml
/bishe-utils/target/ /bishe-utils/target/
/bishe-edge-center/log/
...@@ -52,7 +52,7 @@ public class InDockerTests { ...@@ -52,7 +52,7 @@ public class InDockerTests {
dockerContainer1 = new DockerContainer(); dockerContainer1 = new DockerContainer();
dockerContainer1.setName("RouterTestIn1"); dockerContainer1.setName("RouterTestIn1");
dockerContainer1.setImage("joliu/networktest"); dockerContainer1.setImage("joliu/networktest");
dockerContainer1.setCommand("sh"); dockerContainer1.setCommand("iperf -s");
dockerContainer1 = dockerService.runDocker(dockerContainer1); dockerContainer1 = dockerService.runDocker(dockerContainer1);
dockerContainer2 = new DockerContainer(); dockerContainer2 = new DockerContainer();
...@@ -90,6 +90,41 @@ public class InDockerTests { ...@@ -90,6 +90,41 @@ public class InDockerTests {
System.out.println(result); System.out.println(result);
} }
@Test
public void testQos() {
String result = "";
// 测试网络连通性
result = dockerService.execInDocker(dockerContainer2.getId(), "ping 10.1.100.2 -c 2".split(" "));
System.out.println(result);
// 测试网络带宽
result = dockerService.execInDocker(dockerContainer2.getId(), "iperf -c 10.1.100.2 -i -t 2".split(" "));
System.out.println(result);
// 开启限速
System.out.println(dockerService.execInDocker(dockerContainer1.getId(), "tc qdisc add dev eth1 root handle 1: htb default 20"));
// 下行总速率5Mbit
System.out.println(dockerService.execInDocker(dockerContainer1.getId(), "tc class add dev eth1 parent 1:0 classid 1:1 htb rate 5Mbit"));
// 1 号通道的下行速度,最小3Mbit 最大5 Mbit (还可以添加优先级)
System.out.println(dockerService.execInDocker(dockerContainer1.getId(), "tc class add dev eth1 parent 1:1 classid 1:20 htb rate 4Mbit ceil 6Mbit"));
// 使用了一个公平侧率
System.out.println(dockerService.execInDocker(dockerContainer1.getId(), "tc qdisc add dev eth1 parent 1:20 handle 20: sfq perturb 10"));
// 设置了一个过滤器
System.out.println(dockerService.execInDocker(dockerContainer1.getId(), "tc filter add dev eth1 parent 1:20 protocol ip u32 match ip sport 5002 0xffff classid 1:20"));
// 再次进行测速
result = dockerService.execInDocker(dockerContainer2.getId(), "iperf -c 10.1.100.2 -i -t 2".split(" "));
System.out.println(result);
// 删除限速
String res = dockerService.execInDocker(dockerContainer1.getId(), "tc qdisc del dev eth1 root");
System.out.println(res);
// 再次进行测速
result = dockerService.execInDocker(dockerContainer2.getId(), "iperf -c 10.1.100.2 -i -t 2".split(" "));
System.out.println(result);
}
@Test @Test
public void testParseIptablesDetail() { public void testParseIptablesDetail() {
/** /**
......
...@@ -160,6 +160,87 @@ public class ChainEntity { ...@@ -160,6 +160,87 @@ public class ChainEntity {
return new Builder(); return new Builder();
} }
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getPkts() {
return pkts;
}
public void setPkts(long pkts) {
this.pkts = pkts;
}
public long getBytes() {
return bytes;
}
public void setBytes(long bytes) {
this.bytes = bytes;
}
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
public String getProt() {
return prot;
}
public void setProt(String prot) {
this.prot = prot;
}
public String getIn() {
return in;
}
public void setIn(String in) {
this.in = in;
}
public String getOut() {
return out;
}
public void setOut(String out) {
this.out = out;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public ChainType getType() {
return type;
}
public void setType(ChainType type) {
this.type = type;
}
@Override @Override
public String toString() { public String toString() {
return "ChainEntity{" + return "ChainEntity{" +
......
package top.ninwoo.utils.service.impl; package top.ninwoo.utils.service;
/** /**
* @Author joliu * @Author joliu
* @Description Docker内部的服务接口 * @Description Docker内部的服务接口 TODO:这个应该移动到集群一层
* @Date Create in 下午10:04 2019/10/28 * @Date Create in 下午10:04 2019/10/28
*/ */
public interface DockerInternalNetworkService { public interface DockerInternalNetworkService {
......
...@@ -86,5 +86,7 @@ public interface DockerService { ...@@ -86,5 +86,7 @@ public interface DockerService {
boolean hasRunningContainer(String containerId); boolean hasRunningContainer(String containerId);
String execInDocker(String containerId, String args);
String execInDocker(String containerId, String... args); String execInDocker(String containerId, String... args);
} }
package top.ninwoo.utils.service;
import top.ninwoo.utils.entity.ChainEntity;
import top.ninwoo.utils.entity.ChainType;
import java.util.List;
import java.util.Map;
/**
* @Author joliu
* @Description iptables的服务接口
* @Date Create in 上午10:07 2019/10/30
*/
public interface IptablesService {
Map<String, List<ChainEntity>> getIptablesByContainerId(String containerId);
List<ChainEntity> getIptablesByContainerId(String containerId, ChainType chainType);
void checkCache(String containerId);
void deleteIptable(String containerId, ChainEntity chainEntity);
void deleteIptablesFromList(String containerId, ChainEntity chainEntity);
void deleteIptableById(String containerId, ChainType type, int lineNumber);
}
...@@ -187,7 +187,12 @@ public class DockerServiceImpl implements DockerService, InitializingBean { ...@@ -187,7 +187,12 @@ public class DockerServiceImpl implements DockerService, InitializingBean {
} }
@Override @Override
public String execInDocker(String containerId, String... args) { public String execInDocker(String containerId, String args) {
return execInDocker(containerId, args.split(" "));
}
@Override
public String execInDocker(String containerId, String[] args) {
// 可以对命令进行一个判断 // 可以对命令进行一个判断
if(!runingContainers.containsKey(containerId)) { if(!runingContainers.containsKey(containerId)) {
if (allContainers.containsKey(containerId)) { if (allContainers.containsKey(containerId)) {
......
package top.ninwoo.utils.service.impl;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.ninwoo.utils.entity.ChainEntity;
import top.ninwoo.utils.entity.ChainType;
import top.ninwoo.utils.entity.TableType;
import top.ninwoo.utils.service.IptablesService;
import top.ninwoo.utils.util.IptablesUtils;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @Author joliu
* @Description 这个服务的实现类,并没有采用定时线程进行更新,
* 采用了一种类似缓存的实现方案,难点要保持每次操作和Dockeriptables操作的一致性
* TODO: 未测试
* @Date Create in 上午10:08 2019/10/30
*/
@Service
public class IptablesServiceImpl implements IptablesService {
// 以容器为单位维护着每个容器的iptables
private ConcurrentHashMap<String, Map<String, List<ChainEntity>>> allIptables
= new ConcurrentHashMap<>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
@Autowired
IptablesUtils iptablesUtils;
// 这个服务中不需要进行任务的定时更新,默认其他人无法访问docker容器中的配置
/**
* 根据容器Id查询全部的iptables信息
* 这里的容器id,要求必须存在,需要在调用前进行验证
* @param containerId
* @return
*/
@Override
public Map<String, List<ChainEntity>> getIptablesByContainerId(String containerId) {
checkCache(containerId);
try {
rwLock.readLock().lock();
return allIptables.get(containerId);
} finally {
rwLock.readLock().unlock();
}
}
/**
* 根据容器Id查询iptables信息
* @param containerId 容器id
* @param chainType chain的类型
* @return
*/
@Override
public List<ChainEntity> getIptablesByContainerId(String containerId, ChainType chainType) {
checkCache(containerId);
try {
rwLock.readLock().lock();
return allIptables.get(containerId).get(chainType.toString());
} finally {
rwLock.readLock().unlock();
}
}
public ChainEntity getIptablesByContainerId(String containerId, ChainType chainType, int lineNumber) {
checkCache(containerId);
List<ChainEntity> chains = getIptablesByContainerId(containerId, chainType);
if(chains.size() < lineNumber) {
return null;
}
return chains.get(lineNumber);
}
/**
* 校验缓存是否存在,如果不存在的话,则创建一次查询,并添加到缓存中
* @param containerId
*/
@Override
public void checkCache(String containerId) {
if(!allIptables.containsKey(containerId)) {
// 如果查询不到,证明该容器之前没有被操作过,调用底层命令,进行一次查询
synchronized (allIptables) {
if(!allIptables.containsKey(containerId)) {
Map<String, List<ChainEntity>> containerIptables = iptablesUtils.showIptablesDetail(containerId);
allIptables.put(containerId, containerIptables);
}
}
}
}
/**
* 使用chainentity删除对应的iptable
* @param containerId
* @param chainEntity
*/
@Override
public void deleteIptable(String containerId, ChainEntity chainEntity) {
checkCache(containerId);
try {
rwLock.writeLock().lock();
iptablesUtils.delIptable(containerId, chainEntity.getType(), chainEntity.getSource(), chainEntity.getDestination(), chainEntity.getTarget());
// 更新一下docker的iptables现状
deleteIptablesFromList(containerId, chainEntity);
} finally {
rwLock.writeLock().unlock();
}
}
/**
* 更新iptables容器,有安全问题,如果有其他人插入,这边删除是有安全问题的 TODO:
* @param containerId
* @param chainEntity
*/
@Override
public void deleteIptablesFromList(String containerId, ChainEntity chainEntity) {
List<ChainEntity> chainEntities = allIptables.get(containerId).get(chainEntity.getType().toString());
for (int i = chainEntity.getId(); i < chainEntities.size(); i++) {
chainEntities.get(i).setId(chainEntities.get(i).getId() - 1);
}
chainEntities.remove(chainEntity.getId() - 1);
}
/**
* 通过行号进行删除
* @param containerId
* @param type
* @param lineNumber
*/
@Override
public void deleteIptableById(String containerId, ChainType type, int lineNumber) {
checkCache(containerId);
// 删除第lineNumber个条目
try {
rwLock.writeLock().lock();
iptablesUtils.delIptable(containerId, TableType.filter, type, lineNumber);
allIptables.get(containerId).get(type.toString()).remove(lineNumber - 1);
} finally {
rwLock.writeLock().unlock();
}
}
/**
* 插入一个iptable, 插到前边
* @param containerId
* @param chainEntity
* @return
*/
public ChainEntity insertIptable(String containerId, ChainEntity chainEntity) {
checkCache(containerId);
try {
rwLock.writeLock().lock();
// 先写入Docker
iptablesUtils.addIptable(containerId, "insert", chainEntity.getType(),
chainEntity.getSource(), chainEntity.getDestination(), chainEntity.getTarget());
// 再写入all iptables
chainEntity.setId(1);
insertIntoIptables(containerId, chainEntity);
} finally {
rwLock.writeLock().unlock();
}
return chainEntity;
}
/**
* 插入到iptables
* @param containerId
* @param chainEntity
*/
private void insertIntoIptables(String containerId, ChainEntity chainEntity) {
List<ChainEntity> chainEntities = allIptables.get(containerId).get(chainEntity.getType());
chainEntities.forEach(c -> {c.setId(c.getId() + 1);});
chainEntities.add(0, chainEntity);
}
/**
* 在后边追加一个iptable,插到后边
* @param containerId
* @param chainEntity
* @return
*/
public ChainEntity appendIptable(String containerId, ChainEntity chainEntity) {
checkCache(containerId);
try {
rwLock.writeLock().lock();
// 先写入Docker
iptablesUtils.addIptable(containerId, "append", chainEntity.getType(),
chainEntity.getSource(), chainEntity.getDestination(), chainEntity.getTarget());
// 再添加alliptables最后一个
List<ChainEntity> chainEntities = allIptables.get(containerId).get(chainEntity.getType());
chainEntity.setId(chainEntities.size());
chainEntities.add(chainEntity);
} finally {
rwLock.writeLock().unlock();
}
return chainEntity;
}
}
package top.ninwoo.utils.util;
/**
* @Author joliu
* @Description 基于tc命令的限速接口
* @Date Create in 下午4:04 2019/10/30
*/
public interface TcUtils {
}
...@@ -230,4 +230,6 @@ public class IptablesUtilsImpl implements IptablesUtils { ...@@ -230,4 +230,6 @@ public class IptablesUtilsImpl implements IptablesUtils {
return cmd; return cmd;
//return dockerUtils.execInDocker(containerId, cmd.split(" ")); //return dockerUtils.execInDocker(containerId, cmd.split(" "));
} }
// 差一个转发的实现
} }
package top.ninwoo.utils.util.impl;
import org.springframework.beans.factory.annotation.Autowired;
import top.ninwoo.utils.util.DockerUtils;
import top.ninwoo.utils.util.TcUtils;
/**
* @Author joliu
* @Description
* @Date Create in 下午5:20 2019/10/30
*/
public class TcUtilsImpl implements TcUtils {
@Autowired
DockerUtils dockerUtils;
/**
* 这是个
* @param containerId
* @param maxRate
* @param minRate
* @return
*/
public boolean addQos(String containerId, String maxRate, String minRate) {
String resul = "";
// 开启限速
dockerUtils.execInDocker(containerId, "tc qdisc add dev eth1 root handle 1: htb default 20");
// 下行总速率5Mbit
dockerUtils.execInDocker(containerId, "tc class add dev eth1 parent 1:0 classid 1:1 htb rate " + maxRate);
// 1 号通道的下行速度,最小3Mbit 最大5 Mbit (还可以添加优先级)
dockerUtils.execInDocker(containerId, "tc class add dev eth1 parent 1:1 classid 1:20 htb rate " + minRate + " ceil " + maxRate);
// 使用了一个公平侧率
dockerUtils.execInDocker(containerId, "tc qdisc add dev eth1 parent 1:20 handle 20: sfq perturb 10");
// 设置了一个过滤器--TODO: 这个好像没有生效
dockerUtils.execInDocker(containerId, "tc filter add dev eth1 parent 1:20 protocol ip u32 match ip sport 5002 0xffff classid 1:20");
return true;
}
/**
* 解除限速
* @param containerId
* @return
*/
public boolean delQos(String containerId) {
String res = dockerUtils.execInDocker(containerId, "tc qdisc del dev eth1 root");
if(!"".equals(res)) {
return false;
}
return true;
}
}
package top.ninwoo.utils;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import top.ninwoo.utils.config.DockerConfig;
import top.ninwoo.utils.service.IptablesService;
/**
* @Author joliu
* @Description
* @Date Create in 下午3:15 2019/10/30
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DockerConfig.class)
public class IptablesServiceTests {
@Autowired
IptablesService iptablesService;
}
package top.ninwoo.utils;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import top.ninwoo.utils.config.DockerConfig;
import top.ninwoo.utils.util.DockerUtils;
/**
* @Author joliu
* @Description 这个测试迁移到集群服务中
* @Date Create in 下午4:06 2019/10/30
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DockerConfig.class)
public class TcUtilsTests {
@Autowired
DockerUtils dockerUtils;
@Before
public void init() {
// 创建两个容器
// 创建一个ovs网桥
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment